Files
PythagorasGoal/docs/diary/2026-09-02c-flag-e-pulizia.md
Adriano Dal Pastro 95424f0755 docs: il README era fermo a 15 giorni PRIMA del reset — riscritto contro lo stato vero
Ultimo commit del README: 2026-06-04. Reset v2.0.0: 2026-06-19. Per 75 giorni la prima pagina
del repo ha pubblicato la libreria pre-reset (FADE/HONEST/PAIRS/TSMOM/SHAPE, PORT01-06) con
Sharpe 7,84/10,06 e CAGR ~79% come risultati correnti — cioe' esattamente i numeri che §2
elenca sotto "non citare", dalla libreria che il reset aveva dichiarato artefatto. Meta' dei
file citati non esiste piu' (strategies.yml, portfolios.yml, scripts/waste, scripts/portfolios,
src/live/multi_runner.py), e l'esecuzione descritta era su TESTNET, che e' la causa del reset.

- README riscritto (423 -> 152 righe): cosa gira adesso (TP01+SKH01 75/25, ~$2.050, cadenza
  oraria :47), i numeri nella lente di §2 (TWR +10,6%, non la crescita del conto), la riga che
  ordina il piano, il metodo e i suoi sei requisiti, il dato, la struttura VERIFICATA file per
  file, i comandi, i gate con le loro date, l'obiettivo con la sua onesta'.
- CLAUDE.md §0 e memoria 40: registrato il difetto e la lezione — un reset invalida anche i
  documenti che nessuno rilegge; l'inventario di cosa cita numeri morti va fatto il giorno del
  reset, non 75 giorni dopo per caso.
- Diario 02/09c: sezione col confronto riga per riga; coda dichiarata (l'inventario completo
  degli altri documenti pre-reset non e' stato fatto).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XDJsH3iDSaBns3ccpPBwiu
2026-09-02 15:53:42 +00:00

5.8 KiB

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ì:

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.