book_report costruiva l'ordine con min_usd=5.0 fisso invece di leggere
min_order_usd da config/live.json, come fa gia' scripts/live/book_execute.py
(default 5.0 se assente). Oggi config = 5, nessun cambio di comportamento.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
La leva lorda massima del libro era ridichiarata con tre formule diverse:
usde.frazione_cuscino (N_ASSET fisso, senza scala), la regola `leva` del
giornale (senza scala) e journal.movimenti_capitale (con scala). A scala
1,25 il cuscino USDC risultava 0,30 dell'equity invece di 0,375.
Nuova src/live/book.leva_tetto(cfg) = len(ASSETS) x min(WEIGHT, frac) x
scala, al piu' LEVA_LORDA_MAX; su ScalaNonAutorizzata non solleva, ritorna
il tetto di codice (cuscino_watch non deve morire sulla config sbagliata).
usde.frazione_cuscino e la regola `leva` del giornale ora la derivano;
movimenti_capitale idem, nel suo try/except esistente.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Non e' verificato sotto quale valuta Deribit elenchi lo spot USDE_USDC: la
quotazione (USDC) o la base (USDE). cancella_residui interroga entrambe e
unisce per order_id prima di applicare il filtro instrument+label, cosi' un
residuo elencato sotto USDE non si accumula in eterno per non essere mai
letto. Se una delle due letture solleva, solleva come prima (nessun try
aggiunto attorno al giro).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
hasattr perche' U1 e U2 si uniscono dopo questo rilascio: DeribitTrader oggi non ha
set_open_cap, e l'hasattr evita che l'unione dei due rami rompa in un senso o nell'altro.
Si toglie l'hasattr al merge.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
open_orders solleva RuntimeError se 'all' o 'trigger_all' falliscono, invece di ritornare []
(un bracket disaster-SL perso su 'trigger_all' e' lo stesso difetto di una posizione persa su
'all'). ensure_disaster_sl avvolge la lettura di posizione+open_orders in try/except: su
eccezione ritorna {"state": "unknown", "notes": ...} senza cancellare ne' piazzare, distinto
da "naked" (protezione tolta e non rimessa). shadow.shadow_report chiama open_orders gia'
dentro try/except (non toccato).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Prima, con equity reale non leggibile il giro dimensionava comunque un ordine sul paper_cap
($2.000 nominali) e lo mandava; con SKH ignoto il target restava quello (fail-safe solo nel
segno). Ora: se non si sa quanto vale il conto o qual e' il segnale, nessun rebalance_signed —
ma il disaster-SL si controlla LO STESSO per ogni asset (dipende da posizione/mark, non da
equity/segnale). Giro degradato -> exit 2, solo se armato (non in anteprima dry-run).
Fill persi: rebalance_signed puo' eseguire un fill (es. il close di un flip) e poi sollevare nel
passo successivo (l'open dall'altra parte) — quel fill spariva perche' la lettura di `newpos`,
PRIMA del giro che lo registrava, andava in eccezione a sua volta. Estratta la registrazione in
_registra_fill(...), chiamata SUBITO dopo ogni fill (anche quelli di RebalanceParziale, nuova
eccezione di execution.py con .fills/.causa) e PRIMA di leggere la posizione; la lettura ora e'
in un try separato, non fatale (pos_after=None + "reconcile: pos illeggibile" se fallisce).
Aggiornati due test che assumevano il comportamento vecchio (eq_fallback "prosegue" sul paper
capital) e il guard sulla sorgente di test_tradesdb.py (bar_ts ora e' un parametro di
_registra_fill, non piu' `r['last_data']` inline).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DeribitTrader.set_open_cap(instrument, usd_cap, mark) deriva amount_max = 1,10*usd_cap/mark
dal cap di config del libro; _submit lo usa quando presente, MAX_AMOUNT resta il DEFAULT per
chi non lo chiama (il micro-test). Firma per chi la richiama prima di rebalance_signed (U2):
trader.set_open_cap(inst, r["cap_per_asset"] * r["scala"], mark).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
#29 B2: lo stato si salvava PRIMA dell'invio e il ritorno di notify() non si
leggeva — un invio fallito restava "gia' detto" per l'episodio intero. Schema
di cuscino_watch.py: nuove_condizioni()/rec["allertati"] contano una
condizione come "gia' detta" solo se l'invio precedente e' RIUSCITO; un
record vecchio senza `allertati` vale come "tutto allertato" (nessun rispam
retroattivo). Lo stato si scrive una volta sola, a fine giro.
#35 B3/B4: la quota non e' piu' una decisione dell'operatore rinviata a
lunedi' — dal 10/09 (issue #7) e' DERIVATA dal cuscino USDC
(usde._nota_cuscino) — quindi tolti DECISIONE_QUOTA_DAL, quota_da_decidere()
e la notify "la decisione di QUOTA e' dovuta". Il tetto di allerta IDONEO
legge c["quota_max_frac"] invece del 50% cablato. La riga "margine" non dice
piu' "conto SEGREGATO" (il modello e' Cross X:SM dal 31/08): stampa il totale
USDC + USDE scontato del cross, coi numeri che la funzione ha gia'.
Le due modifiche toccano lo stesso blocco (allarmi + STATE write + stampa) e
non si possono separare per hunk senza rischio: un solo commit per il file.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
save_state girava sempre dopo l'eventuale notify, anche quando l'invio
falliva: il giro dopo diff_vs confrontava lo stato nuovo con se stesso e il
cambiamento (o il livello AZIONE) spariva senza essere mai stato detto. Ora
lo stato si salva solo se non serviva un invio, o se l'invio e' riuscito.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Il gateway cerbero-mcp non accetta time_in_force (PlaceOrderReq non ha il
campo): un limit riempito solo in parte restava APERTO per sempre e si
accumulava a ogni giro. cancella_residui() pulisce lo spot USDE_USDC dai
residui con label "usde-quota-*" prima del ciclo; nel ciclo, un ordine con
filled < amt viene cancellato subito dopo, e una cancellazione fallita ferma
il ciclo (mai un secondo ordine con un residuo vivo).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
scrivi() chiamava J.salva() prima del controllo su --secco: un giro "a secco" scriveva
comunque le sezioni misurate nel giornale. Ora salva() (e scrivi_file, che era gia' dopo
il return) girano solo quando non e' secco; rendi_markdown() tollera l'assenza della riga
in DB (nota/analisi vuote, verificato).
Test nuovo in tests/test_analista.py (non c'e' un test_analista_u4.py: l'analisi indicava
i due file journal/tradesdb, questo fix e' su analista.py e segue la convenzione un
file-di-test-per-modulo del resto della suite).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Il gateway manda size/size_currency in assoluto e il segno a parte in direction:
letta com'era, uno short risultava un long e close()/ensure_disaster_sl decidevano
lato ordine e prezzo dello stop dal segno sbagliato.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
C2: fifo_roundtrips ora apre un lotto SHORT quando un sell non trova lotti long da chiudere
(prima il resto spariva in silenzio), chiude prima il lato opposto e apre l'eccedenza nel
segno del fill — anche a meta' dello stesso fill (inversione long<->short). stato_aperto e
report() portano la direzione del lotto residuo.
C10: un fill "NON VERIFICATO" a qty 0 (place_order error) non entra piu' nel FIFO ne' in
stato_aperto (WHERE qty > 0 in rebuild_roundtrips/stato_aperto); resta nel DB marcato
(verified=0), non e' scomparso.
test_fifo_non_mescola_gli_asset aggiornato: una vendita ETH senza lotti long ora apre uno
short invece di sparire (era il comportamento che C2 corregge). Test nuovi in
tests/test_tradesdb_u4.py.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
#27: due movimenti dichiarati nello stesso intervallo si sommavano al posto di sovrascriversi
(l'aggancio "dichiarato+rilevato" ora cerca solo fonte=="rilevato").
#35 C9: salute() non conta piu' il giro dell'ora corrente prima che scatti (minuto :47 +
margine, MINUTO_GIRO costante di modulo).
#35 C15: la finestra "ultimi 7 giorni" della concentrazione ora copre 7 giorni di calendario,
non 8 (baseline = ultima lettura al o prima di giorno-7 fine giornata).
#35 C7: il drawdown si calcola sulla serie equity al netto dei movimenti di capitale certi,
cosi' un prelievo non si legge come perdita di trading e un versamento non alza il picco.
Test nuovi in tests/test_journal_u4.py; tests/test_journal.py aggiornato (l'orologio del
test su salute() era reale e non deterministico, ora e' fissato).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Un'eccezione sulla lettura del conto USDE valeva 0 USDE: se il conto ne aveva davvero, l'equity
totale risultava sottostimata senza che nulla lo dicesse. Ora _collaterale_usde ritorna None +
la nota dell'eccezione, e _equity propaga l'ignoto (real_eq None -> eq_fallback, non un numero
falso). shadow_report.online guardava solo il mark di BTC: con ETH in fallback il giro si
considerava comunque online. Ora richiede TUTTI i mark da mainnet.
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>
ISTRUZIONI diceva «capitale ~$635» (equity reale ~$4.5k dal 04/09): valore ridichiarato,
forma di P1, e fuori pagina per la regola 1 delle istruzioni stesse. Ora il capitale e'
l'equity in pagina. Aggiunto che fifo_roundtrips chiude un round-trip per lotto: piu'
round-trip che fill nello stesso giorno e' atteso (l'analista lo segnalava come anomalia).
Test: nessun importo in ISTRUZIONI; FIFO e lotto nominati.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- CLAUDE.md §1 OMBRA: cron :44 sulla stessa crontab, legge il conto con la STESSA chiave live di
cerbero-mcp (verificato per hash), scrive solo nel suo albero (3 giri misurati, nessun file di
data/ o logs/ di qui cambiato), non invia per assenza di codice e non per permesso. §12 rimanda.
- cc01: ogni giro con entrambi gli asset misurati scrive data/cc01_regime/runs.jsonl (ts ms,
stato, funding 30g/7g); se non vede, non scrive e lo dice. monitor_health: MonitorSpec
giornaliera, max_age 30h, percorso incrociato con cc01.RUNS da un test (P1).
- tests/test_cc01_regime_watch.py (4, rossi prima). Suite completa: 1074 passed.
Autorizzato da Adriano il 16/09 dopo la revisione settimanale.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Decisione dell'operatore 10/09 («riportarla a quota in autonomia»). Verificato da revisione fable
(10 segnalazioni, 9 applicate; loop numerico su usde_convert.piano: nessuna sequenza vendita→acquisto).
- quarto stato ECCEDENTE: slack > cuscino_riacquisto_frac (0,40) x cuscino => acquisto di USDE fino
allo stesso bersaglio della vendita, q* = 1 - 0,30 x (1 + cuscino_margine_frac 0,20) = 0,64.
Isteresi [0 ; 0,40] x cuscino con bersaglio unico 0,20: per oscillare servono +-8,6% di equity
USDC (~$380); un bonifico alza lo slack di 0,7 x importo e sopra ~9% dell'equity ricompra da solo.
- le tre frazioni (preavviso/margine/riacquisto) in config/live.json sezione usde, lette da
usde.bande_cuscino() che verifica l'ordine; quota_target 0,70 TOLTO (slack zero per costruzione).
- notifier.notify: html.escape su titolo e valori — la prima allerta vera (13:53Z) era andata persa
per un '<' nudo; allerta_errore registrato nel record (P3).
- da ECCEDENTE un fallimento si ritenta ogni 24h (non 4 Telegram/giorno per sempre); bande fuori
ordine => BLIND con motivo, non un traceback ingoiato dal cron.
- CLAUDE.md §1/§4/§5.17, config _nota_usde/_nota_cuscino, diario. 0,64 e' una DERIVAZIONE
dell'autore, non la quota decisa il 30/08 (0,70): dichiarato, da confermare.
- test: 1070 (+8 netti).
Fixes#7
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kqvff47UBGeYfj1QeN4zE
Decisi dall'operatore il 2026-09-10, verificati da revisione fable (15 segnalazioni, 12 applicate).
- usde_watch: TRADE_LIMIT 1000 (count max Deribit) e trade_copertura(): lista troncata o ultima
lettura oltre la finestra di 24h del gateway => somma NON leggibile, reward non attribuito (P12).
Riga del 07/09 corretta nel log con campo `correzione` (400 USDE erano acquisti, non reward).
- cuscino_watch.py (cron :53, monitor_health): equity USDC contro cuscino derivato da
usde.cuscino_richiesto_usd (formula spostata in src/live/usde.py, usde_convert la importa);
OK/PREAVVISO/SCOPERTO/BLIND; sotto zero lancia usde_convert --quota quota_ripristino(0.20)=0.64
--esegui con guardie (execution_enabled, depeg_warn, 1 tentativo/6h). Primo giro: PREAVVISO, +$26.
- usde_convert: il tetto del venue vale solo in ACQUISTO (bloccava la vendita).
- paper_prevday: GATE PREVDAY-01 cablato (2027-06-21, kill Sharpe giornaliero < -0,50 su >=180 g
attivi, veto >=80% barre ricostruibili + divergenze non crescenti con soglia materiale).
Oggi: +0,95 su 81 g, 1942/1943 ricostruibili, kill NON MATURO.
- CLAUDE.md: arming 20/06 (TP01) / 23/06 (BOOK); piano EUR 5.000 chiuso col versamento 04/09
($2.414,68 dal balance, dichiarato); SCALA-01 non prima del 2027-02-28 (A2 dal 01/09);
PREVDAY-01 con data, kill, veto; §5.17 riparato con i limiti dichiarati (ratchet, slack zero a 0,70).
- test: 1062 (+31): test_cuscino_watch (16), test_paper_prevday_gate (8), test_usde_watch (+5).
Fixes#2Fixes#3Fixes#4Fixes#5Fixes#6
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kqvff47UBGeYfj1QeN4zE
- src/live/revisione.py: materiale (CLAUDE.md, config, crontab, git, monitor_health, stati dei
sorveglianti, 7 g di giornale e diari, ~195k caratteri), prompt con dieci regole (sola lettura, fonte
per ogni segnalazione, solo numeri del materiale, §3 non si ripropone, idee nuove solo citando la
memoria, gate con data e criterio), guardia sui numeri, rapporto firmato (P13), Telegram = Sintesi
con taglio dichiarato; modello muto o risposta senza titoli -> rapporto «NON eseguita» + 🚨 (P5).
- scripts/live/revisione.py (guardia cli.valida, --secco/--no-telegram/--quiet/--giorno/--modello),
scripts/cron_review.sh, crontab `15 6 * * 1`.
- primo giro reale: il prompt su argv moriva con `Argument list too long` senza rapporto ne' allerta ->
prompt su stdin, ogni eccezione diventa errore dichiarato; `analista.pulisci` toglieva i titoli.
Secondo giro: docs/revisioni/2026-09-09.md, stato sospetta (cifre in formato italiano), nessun URGENTE.
- scartati con la memoria: autoregolazione dei parametri, generazione automatica di strategie, macro
da internet (diario 2026-09-09c, memoria 40).
- test: tests/test_revisione.py (18) + 2 in test_cli_flag; suite 1031/1031.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bjj5vPEBoAJrB23P6RjKzs
- cblib.causale(s, cadenza): spot_series e dvol_series escono causali (asof = ultima chiusura NOTA);
il DVOL giornaliero era una seconda serie con lo stesso difetto (fino a 24h avanti), verificato contro
l'API pubblica a 1h. Regolamento ST alle 08:00 invece delle 09:00.
- §11 riprodotto al millesimo su worktree HEAD (0,714 [0,690-0,779], n=19, flag --al) e rimisurato:
0,712 [0,664-0,732]; solo spot 0,721, solo DVOL 0,693, DVOL orario di controllo 0,717. Mediana onesta
BTC 1,45 → 2,12, fee 1,51x/1,87x. r0730: 0,73 → 0,71. §75: ETH pre 0,76, BTC durante 0,89 (orario 0,83).
skew panel ≤0,005. vrp_f_watch: f canonico 0,732 → 0,706, differenza +0,097 [+0,042, +0,140].
- r0909 senza doppio shift, contesto sul DVOL del giorno; r0822 regime su date di calendario; r0901
join riallineato (bit-exact). Aperti con costo: DVOL orario (−0,04/+0,06 nel crollo), spot 5m (≤25 min).
- test: +3 causalita' in test_cb_chain_vrp, anti-doppio-shift in test_r0909; suite 1011/1011.
- revisione fable: 16 segnalazioni, tutte applicate (fra cui un «−1,8% in un'ora» che era +3,9%).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bjj5vPEBoAJrB23P6RjKzs
Quattro misure (r0909_*), nessun cambio a libro/pesi/config:
- libro nei crolli: −0,48%/g nei 160 giorni ≤ −5%, positivo per finestra dal 2022
per la gamba short di SKH01 (108% dei guadagni); beta 0,0769 riprodotto (§46);
il peso di SKH01 resta chiuso dal gate (in-sample).
- crollo catturato 1-5/06/2026 a quote vere: f_net 0,74 = rally; put δ−0,10
1,92× il modello; a vol bassa e fuori dal gate di VRP01 → §3 non si riapre.
- XRP terza gamba (harness r0822_sol_leg): hold-out −0,169 in 0/24, un anno buono.
- universo Deribit: liquidi solo BTC/ETH/XRP/SOL; XS01 13/19; BTCDVOL future
non negoziabile; PAXG non misurato.
Revisione fable: due conclusioni smontate (MTM 2,6× era un artefatto di quote;
«8/12 guadagna» era l'ordine delle classi). Debito §5.18: cblib.spot_series
+ asof guarda un'ora avanti (feed 1h etichettato all'apertura).
Test Opus: 92 nuovi, suite 1008/1008; due difetti del verdetto XRP corretti.
Docs: diario, RESULTS §74-77, CLAUDE.md, memoria 20/50, README; journal 07-08/09.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zJjHUS7mf4pnGE6pq9RTt
Su autorizzazione dell'operatore («usa piu' USDE», «cerca % massima raggiungibile»):
- usde_convert al 31,8% (774 USDE), poi sonda a saldo crescente r0906_usde_tetto_sonda.py
(passi 100->20->4->1, doppio rifiuto prima di scendere, conferma a saldo neutro): da 31,8%
a 68,7% in 39 ordini @ 1,0005, ZERO rifiuti. Fermata dal cuscino di regolamento (70%,
derivato da config), non dal venue. «Il 70% non e' raggiungibile ne' ora ne' mai» (31/08)
e' falsificato: il tetto e' sparito, non scalato. Non spiegato, puo' tornare.
- config: venue_cap_frac -> null (misura in venue_cap_misurato), quota_max_frac 0,50 -> 0,85
(il valore scelto dall'operatore il 30/08 per questo scenario).
- debito §5.17: nessuno sorveglia il cuscino USDC (slack $58; una perdita del libro lo consuma
da sola).
Versamento di prova di EUR 25 il 25/08 08:00Z (dichiarato dall'operatore): +3,3% su $647, sotto
la soglia del 10% del rilevatore, contato per 12 giorni come trading.
- data/live/movimenti_dichiarati.jsonl (append-only, nel backup) letto da
journal.movimenti_dichiarati; movimenti_capitale lo fonde coi rilevati (fonte dichiarato,
importo dell'operatore, dopo = prima + importo; dichiarato+rilevato se coincide; fuori
letture o riga rotta -> avvisi). Report e nota di giornale lo dicono.
- trading da arming +87,35 -> +62,45; TWR +11,98% -> +7,83%. CLAUDE.md §2 aggiornato.
- tests: +6 in test_journal (conftest isola il file). Suite 916 verdi.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KSnordG9FT4q8M4MVm85GQ
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
Il feed 1h certificato si ferma alle 00:00: per le letture successive `asof` dava la stessa
barra a t0 e t1, mercato "fermo" = 0, e qualunque calo >=10% del giorno sarebbe stato un
"movimento" scorporato come prelievo (giornale dal 25/08, report da oggi). Con feed assente
tutto era "ambiguo" e il report stampava e1/e0-1 sotto l'etichetta TWR.
- journal.movimenti_capitale: stato "mercato non misurabile" (feed fermo/assente/barra
mancante) => ambiguo con la ragione; leva_tetto = min(frac x n x scala, LEVA_LORDA_MAX) (P1).
- journal.rendimento_twr: salto non classificabile => twr E trading None con motivo.
- journal.pnl_giorno CHIAMA rendimento_twr (prima rifaceva cum - certi: "entrambi la chiamano"
era falso); la pagina stampa il TWR; analista qualifica il cumulato "di cui versati".
- trades_db --report: la classe di ogni salto con la sua misura (mercato max a leva piena).
- book_execute docstring: banda dello stop -33,5%/-26,5% (era invertita), "non costa ordini"
-> micro-ordini di ri-taglia (22/48, C2), latenza <=1h solo con feed fresca, conteggi di
r0823 al posto di "raddoppia" (2 contro 1 e' rotolante vs pavimento sulla riga 4h; la
peggiore misurata e' 24h).
- test_book_cadenza: LTF_MIN importato da skyhook; tutte le righe attive della crontab (una
sola); tre stati dello skip (col progetto ma senza cron_book => ROSSO); slot di release
testato con venue_probe (il :07 come controllo positivo); parser regolare, passo > 0.
- r0823_sl_anchor: guardia sul :47 (era sul vecchio :07), prosa al passato; cron_chain.sh idem.
- CLAUDE.md: §5.7 frase invertita corretta, §5.14 limite vero (non l'artefatto della fixture),
§2 ora della LETTURA (13:47Z), nuovo debito §5.15 (USDE fuori dal bound di mercato).
- diari: tempi "scritto" corretti coi commit; sezione "Seconda tornata".
Test +11 (858 verdi).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XDJsH3iDSaBns3ccpPBwiu
Quattro segnalazioni della revisione sui commit di oggi, tutte verificate e riparate.
1. book_execute.py (+ CLAUDE.md §5.7, memoria 40): «il disaster-SL rotolante si ri-ancora ogni
ora» era falso — ensure_disaster_sl lascia il bracket finche' lo stop e' entro il 5% e la
taglia entro il 10%; il giro orario CONTROLLA, ri-ancora oltre la tolleranza (mark
+5,263%/-4,762%). Lo stop siede fra -26,3% e -33,3% dal mark corrente.
2. journal.rendimento_twr: limite dichiarato (D5) — l'intervallo che contiene un movimento
certo esce intero dal rendimento, il suo P&L di mercato va in `certi`; errore massimo meta'
del movimento per costruzione (25/08: ~$0,5). Non si stima (P12). Segmenti a lunghezza zero
non prodotti; nessun tempo a mercato -> 0,0 dichiarato numero.
3. base di equity zero: `twr` E `trading` None con motivo (il salto 0->X e' invisibile al
classificatore, `trading` valeva l'intero conto); il report stampa n/d.
4. test_book_cadenza: la guardia estrae ogni prescrizione «ogni/every N unita'» e pretende 60
minuti, con controllo positivo (M15); limite P13 dichiarato.
Test +5 (847 verdi). Diari 02/09 e 02/09b con la sezione "Revisione".
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RziUCB336YPUUyDJ29x4Ke
Il docstring di book_execute.py prescriveva «ogni ~230 minuti» mentre il cron gira ogni ora
(47 * * * *). Era il docstring a sbagliare: sulla riga 4h BTC raddoppia gli scatti del
disaster-SL rotolante (r0823_sl_anchor.py), e chi avesse "corretto" il cron verso il
docstring avrebbe spostato il libro sulla riga peggiore.
- scripts/live/book_execute.py: CADENZA: ORARIA, la riga di crontab, la ragione (giro
idempotente, latenza SKH01 <=1h, ri-ancoraggio orario) e il divieto esplicito con la data.
- tests/test_book_cadenza.py (10): deriva e confronta docstring, intestazione di
cron_book.sh e crontab installata (crontab -l; SALTATO se illeggibile, non verde);
parser a 5 campi solo per cadenze regolari; 60 < 230 < 240; minuto != :00.
- docs: CLAUDE.md §5.7 chiuso, §13 conteggio 842; memoria 40; diario 02/09b.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RziUCB336YPUUyDJ29x4Ke
`trades_db.py --report` calcolava e1/e0-1 sulla serie grezza di equity: il 96,3% del
numero era il versamento di $1.399,39 del 25/08. La riparazione (journal.movimenti_capitale)
esisteva e non aveva attraversato il confine fra i due lettori della stessa serie (P1).
- src/live/journal.py: `rendimento_twr` — funzione unica, spezza la serie sui movimenti
CERTI e moltiplica i segmenti; gli ambigui restano dentro, dichiarati (P12); tre stati.
- scripts/live/trades_db.py: report() la chiama; stampa TWR con segmenti datati, movimenti
elencati, trading al netto, delta $ etichettato "movimenti INCLUSI"; il % grezzo sparisce.
- test: +5 in test_journal.py (incl. riproduzione del +10,80% del diario 01/09, M23),
+2 in test_trades_report.py sul testo stampato con connect() deviato in tmp. 832 verdi.
- docs: CLAUDE.md §5.14 chiuso, §2 e §13 aggiornati; memoria 40; diario 02/09.
Limite ereditato e dichiarato (D5): +10% di trading fra due letture consecutive tocca la
soglia del rilevatore e a mercato fermo verrebbe classificato movimento.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RziUCB336YPUUyDJ29x4Ke
Chiude il debito che CLAUDE.md dichiarava da settimane: la regola "ogni cambio
di scala passa dal cap di config, non da target_vol" NON era implementabile
perche' una chiave di scala non esisteva — qualunque cambio sarebbe finito su
WEIGHT/W_TP01/W_SKH, cioe' codice su un percorso con soldi veri e per giunta
nel posto sbagliato (W_TP01/W_SKH sono il RAPPORTO 75/25, non la taglia).
Specifica gia' scritta in docs/research/SPEC-scale-key.md (618 righe, 9
condizioni di gate, prototipo). Non ho progettato: ho eseguito i punti 1-4.
🚨 config/live.json NON E' STATO TOCCATO. La chiave e' assente, vale 1,00, e
T7 dimostra bit-exact che il libro e' quello di ieri (max|diff| = 0.0).
Verificato anche a runtime: book_execute in dry-run da' gli stessi target del
cron delle 15:47 (BTC $+355, ETH $+214).
LE QUATTRO DECISIONI CHE NON SONO DI COMODO
- La scala si applica DOPO il clamp. Prima, il cap se la mangerebbe proprio
nei giorni di massima convinzione (a tp=1/sg=+1 il grezzo vale esattamente
cap => k_eff tornerebbe a 1,00 a ogni k): sarebbe un cambio di FORMA
travestito da cambio di taglia, e la curva g(k) con cui il gradino viene
autorizzato non descriverebbe quel libro. Prezzo dichiarato: il cap diventa
il tetto del libro UNITARIO, e la guardia sulla leva lorda va ricostruita.
- Il tetto e' sul PRODOTTO e sta nel CODICE. Sulla sola chiave lascerebbe
aperta la porta accanto (frac 0,625 x scala 1,25 = 1,562x); in config
sarebbe un lucchetto con la chiave attaccata. LEVA_LORDA_MAX 1,25 in
src/live/book.py => il gradino a 1,50 richiede codice, quindi review.
- Fuori scaletta o fuori tetto = STOP, non clamp. book_execute si ferma, non
invia, allerta (ScalaNonAutorizzata). E SCALA_LADDER (1,00 · 1,25) rende
INESPRIMIBILE "solo un po'": 1,05 non e' prudente, e' fuori scaletta.
- La scala vive solo sul percorso fidato (equity illeggibile => 1,00), cosi'
"il fallback non e' piu' permissivo" e' vero per costruzione. Ma la
VALIDAZIONE avviene sempre: una config rotta non si nasconde dietro un giro
in cui l'equity non era leggibile.
LA GUARDIA CHE MORDE PER PRIMA non e' il peggior giorno (k <= 3,49x) ma il
COSTO di un disaster-SL (k <= 1,67x, 2,1x piu' stringente): l'invariante
n_asset x frac x scala x disaster_sl_pct <= 0,50 scatta anche se qualcuno
allarga lo stop invece di alzare la scala.
TEST T1-T11 (tests/test_book_scale.py, 18 verdi). Il piu' importante e' T1b:
a k=1 l'implementazione simmetrica e quella asimmetrica danno lo STESSO
numero, quindi un test di simmetria scritto sul caso di default ha potenza
ZERO. T1b verifica che le due coincidano a k=1 (il rischio e' reale) e che
fuori da k=1 l'asserzione le SEPARI, con un'implementazione asimmetrica
scritta nel test apposta perche' fallisca.
SORVEGLIANTE scale_watch (cron_daily, 3 domande / 3 azioni / 3 stati, una
allerta per streak, marcatore scritto solo dopo invio riuscito — debito #2).
Riporta la frequenza del ramo di fallback, che sopra il 2% in 90 giorni
invaliderebbe la regola: misurata 0/1.676, coi 19 giri "paper capital"
(pre-finanziamento, dove il libro non invia) contati e dichiarati a parte.
Non puo' impedire la modifica: la rende visibile entro 24h e attribuibile.
CHIUDE il debito #5 di §5: T2/T3 sostituiscono il vecchio
test_leva_massima_da_config (che misurava frac x n_asset mentre la grandezza
vera e' frac x n_asset x scala), e T11 verifica che sia rimasto cancellato.
NON FATTO, deliberato: la chiave in config (punto 2 lo vieta), GATE SCALA-01
(A2 richiede >=30 giorni a 1,00 col sorvegliante attivo — "l'unico modo di
scoprire che il sorvegliante e' rotto mentre la leva e' ancora 1,00"),
r0726_fee_sensitivity rifatto (A7: serve solo al gradino; a 1,25x una
liquidazione costerebbe 1,25% non 1,00%, e ereditarlo sarebbe l'errore).
Nessun ordine. Suite: 825 passati.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Chiesto dall'operatore in quattro battute: hold BTC long o short coperto in
opzioni, scadenza <=15gg, "ridurre la vincita ma bloccare la perdita" (=>
collar, non put protettiva), entrata gated da indicatori ("forte bull"), e
uscita dalle opzioni fra il 50% e il 75% del tempo.
PERCHE' SI POTEVA RIAPRIRE DOPO §46. §46 (tail-hedge) fu refutato sul beta
+0,076 del libro — "non si assicura un libro che nei crash e' gia' quasi
piatto". Qui il sottostante e' un hold di BTC, beta 1,0: quel motivo non si
applica. E §46 dichiarava non provata proprio la copertura gated su regime.
L'entrata non aggiunge un solo parametro: tsmom_blend media tre np.sign() su
(30,90,180) => valori in {-1,-1/3,+1/3,+1}, quindi "forte bull" = |blend|==1
(52,5% dei giorni) contro il confronto dichiarato |blend|>=1/3 (97,1%).
RISULTATI (lente lunga 2021-03 -> 2026-09, 5,44 anni; griglia 48 celle
dichiarata prima + 36 di estensione dichiarata):
- A1 CONFERMATA: il pavimento FUNZIONA, maxDD scende in 36/48 (§46: saliva
in 162/162). La meta' della domanda ha risposta positiva.
- A3 CONFERMATA: il de-levering lo fa meglio in 45/48. Δdrift/ΔmaxDD 7,90
(gate forte) / 1,98 (largo): 2-8 punti di drift per punto di DD.
- C9 in forma pura: il tetto taglia il 46,2% dei cicli VINCENTI, il pavimento
para il 6,7% dei PERDENTI — 7x piu' spesso sui vincenti: troncatura.
- M1: collar Sharpe 0,508 vs TP01 0,852; TP01+10% => +0,000 di Sharpe e
+2,32pp di maxDD.
IL FATTO CHE VALE PIU' DEL VERDETTO. Le 3 celle vincenti stavano tutte sul
BORDO; estesa la famiglia vince 35/36 nell'ANGOLO (dput 0,02 / dcall 0,50,
Sharpe 1,471) — e il limite di quell'angolo e' una COVERED CALL: la pendenza
porta fuori dalla domanda posta e dentro lo short-vol. E quel 1,471 e' il
prezzatore che si paga da solo: DVOL/RV-forward 1,320 a 7g (sopra nel 76,9%
dei giorni) => riprezzato alla vol vera l'angolo cade a 0,511, che e' VRP01
(0,47). Non una scoperta: VRP01 per una strada piu' lunga. §3 lo blocca.
USCITA ANTICIPATA: implementata (exit_frac) e COSTA. Cella onesta gate forte:
drift +9,48% (scadenza) -> +3,84% (50%), esito da VINCE a perde sotto 0,75.
Il meccanismo previsto c'e' (VRP residuo +3,38 -> +1,27pp) ma lo spread lo
travolge. Corregge l'applicazione di §46: "un roll anticipato non paga f"
vale per una copertura solo LONG; in un collar la gamba venduta va
RICOMPRATA, quindi si paga f sulla parte che a scadenza si regolava gratis.
L'asimmetria si INVERTE quando la struttura ha una gamba corta.
CONTROLLI DELL'APPARATO 3/3 (M15): pranzo gratis riconosciuto (maxDD
51,83%->36,76%, drift +10,04%->+35,69%), premio x10 rifiutato, zero-cost
finito. Cinque difetti miei catturati dai controlli, non a occhio: bisezione
zero-cost invertita (dava Sharpe -3,9), dcall=NaN nella cassa, C9 non
consapevole della direzione (S1>S0 non e' "vincente" per uno short), e due di
contabilita' che avrebbero ADULATO il collar (base che rollava lo spot
pagando ~3,6%/a di fee inesistenti; roll che chiudeva lo spot senza motivo).
Corregge anche un muro di §46: il tick da 5 USDC e' della famiglia USDC; la
catena che raccogliamo e' 100% inverse, quindi li' non si applica.
Regole nuove in CLAUDE.md: M29 (un edge da opzioni prezzate a modello si
riprezza alla vol REALIZZATA prima di crederci), M8 esteso (un argmax sul
BORDO e' una pendenza, non una cella), C4 esteso (il segno dell'asimmetria di
f dipende dal verso della gamba).
Libro, pesi, cron, config INVARIATI. Nessun ordine. Suite: 807 passati.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nasce dall'annuncio sulla fine della Proof of Reserves. La notizia in se' vale
poco: si perde un segnale ad alta frequenza e DEBOLE (una PoR auto-pubblicata
prova che gli attivi esistono in un istante, non che coprano le passivita') e si
guadagna un audit annuale indipendente sotto VARA piu' il 90% degli attivi presso
Coinbase come custode. E non l'abbiamo mai sorvegliata: zero occorrenze nel
codice. Rinunciato di proposito a catturare l'ultimo dato — uno snapshot singolo
auto-riportato non regge lo standard di prova e non permetterebbe di stimare `p`.
CONSEGUENZA VERA: la decisione "100% Deribit fino a $20k" ha fra i suoi riapritori
"`p` che diventa stimabile invece che assunto". Dal 1/9 il segnale pubblico passa
da quotidiano ad ANNUALE: da una serie si stima, da un punto all'anno no. Quel
riapritore diventa praticamente irraggiungibile => la decisione e' ora gated SOLO
dal capitale.
TROVATO CERCANDO: esiste un feed RSS degli exchange-update, e conteneva quattro
annunci materiali che nessuno leggeva. Il caso che decide: le specifiche dei perp
USDC sono cambiate il 18/08, ANNUNCIATE IL 14/08. check_specs() e' nato da quella
svista e gira ogni ora, ma rileva la deriva DOPO; il feed l'avrebbe detta quattro
giorni PRIMA. La prima volta e' andata bene solo perche' i cambi erano RIDUZIONI.
Costruito scripts/live/venue_news.py (in cron_daily accanto a fee_watch):
- NON interpreta: dice "e' uscito questo, guardalo". Nessun automatismo su un
testo di marketing (P13). Classifica solo l'urgenza.
- parole-chiave DERIVATE da deribit._CONTRACT e config/live.json, non
ridichiarate (P1): chi aggiunge un asset allarga la sorveglianza da solo, ed
e' il test che lo blinda.
- primo giro semina senza allertare (P9); feed illeggibile -> exit 2, mai
silenzio implicito (P5).
Debito #8 si RESTRINGE, non si chiude: il Rulebook non ha un feed.
Confermato due volte lo zero USDC: l'espansione del 31/07 non contiene l'Italia
ne' alcun paese UE, mentre San Marino e Citta' del Vaticano SONO idonei. Non
asserisco una causa (ci sono anche Canada e Giappone).
DUE CORREZIONI dalla KB "Cross collateral specifications":
(a) Il saldo negativo costa una collateral fee dello 0,05% AL GIORNO = 18,25%/anno,
al secondo — 4,3x la resa USDE. Il 30/08 avevo scritto "lo finanzia a
interesse" SENZA il numero: giusto e vuoto. Col numero, il criterio del
cuscino di regolamento diventa aritmetica (-14 punti). E il ribilanciamento
automatico non salva: scatta a $1M assoluti o al 100% della cross equity,
irraggiungibili a $2k. Non veniamo ribilanciati: sanguiniamo la fee.
(b) L'haircut USDe ufficiale e' 5%, noi abbiamo 0.10 registrato come "verificato
sul venue" il 26/08 senza traccia di come. NON riparato (P12/M28): si tiene
0.10 perche' e' il lato conservativo, non e' sul percorso soldi e non morde
fino al 90% di quota. Divergenza dichiarata in config.
Di lato: BUIDL haircut 2% (sarebbe stato il miglior collaterale del listino, se
si potesse comprare), stETH 7,5% (terza ragione indipendente per lasciarlo stare).
Nessuna fonte documenta un tetto sulle QUANTITA': il ~31,2% resta misurato e non
spiegato — e ora si sa che non e' una svista di lettura.
Suite: 800 passati (5 nuovi su venue_news).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Il 2026-08-28 12:35Z `usde_watch` ha rilevato il primo reward (+0.052055 USDE su
500), e la regola pre-registrata il 26/08 PRIMA dell'esito ha chiuso il gate
USDE-01 su IDONEO. Si apre la decisione di QUOTA, che e' dell'operatore.
DECISIONE DELL'OPERATORE (29/08): la quota si decide lunedi' 31/08, su tre-quattro
finestre invece che su una. Il motivo e' un numero: sul solo pagamento il tasso
implicito e' 3,80% annuo, su DUE finestre — il 27/08 aveva pagato ZERO — e' 1,90%.
Fra i due c'e' tutta la decisione, e il campione e' UN pagamento.
`rendimento()`: APR sulle finestre OSSERVATE, col denominatore sul TEMPO VERO e
non sul numero di finestre pagate — cosi' una finestra che non paga ABBASSA la
stima invece di sparire (P5: quel silenzio e' uno zero). Le letture con trade nel
mezzo si escludono, non si riparano in silenzio (P12). L'APR si stampa sempre col
suo `n`, e sotto 4 finestre la riga dice «un pagamento non e' un tasso». Sulle
letture vere: 1,97% annuo su 1,9 giorni, 1/2 finestre pagate.
`quota_da_decidere()`: vera SOLO se IDONEO E il rinvio e' scaduto. Da lunedi' il
watch manda il 📌 OGNI giorno — quota attuale, tetto di allerta, APR osservato —
finche' non si decide (N9: una decisione rinviata senza promemoria e' rinviata per
sempre). Stesso schema della soglia $15k di GTAA01, con la data al posto del
capitale. Si smette togliendo `DECISIONE_QUOTA_DAL`.
6 test nuovi, incluso il controllo positivo — «la finestra sola darebbe il doppio»
— che e' esattamente la ragione per cui l'APR non si cita senza il suo n.
CONFERMATO il fix IB di ieri: il giro delle 00:30 ha 0 righe
`orders request timed out` (erano 2 per giro, 63 su 63) e tutti e sei gli ETF
scaricati. E una conferma involontaria del debito §5.13: SPY e' passato da
1996-09-04 a 1996-09-05 — la finestra rotolante ha perso un altro giorno in una
notte, come misurato.
Diario: docs/diary/2026-08-29-usde-idoneo-e-ib.md
Suite: 795 passati, 0 falliti.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Difetto trovato addosso: `uv run pytest` mandava messaggi Telegram VERI sul
canale dell'operatore — cinque per giro, col testo delle fixture («Analisi di
ieri.», «rete KO», «Testo dell'agente.») sotto l'intestazione di una voce di
giornale del 21/08. Colpevoli i cinque test di `analista.CLI.scrivi()`, che non
passavano `telegram=False` e percorrevano `invia()` fino a `notifier.send()`.
`_cfg()` legge il token da `.env.mainnet`/`.env`: il fatto che non fosse
nell'ambiente non proteggeva niente.
NON E' COSMETICO. E' P9 al contrario — allarmi finti spesi su un canale che
deve restare credibile il giorno che l'allarme e' vero. Chi riceve cinque
messaggi identici a ogni giro di test impara a non aprirli, ed e' l'unico
canale da cui passano disaster-SL, uscita di fondi e venue giu'.
RIPARAZIONE STRUTTURALE, stessa lezione del watermark (§5.12): si blocca la
RETE in una fixture autouse, non si chiede a ogni autore di ricordarsi un
parametro. Un test che vuole davvero esercitare `send()` continua a funzionare
— patcha `urlopen` nel proprio corpo e vince su questo.
In piu' una guardia di sessione: bloccare non basta, un tentativo va TROVATO e
reso esplicito, o resta li' pronto a tornare vero il giorno che qualcuno cambia
il boundary. Validata su controllo positivo (M15): un test che chiama
`notifier.send()` fa fallire la sessione.
⚠️ E un difetto fatto e corretto nello stesso giro: la prima versione registrava
l'URL, che contiene il BOT TOKEN in chiaro — e quella lista finisce nel
messaggio di un assert, cioe' nell'output della suite e nei log. Ora si registra
solo "telegram sendMessage": serve sapere CHE si e' tentato, non VERSO DOVE.
Il token e' stato esposto una volta nell'output di quella verifica: va ruotato.
Suite: 789 passati, 0 falliti.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Decisione dell'operatore: GTAA01 NON si blocca oggi, si decide quando il book
arriva a $15k. Il motivo registrato non e' «non contribuisce» — la misura dice
il contrario (+0,095/+0,124 di Sharpe a iso-rischio secondo la fase, positivo in
tutte e cinque, hold-out +0,247, 6 anni su 8, correlazione col resto +0,087).
Il motivo e' che sotto $15k di book lo sleeve NON E' ACCENDIBILE:
GTAA_MIN_CAPITAL e' $3.000 allocati, che al peso 20% fa $15.000 contro i $2.068
attuali. Finora era manutenzione senza beneficio incassabile.
Registrate anche le due ragioni contro il blocco, che restano valide: N7 (uno
sleeve difensivo si giudica sul sinistro, e questa finestra non lo contiene) e
N4 (togliendolo il portafoglio di ricerca diventa 100% cripto su un venue solo).
E il costo che sarebbe andato pagato: GTAA01 e' uno dei quattro nomi di
W_DEPLOY, da cui escono i $313k del muro.
PERCHE' LA DECISIONE NON SI DIMENTICHI (N9). Una decisione parcheggiata su un
numero che nessuno sorveglia e' parcheggiata per sempre. `journal.SOGLIE_CAPITALE`
legge l'equity ogni giorno — il giornale lo fa comunque — e il giorno che supera
la soglia la voce dice quale decisione si sblocca e perche'. Seconda riga: $20k,
dove si riapre «100% Deribit fino a $20k». Una riga si TOGLIE quando la decisione
e' presa. 5 test, incluso «equity non leggibile non e' una soglia superata» (P5).
GATE (A) RITIRATO come pass/fail, congelando il MOTIVO e non l'esito — come il
07/08 col confronto fra ranghi, e per la stessa ragione: il criterio decide su un
margine piu' piccolo del rumore che lo scuote. In piu' una guardia sulla CAUSA
(`test_la_fase_di_ribilanciamento_e_ancora_ancorata_alla_POSIZIONE`) che si rompe
il giorno che qualcuno ancorasse la fase al calendario: quel giorno il gate
potrebbe tornare decidibile, ed e' un fatto da guardare, non da ignorare.
Il test sul margine assoluto si e' auto-ritirato: diceva «se scendesse sotto un
centesimo questo criterio smetterebbe di essere una misura», ed e' sceso a 0,0074.
CLAUDE.md: §3 nuova riga · §5.2 RISOLTO (trasporto allarmi) · §5.4 riscritto (la
domanda fiscale (a) ha una risposta alla fonte: derivati in c-quater al 26%, non
c-sexies al 33% — Circolare AdE 30/E del 27/10/2023, citata verbatim) · §5.13
nuovo debito, la fase che ruota — quantificata e dichiarata INNOCUA oggi (D5):
0,029 di Sharpe a livello di portafoglio, dentro la banda [1,81-2,12].
Diario: docs/diary/2026-08-28-gtaa-fase-e-allarmi.md
Suite: 789 passati, 0 falliti.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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 2026-08-28 alle 00:37:00Z la CLI `claude` e' uscita 1 scrivendo
«Failed to authenticate: OAuth session expired and could not be refreshed»
su STDOUT, con stderr VUOTO. `interroga()` componeva il motivo dal solo
stderr, quindi nel DB e' finito `analisi_stato='errore'`,
`analisi_motivi='uscita 1: '` — e su Telegram e' partito
«analisi non disponibile (errore): uscita 1:».
La meccanica ha retto (nessuna analisi di ieri spacciata per quella di oggi,
esito registrato, notifica partita): a mancare era solo il PERCHE'. P4 —
un'allerta risponde a due domande, e con la prima sola la causa si ricostruisce
aprendo a mano il transcript della sessione headless. P3 — quando la diagnosi
serve, il guasto e' gia' rientrato: il motivo si cattura li' o mai.
- `motivo_uscita(returncode, stdout, stderr)`: unisce i due canali (stderr per
primo), tronca a 300 caratteri.
- Silenzio totale su entrambi i canali -> lo DICE, invece di lasciare i due
punti a vuoto: «la CLI non ha detto perche'» e «il perche' l'abbiamo perso
noi» sono guasti diversi e finora si scrivevano uguali.
- 4 test nuovi, fra cui la regressione col messaggio testuale del 28/08.
NON risolve la causa a monte: perche' quella refresh sia fallita non sta in
nessun log locale. Il refresh token era valido (rinnovo automatico riuscito
alle 08:03:35Z dello stesso giorno, scadenza 2026-09-25) e la stessa chiamata
rifatta a mano esce 0 -> guasto transitorio, unico su 24 sessioni locali.
Da qui in avanti, se ricapita, il motivo si legge dalla notifica.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- config/live.json sezione `usde` (unica autorita', P1): indice, haircut 10%,
tetto allerta quota 50%, soglie depeg 0.99/0.95 coi criteri dichiarati (P6)
- src/live/usde.py: config + catena di prezzo (indice pubblico -> ticker ->
1.0 dichiarato) + valutazione PURA; shadow._collaterale_usde ora deriva da qui
- scripts/live/usde_watch.py + cron_usde.sh (12:35 UTC, dopo la finestra reward):
reward per delta netto trade (P12: senza inventare attribuzioni), depeg
(crit ripetuto, resto a transizione, P9), quota anche per deriva passiva (N4);
applica il verdetto di eligibilita' pre-registrato (>=1 reward entro 29/08)
- serie data/live/usde_watch.jsonl sotto monitor_health (max 30h, P5: un watch
fermo non deve leggersi come "va tutto bene"); baseline 14:17Z registrata
- GATE USDE-01 in CLAUDE.md §4; test 775 (+17 in tests/test_usde_watch.py)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9UyJLHzR7EJzxR3iQ3RN1
Trovato eseguendo il test di eligibilita' USDE ($500 convertiti alle 13:04Z,
fill 1.0003 fee 0): shadow._equity leggeva solo il conto USDC -> il giro
successivo avrebbe visto -24,3%, mandato un falso "USCITA DI FONDI" e venduto
~$140 di posizioni. Riparato prima del giro delle 13:47: _collaterale_usde()
valuta l'USDE all'indice pubblico usde_usdc (mediana multi-exchange, lezione
Binance 10/10/2025), depeg passa nel sizing, clamp a 1.0 sopra la pari,
fallback 1.0 dichiarato (mai 0: il fallback si sceglie sul danno, P5).
6 test nuovi in tests/test_shadow_usde.py.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9UyJLHzR7EJzxR3iQ3RN1
S5.1 RIPARATO E RIGENERATO. Filtro condiviso src/live/paper_guard.py (barra
open-labeled chiusa = ts + cadenza <= adesso) importato da tutti e 6 i monitor;
serie rigenerate dallo stesso start_ts con scripts/live/paper_regen.py (evidenza
in *.pre_regen_20260826.*): statarb +1,95 -> -1,61 (il ribaltamento del gate
27/09 previsto dall'audit), dvolspread -14,73 -> -4,41, xsr -4,98 -> -2,72,
prevday invariato. Nessuna data di gate si sposta. Guardia cablata in
monitor_health: stato PREMATURO (ultima barra che chiude dopo l'mtime, grazia
5 min, open_labeled=False per collect_chain) — sul dato vivo segnala i 5 rotti
e tace sui 2 sani; dopo la rigenerazione 7/7 OK. paper_portfolio non rigenerato
(GTAA su ADJUSTED_LAST: replay != serie registrata, P12), tolta la coda non
chiusa. D6 pagata di nuovo nel fix: asi8 in pandas 3 e' in us, non ns —
blindata con test su tre risoluzioni.
S5.12 ESTESO: conftest devia anche trades.db (wrapper su connect: il default
e' catturato alla definizione) e docs/journal/; book_executions.jsonl
sorvegliato con impronta inizio/fine suite.
S5.5 FATTO: test_leva_massima cancellato con nota (misurava frac*n_asset:
con una chiave di scala avrebbe continuato a passare smettendo di controllare).
S5.9 INDAGATO E RIPARATO (r0826_skh_band_drift): il dato regge (taglio 02/07
riproduce l'audit 1,6376, in-sample identico su ogni taglio); la deriva era la
finestra hold-out — e la sola settimana 15-22/08 vale +0,35 di Sharpe hold-out.
Il test ora taglia il feed al 02/07 e verifica la riproduzione stretta.
Suite: 751 passati, 0 falliti.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9UyJLHzR7EJzxR3iQ3RN1
Il P&L di giornale era un delta di equity: la voce del 25/08 dichiarava +$1.414,57
di "giorno" quando $1.399,39 erano il deposito USDC, e il cumulato dall'arming
avrebbe mentito per sempre. Nuova `movimenti_capitale()`:
- soglia IMPORTATA da book.EQUITY_JUMP_ALERT, non ridichiarata (P1);
- "movimento" solo se il salto supera di >2x il massimo che il mercato MISURATO
(feed certificato, tetto di leva da config) poteva produrre fra le due letture;
- altrimenti AMBIGUO: dichiarato con attenzione e NON scorporato (P12 -- un crash
vero a tutta leva non deve diventare "prelievo"); idem a feed illeggibile (P5).
Scansione dell'intera storia: 1 evento, esattamente il deposito (+209,6% contro
mercato max 0,22%), zero falsi positivi. `concentrazione` ora lavora sul cumulato
di TRADING; le regole sui movimenti stanno sopra l'early-return "nessun giro".
Limite dichiarato (D5): un movimento sotto il 10% dell'equity resta nel P&L.
7 prove nuove (31 -> 37), incluso il controllo M15 al contrario. Voce del 25/08
rigenerata: giorno -> trading +$15,18; cumulato -> trading +$59,14.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9UyJLHzR7EJzxR3iQ3RN1
Nato da "stato trades" durante una manutenzione Deribit (system_maintenance 11051,
08:57-09:20 UTC). Contati i log invece che ricordarli: 1.499 giri dal 23/06, 3 con
manutenzione, 5 traceback duri — e 4 dei 5 sono il NOSTRO gateway, non il venue.
Le release Deribit escono il martedi' alle 09:00 UTC: il cron al :07 ci cadeva dentro
per costruzione (21/07, 11/08, 18/08, 25/08).
DIAGNOSI (src/live/venue_probe.py, nuovo)
Sonda l'API PUBBLICA Deribit senza gateway e senza credenziali, e classifica il guasto:
VENUE_MANUTENZIONE / VENUE_GIU / GATEWAY / IGNOTO. Prima ogni causa stampava la stessa
riga ("conto non leggibile (offline)") con nota di diagnosi CABLATA — P4 violata, e il
18/08 il codice 11051 era gia' dentro il processo senza arrivare a chi decideva la
gravita'. Parte solo dopo un guasto: sul percorso sano costa zero. P1 rispettata: la
firma 11051 si importa da venue_watch.is_maintenance, non si ridichiara.
P9: la manutenzione dentro lo slot declassa il titolo a info, ma solo su EVIDENZA della
sonda (mai sull'orologio) e solo dentro la durata annunciata — oltre, RIALZA. Un gateway
rotto di martedi' mattina resta al massimo.
DISASTER-SL SCOPERTO (src/live/execution.py)
ensure_disaster_sl cancella i bracket incoerenti PRIMA di ripiazzarne uno: fra le due
chiamate la posizione e' senza stop. Se il ripiazzamento sollevava, l'eccezione risaliva
a main() e il guasto peggiore aveva la faccia di un errore qualunque. Ora: due tentativi,
poi stato `naked`, distinto da `place-failed` (P5). Non e' "non sono riuscito a
proteggere": e' "ho tolto la protezione e non sono riuscito a rimetterla" -> allarme
massimo, mai declassato. La SEQUENZA non e' stata invertita: piazza-poi-cancella sembra
piu' sicuro ma "sembra" non basta con soldi veri senza misurarlo.
ISOLAMENTO PER ASSET (scripts/live/book_execute.py)
Il 21/07 un 502 dentro ensure_disaster_sl su BTC ha ucciso il giro intero: nel log ETH
non compare — ne' ribilanciato ne' verificato nella protezione. Ora un asset che esplode
non ferma il ciclo, e il giro degradato esce con codice 2.
CRON :07 -> :47
Il vincolo vero non era ":07" ma "fuori dai ~26s del minuto tondo" (rate-limit per-IP
auto-saturato dal collettore catena, misura del 30/07). Il :47 lo soddisfa e in piu' sta
fuori dallo slot di release. PREVISIONE DICHIARATA (M12): 3 delle 4 finestre osservate
sono rientrate entro l'ora -> il :47 ne avrebbe scavalcate 3 su 4; se martedi' prossimo
becca comunque la manutenzione, la previsione e' sbagliata.
WATERMARK AVVELENATO DAI TEST (tests/conftest.py, nuovo)
Trovato addosso: lanciando la suite, data/live/equity_seen.json passava a $5.000 e il giro
successivo mandava un allarme Telegram FALSO ("USCITA DI FONDI -86,6%"). Non cosmetico:
cap_fallback = min(cap_config, watermark x frac) sarebbe passato da $334 a $2.500/asset,
~7,5x di leva su un conto da $668, sul ramo eq_fallback che allerta e NON blocca — cioe'
i test potevano armare il pericolo che il watermark esiste per impedire. Riparato con una
fixture AUTOUSE, non per-test: chiedere a ogni autore di ricordarsene ha gia' perso il
26/07 e il 21/08. Resta esposto lo stesso errore su trades.db e book_executions.jsonl.
BLOCCATO, NON RINVIATO
Il fallback diretto ai privati Deribit richiede chiavi API create dall'operatore: in
locale esiste solo CERBERO_TOKEN. Il gateway resta un punto singolo di guasto non
aggirabile (CLAUDE.md 5.11). La sonda dice di chi e' il guasto, non lo aggira.
Test: 20 nuovi, nessuno tocca la rete; controllo positivo fatto (5 su 7 falliscono contro
il codice vecchio). Suite 730 passati, 1 fallito — quello gia' noto di 5.9 (deriva dati).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9UyJLHzR7EJzxR3iQ3RN1
cron_daily (00:30 UTC) faceva DUE chiamate al giornale: chiudeva IERI (giusto)
e apriva OGGI. La pagina di oggi nasceva con ~30 minuti dentro e nessuno la
aggiornava fino alla notte dopo.
Il difetto non era il dato mancante: era che la pagina non lo diceva dove si
legge. Aveva TUTTE le sezioni di una chiusa -> passava ogni controllo di
completezza e freschezza, e la parzialita' stava solo in §Salute, quinta
sezione su otto. Stessa famiglia di "una barra presente non e' una giornata
presente", in veste nuova: la pagina e' presente, il giorno no.
Taglia misurata sul caso reale di oggi: la pagina congelata alle 00:37 diceva
"giorno: $+0.54 (1 letture)" e la regola [pnl] chiosava "senza operare". Alle
08:54 il libro aveva fatto 3 fill, 2 round-trip e +$25.86 ($642.56 -> $667.88).
Avrebbe raccontato una giornata ferma per tutta una giornata operativa.
Riparato in due pezzi indipendenti:
1. la pagina dichiara la parzialita' nel TITOLO e nella prima riga —
"PARZIALE (giorno in corso)", copertura esplicita (N giri su 24), il fatto
che non si aggiorna da sola, e quali numeri sono di quella frazione;
2. tolta la seconda chiamata dal cron. In docs/journal/ restano solo giorni
chiusi; lo stato corrente si prende da journal.py a mano (pagina marcata)
o da trades.db, che cron_book sincronizza ogni ora.
Scelta dichiarata: NON si rigenera ogni ora. Costerebbe una riga in cron_book
ma riscriverebbe un file tracciato da git 24 volte al giorno per un consumatore
che non esiste (l'analista legge il giorno chiuso). Se un domani servisse, la
strada e' RIGENERARLA, non congelarla: e' scritto nel commento del cron.
Prove (test_journal 28 -> 31): una accende la marcatura, una la tiene spenta su
un giorno chiuso (una marcatura sempre accesa non si legge), una e' guardia sul
SORGENTE di cron_daily.sh — ogni chiamata a journal.py deve avere --giorno
esplicito, perche' senza argomenti scrive OGGI.
Regolare docs/journal/2026-08-25.md rigenerato: ora si dichiara PARZIALE (9/24).
NON riparato, e registrato come debito aperto in CLAUDE.md §5:
test_wave_0726::test_t1_canonical_riproduce_il_backtest_ufficiale fallisce, e
falliva gia' prima di questa modifica (verificato con git stash sull'albero
pulito). Sharpe hold-out SKH01 canonical 1,9223 contro la banda cablata
1.3 < h < 1.9: il codice non e' cambiato, sono cambiati i dati (data/raw e'
gitignored, il cron lo ricostruisce ogni notte). La banda NON e' stata
allargata — lezione 07/08. Suite: 710 passati, 1 fallito.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>