# 2026-09-02 — Un flag sconosciuto non è l'azione di default *Scritto fra le 15:45Z e le 16:05Z. Il difetto è stato misurato, non ipotizzato: la revisione del codice di questa sessione ha eseguito `trades_db.py --help` come sonda di tempi e lo ha visto sincronizzare il DB.* ## 1. Il difetto Nessuno dei 18 script di `scripts/live/` usava argparse. Leggevano gli argomenti così: ```python if "--reconcile" in args: ... elif "--report" in args: ... else: sync() # <- qui finiva QUALUNQUE cosa non riconosciuta ``` Un flag sbagliato non era un errore: era il ramo finale. Costo osservato e costi possibili: | script | `--help` faceva | gravità | |---|---|---| | `trades_db.py` | `sync()`: riscriveva `meta.ultimo_sync` | osservato oggi, danno nullo | | `journal.py` | scriveva la pagina di oggi e una riga nel DB | non osservato, ma scrive | | `analista.py` | spendeva una chiamata al modello e mandava un Telegram | non osservato, ma spende | ## 2. La riparazione, e perché non è argparse `src/live/cli.valida(nome, uso, flag=..., con_valore=...)`, chiamata come **prima istruzione** di ogni blocco `__main__` — prima di `connect()`, prima del sync, prima della rete. - `--help` / `-h` → stampa l'uso, esce **0**; - flag non dichiarato, o valore mancante, o posizionale → stderr con **cosa** e **cosa si poteva** (P4), esce **2** (errore d'uso, distinto dall'1 con cui gli script segnalano un esito negativo); - tutto il resto invariato. **Argparse no.** Cambierebbe messaggi d'errore, codici d'uscita e il comportamento di `--help` su 18 script che il cron già invoca: romperebbe ciò che gira per riparare ciò che non gira mai. Qui serviva l'opposto — lasciare intatti i flag esistenti e rifiutare solo l'ignoto. ## 3. Il test guarda entrambe le metà del contratto `tests/test_cli_flag.py`, 30 test: - **l'elenco degli script si deriva dalla cartella** (P1): uno script nuovo che legge `sys.argv` a mano e non chiama `valida` fa fallire il test, non passa inosservato perché nessuno ha aggiornato una lista; - `valida` dev'essere la **prima istruzione** di `__main__` (uscire dopo l'effetto non è uscire); - l'uso deve **nominare** i flag che lo script accetta; - **i flag che il cron usa davvero devono restare accettati** (P15/P16, letti dai `cron_*.sh`): una guardia che ferma il libro di bordo la notte stessa sarebbe peggio del difetto; - end-to-end sui tre script che scrivono: `--help` esce 0 e **non tocca `trades.db`**; un flag ignoto esce 2 e non lo tocca (M15: il caso che ha causato il difetto, non un caso vicino). Verificato a mano anche il contrario: `monitor_health.py --quiet`, `trades_db.py --sync --quiet` e `book_execute.py` in dry-run escono 0 come prima. ## 4. Il resto della sessione **Indice USDE orario** (debito §5.15, primo passo). Il classificatore dei movimenti di capitale confronta due letture di equity a un'ora di distanza e il suo bound guarda solo BTC/ETH, mentre il 31% dell'equity è USDE: un depeg sarebbe scorporato come un prelievo. `usde_watch` registra l'indice una volta al giorno — troppo rado. Ora `balance_watch` (orario, sola lettura) lo registra a ogni campione, `None` con la ragione se non leggibile, mai 1,0. Il cablaggio nel bound viene quando la serie ha storia: prima serve il dato, poi la regola. **Pulizia lasciata dalla revisione.** `tests/helpers.carica_script` sostituisce la dodicesima copia del caricatore `importlib` (15 in giro, con nomi di modulo diversi per lo stesso file e differenze silenziose su `sys.modules`); il fill di prova si scrive con `upsert_fills` invece che con un `INSERT` a mano che lasciava `verified` NULL, una forma che la produzione non produce; le asserzioni sul testo del report non sono più ancorate al padding; `movimenti_capitale` accetta le righe già lette, così il report non fa due SELECT sulla stessa tabella a un'ora del cron — due letture ai due lati di una scrittura descriverebbero due istanti diversi. ## 5. Il README era fermo a quindici giorni prima del reset Chiesto un aggiornamento della documentazione, ho aperto il README e ho trovato un documento del **2026-06-04**. Il reset v2.0.0 è del **19 giugno**. Per 75 giorni la prima pagina del repository ha descritto la libreria pre-reset come se fosse il presente: | cosa diceva | stato vero | |---|---| | famiglie FADE / HONEST / PAIRS / TSMOM / SHAPE, strategie MR01…SH01 | archiviate in `Old/`, artefatto di feed contaminato | | PORT06: Sharpe **7,84 / 10,06**, DD 2,60%, CAGR ~79% | numeri che `CLAUDE.md` §2 elenca sotto «non citare» | | paper trader su `strategies.yml`, portafogli in `portfolios.yml` | **file inesistenti** | | `scripts/waste/`, `scripts/portfolios/`, `src/live/multi_runner.py` | **inesistenti** | | esecuzione shadow su Deribit **testnet** | il testnet è *la causa del reset*; oggi si esegue su mainnet con soldi veri | Riscritto contro lo stato vero: cosa gira adesso, i numeri nella lente di §2 (TWR +10,6%, non la crescita del conto), il metodo e i sei requisiti, la struttura verificata file per file, i gate con le loro date, l'obiettivo con la sua onestà. Ogni percorso citato è stato controllato: esiste. Da 423 righe a 152. **La lezione che ho registrato non è «aggiornare il README».** È che un reset invalida anche i documenti che nessuno rilegge, e l'inventario di cosa cita numeri morti va fatto il giorno del reset — non 75 giorni dopo, per caso, mentre si fa altro. ## 6. Cosa NON ho fatto - I loader `importlib` dei test sulla **ricerca** (moduli in `scripts/research/`) restano come sono: sono a livello di modulo, con radici diverse, e toccarli non ripara niente. - Il bound USDE nel classificatore: manca la storia, non il codice. - Non ho cercato altri documenti fermi al pre-reset fuori da `README.md` e `docs/`: l'inventario completo (ogni file che cita un numero morto) resta da fare, ed è la vera coda di questa scoperta.