Con un asset BLIND e nessun ALERT, severity restava None e il titolo del
runner cadeva sul default piu' forte ("PRIMO PASSO: prelievo di prova") per
un episodio che e' "non vedo", non "stress misurato". run_once ora assegna
severity="blind" quando c'e' un BLIND senza ALERT (ALERT resta piu' forte, P9);
_titolo distingue il caso con "venue_watch CIECO — referenze non leggibili,
nessun giudizio sul venue". La ripetizione oraria di BLIND non e' toccata.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
src/live/giri.registra_giro: una riga jsonl {ts ms, campi} dopo una misura completata,
mai un'eccezione. edge_watch, fee_watch, scale_watch, vrp_f_watch, venue_news (cron_daily)
e venue_watch (cron_book, orario) scrivono data/<dir>/runs.jsonl; niente riga senza misura.
monitor_health: sei MonitorSpec (30h i giornalieri, 3h venue_watch), open_labeled=False.
Stessa riparazione di cc01 (#10, #12), generalizzata. Primo giro notturno: NUOVO, non allerta.
Test: incrocio P1 percorso/RUNS, misura -> una riga, non-misura -> nessuna. Suite: 1098 passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MISURATO oggi durante la revisione: `trades_db.py --help` non stampava l'uso, cadeva in sync()
e riscriveva meta.ultimo_sync. Nessuno dei 18 script di scripts/live/ usava argparse: un flag
sbagliato era il ramo else. Su journal.py avrebbe scritto pagina e riga di DB, su analista.py
avrebbe speso una chiamata al modello e mandato un Telegram.
- src/live/cli.valida: prima istruzione di ogni __main__, prima di connect()/sync/rete.
--help -> 0 con l'uso; flag ignoto, valore mancante o posizionale -> 2 con l'elenco dei
previsti (P4). NIENTE argparse: cambierebbe messaggi, codici d'uscita e --help di script
che il cron gia' chiama.
- 18 script cablati (i 3 che scrivono + 14 + cc01), flag invariati.
- tests/test_cli_flag.py (30): elenco DERIVATO dalla cartella (P1), valida come prima
istruzione, uso che documenta i flag, e i flag che il CRON usa davvero restano accettati
(P15/P16); end-to-end su --help e flag ignoto con trades.db non toccato (M15).
Verificato a mano: monitor_health --quiet, trades_db --sync --quiet, book_execute dry-run.
Debito §5.15, primo passo: balance_watch (orario) registra `usde_usdc` a ogni campione — None
con la ragione se illeggibile, mai 1,0. Il cablaggio nel bound quando la serie ha storia.
Pulizia dalla revisione: tests/helpers.carica_script al posto della 15a copia del loader
importlib (5 file del libro live); il fill di prova via upsert_fills invece di un INSERT che
lasciava verified NULL; asserzioni non ancorate al padding; movimenti_capitale accetta le
righe gia' lette (una SELECT invece di due ai due lati di una scrittura del cron).
Test 910 verdi (+52). Diario 2026-09-02c.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XDJsH3iDSaBns3ccpPBwiu
Debito §5.2 chiuso su decisione dell'operatore. `run_once` salvava lo stato coi
marcatori `alerted` gia' a True e l'invio lo faceva il chiamante DOPO: col 6,9%
di invii falliti misurato (2 su 29), un 🚨 perso restava perso per l'EPISODIO
INTERO — l'ora dopo lo stato diceva "gia' detto" e usciva WATCH/MUTO. Gli
episodi storici durano 200-2.324 ore, quindi il buco non era teorico.
- `run_once(state_path, sender=None)`: il sender e' INIETTATO, non importato —
e' cio' che tiene la funzione testabile senza rete d'uscita, che era la
ragione del disegno precedente. Senza sender il comportamento resta quello di
prima e il report lo DICE (`invio`), invece di lasciar credere che qualcosa
sia partito.
- Su invio fallito si disfano SOLO i marcatori "gia' detto", non le misure:
· asset in ALERT -> alerted=False, l'ora dopo ri-allerta;
· lock MAINT/ALERT -> alerted_soft/hard=False ma le ORE restano a correre,
cosi' una manutenzione che sfora la grazia sale ad ALERT anche col trasporto
giu' (disfare anche le ore congelerebbe l'escalation proprio mentre non si
riesce a parlare);
· lock RIENTRATO -> si ripristina l'intero LockState, perche' il rientro si
annuncia una volta sola e senza le ore non ci sarebbe piu' niente da dire.
- `notify(..., tentativi=)`: il retry esisteva in `send` e non arrivava qui.
venue_watch ora manda con 3 tentativi.
- L'esito dell'invio finisce nel log del cron invece di sparire.
5 test nuovi. Il primo e' quello che conta — dopo un invio fallito, l'ora dopo
ri-allerta — col suo controllo positivo (un invio riuscito consuma l'allarme
UNA volta sola), senza il quale "ri-allerta sempre" passerebbe.
Suite: 782 passati, 2 falliti (i due del gate GTAA, non toccati qui).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Il 18/08 sono usciti quattro 🚨 identici con 'PRIMO PASSO: prelievo di prova'
per una manutenzione Deribit annunciata, e tutti e quattro DOPO che il book
aveva gia' ripreso a eseguire. Il book si era comportato bene (due giri di
astensione, 'non eseguo a cieco'); il difetto era negli allarmi.
1. Il blocco piattaforma era un if secco senza memoria, accanto a un rilevatore
tarato con cura che allerta una volta per streak. Ora passa da lock_step(),
pura e testata: manutenzione entro tolleranza = un solo avviso morbido, che
sfora = un solo 🚨 ('ha SFORATO'), blocco inspiegato = 🚨 subito, rientro
annunciato una volta. public/status illeggibile NON e' un rientro.
2. Il messaggio diceva 'locked=true' cablato mentre il parser accetta anche
'partial': dichiarava un valore che non aveva letto, e il runbook manda a
controllare proprio quel campo. Ora stampa e salva il valore grezzo.
3. Deribit ha cambiato tick e size dei perpetual lineari USDC il 18/08 e la
tabella _CONTRACT, cablata a mano, non se n'era accorta. Nessun ordine
rifiutato solo perche' i cambi erano riduzioni: e' andata bene per la
direzione, non perche' ce ne fossimo accorti. Tabella aggiornata ai valori
verificati e aggiunto check_specs(), che gira nel venue_watch orario (fuori
dal percorso ordini) e dichiara la direzione: 'granularita'' = conforme,
'rifiuto' = il venue rifiuta. La tabella dichiarata resta l'autorita' per
costruire un ordine, il venue e' il controllore.
4. Aggiunta Kraken come terza referenza: Coinbase ha comprato Deribit, e una
referenza che e' la casa madre non misura piu' se Deribit scolla dal mondo.
THRESHOLD_BPS e PERSIST_HOURS invariati, ma il consenso ora e' su tre serie
e quel numero non e' ri-misurato: dichiarato nel codice e nel diario. La
direzione dell'errore e' 'allerta di meno', non 'grida al lupo'.
Test 23 -> 35 su venue_watch, suite intera 618 verdi. Book, pesi e config
invariati; dry-run del book verificato. Diario: docs/diary/2026-08-19-*.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Risposta a "trova un sistema di protezione da fallimento exchange" SOTTO IL VINCOLO
della decisione appena presa (100% Deribit fino a $20k). Se non si puo' ridurre
l'ESPOSIZIONE, l'unica leva e' il TEMPO: il modello di rischio del mattino assumeva il
salto a zero istantaneo, ma i fallimenti reali non lo sono (Mt.Gox mesi, FTX ~72h, e
misurato qui: Bitfinex 2018-19 dislocato per 2.324 ore consecutive).
SEGNALE: un venue che gata i prelievi rompe l'ARBITRAGGIO -> il prezzo si stacca dal
consenso e ci resta. E' |scarto|, non il segno (Mt.Gox a premio, un venue in fuga a
sconto: stessa cosa). Consenso = venue USD indipendenti (Coinbase, Bitstamp), mai USDT.
Deribit sta a 3 bps dal consenso in mediana su 8 anni (65.043 ore BTC + 64.541 ETH).
TARATURA CONGELATA: 100 bps persistenti 4h a segno costante. Criterio DICHIARATO PRIMA,
perche' i due ovvi sbagliano in versi opposti (provati entrambi): "minimi bps" -> 25/24h
consuma 24 delle ~72h di FTX; "minime ore" -> 500/2h MANCA FTX (margine 0.6x). Regola:
zero falsi allarmi in 8 anni + margine >=3x sul caso storico piu' debole -> soglia
<=100bps -> poi minima latenza. Margine 3x FTX / 5x Quadriga / 10-20x Mt.Gox, zero falsi
allarmi con crash COVID, maggio 2021, LUNA e novembre 2022 inclusi.
CONTROLLO POSITIVO SUPERATO (un rilevatore tarato per non segnalare e' indistinguibile da
uno rotto): puntato su Bitfinex 2018-19 scatta 22 volte, episodio piu' lungo 2.324h a
+447bps. 22 dove il problema c'era, 0 su Deribit. E la durata risponde alla domanda vera:
un venue gated resta dislocato per settimane, quindi 4h di latenza sono trascurabili.
ECONOMIA: falso allarme = 0.248% atteso (flat 3g misurato sul book reale a ogni data
d'inizio); vero positivo = 100% salvato. Break-even p > (falsi/anno) x 0.00248: a 1 ogni
8 anni serve p > 0.031%. Il valore sta nella SPECIFICITA', non nella sensibilita'.
CABLATO: src/live/venue_watch.py (nucleo puro) + scripts/live/venue_watch.py, in
cron_book.sh PRIMA di book_execute (se Deribit e' in stress l'allarme deve partire anche
quando l'esecuzione fallisce per la stessa ragione). Tre stati OK/ALERT/BLIND — "non
vedo" non e' "va bene". ALLERTA, NON BLOCCA: l'azione e' prelevare (manuale; una chiave
con permesso di prelievo sarebbe essa stessa un rischio) e bloccare non protegge un saldo
che e' a rischio anche stando flat. Runbook pre-deciso nel docstring.
NON COPRE, e non e' un argomento per riaprire il 26/07: un fallimento SENZA finestra
(furto chiavi, sequestro, exit-scam) non lo prende nessun tripwire.
ERRORI CATTURATI IN SESSIONE:
- break-even calcolato sul p5 invece che sulla media (8.3x piu' severo, conclusione
ribaltata);
- ipotesi meccanica sbagliata: credevo che i crash dislocassero a segno ALTERNATO. Falso,
sono a segno costante anche loro (perp sotto spot per ore in cascata). A separare sono
ampiezza e durata, non il segno;
- la prima corsa tronco' il campione da 8 anni a 29 GIORNI per un inner-join con Kraken
(che serve solo ~700 candele) e la copertura era gia' stampata a video: una diagnostica
stampata NON e' un controllo. Ora c'e' una guardia che ferma lo script. 2a occorrenza
in un giorno dopo GTAA01;
- il controllo positivo era finito dentro il ramo `else` -> non girava mai, cioe'
esattamente il difetto che doveva prevenire.
Book, pesi, config INVARIATI. 359 test verdi (+23).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>