usde_watch e fee_watch salvano lo stato prima dell'invio: un Telegram fallito non viene piu' ripetuto #29

Closed
opened 2026-09-27 13:12:13 +00:00 by Adriano · 3 comments
Owner

Revisione 2026-09-27 (goldrake): rilievo Opus 5.5, verifica avversariale fable. Sola lettura, nessun codice toccato.

Rilievo B2 [bug]

FILE: pg:scripts/live/usde_watch.py:287-320
COSA: il marcatore "gia' detto" di DEPEG_WARN / QUOTA_OVER / BLIND e' la condizione del record precedente, non l'esito di notify(): un invio fallito consuma la transizione (la lezione §5.2 applicata in cuscino_watch non e' applicata qui).
SCENARIO: giorno 1 indice 0.985 (DEPEG_WARN nuova), Telegram in errore -> notify False, ignorato; record scritto con px 0.985. Giorno 2 ancora 0.985: att_prev contiene DEPEG_WARN -> nessun invio. Il depeg resta non detto finche' non sparisce e ricompare. Idem QUOTA_OVER e BLIND. Il cron e' giornaliero: la perdita e' di 24h per tentativo.
PROVA: VERIFICATO: lettura — nessuno dei notify() alle righe 296-319 ha il valore di ritorno registrato; il record e' scritto a riga 288 prima degli invii; condizioni() dipende solo da px/quota/stato.
PROPOSTA: come cuscino_watch: scrivere il record DOPO gli invii con allertati=[...] effettivamente partiti, e in nuove sottrarre solo le condizioni del prev che risultano allertate.

Verifica fable B2 VERDETTO: CONFERMATO

GRAVITA': medio
PERCHE': scripts/live/usde_watch.py:288-289 scrive il record PRIMA degli invii; 296-319: nessun notify() ha il ritorno letto; condizioni() (166) dipende solo da px/quota/stato -> att_prev del giro dopo contiene la condizione anche se l'invio e' fallito. Il record non ha campo allertati.
CORREZIONE: ok (schema di cuscino_watch: record dopo gli invii con allertati, nuove = att_now - {c in att_prev se allertata}).

Rilievo B8 [bug]

FILE: pg:scripts/live/fee_watch.py:248-253
COSA: il cambio di fee viene consumato anche se Telegram fallisce: notify() ignorato, save_state() salva i nuovi valori subito dopo.
SCENARIO: Deribit porta il taker da 5 a 8 bps (livello NOTA), invio fallito -> il giro dopo prev == cur, changes vuoto, livello NOTA non allerta: il cambio non sara' mai detto. (AZIONE >10 bps invece si ripete.)
PROVA: VERIFICATO: lettura righe 248-253; stesso schema che §5.2 ha riparato in venue_watch/scale_watch/cuscino_watch.
PROPOSTA: ok = notify(...); salvare lo stato solo se ok (o se non c'erano cambi).

Verifica fable B8 VERDETTO: CONFERMATO

GRAVITA': medio
PERCHE': scripts/live/fee_watch.py:248-253: notify(...) senza lettura del ritorno, poi save_state(r["current"]) incondizionato -> un cambio NOTA con invio fallito non viene piu' detto (il giro dopo changes e' vuoto). AZIONE si ripete perche' level=="AZIONE" e' ricalcolato ogni giro.
CORREZIONE: ok.

Revisione 2026-09-27 (goldrake): rilievo Opus 5.5, verifica avversariale fable. Sola lettura, nessun codice toccato. ### Rilievo B2 [bug] FILE: pg:scripts/live/usde_watch.py:287-320 COSA: il marcatore "gia' detto" di DEPEG_WARN / QUOTA_OVER / BLIND e' la condizione del record precedente, non l'esito di notify(): un invio fallito consuma la transizione (la lezione §5.2 applicata in cuscino_watch non e' applicata qui). SCENARIO: giorno 1 indice 0.985 (DEPEG_WARN nuova), Telegram in errore -> notify False, ignorato; record scritto con px 0.985. Giorno 2 ancora 0.985: att_prev contiene DEPEG_WARN -> nessun invio. Il depeg resta non detto finche' non sparisce e ricompare. Idem QUOTA_OVER e BLIND. Il cron e' giornaliero: la perdita e' di 24h per tentativo. PROVA: VERIFICATO: lettura — nessuno dei notify() alle righe 296-319 ha il valore di ritorno registrato; il record e' scritto a riga 288 prima degli invii; condizioni() dipende solo da px/quota/stato. PROPOSTA: come cuscino_watch: scrivere il record DOPO gli invii con `allertati=[...]` effettivamente partiti, e in `nuove` sottrarre solo le condizioni del prev che risultano allertate. ### Verifica fable B2 VERDETTO: CONFERMATO GRAVITA': medio PERCHE': `scripts/live/usde_watch.py:288-289` scrive il record PRIMA degli invii; 296-319: nessun `notify()` ha il ritorno letto; `condizioni()` (166) dipende solo da px/quota/stato -> `att_prev` del giro dopo contiene la condizione anche se l'invio e' fallito. Il record non ha campo `allertati`. CORREZIONE: ok (schema di cuscino_watch: record dopo gli invii con `allertati`, `nuove = att_now - {c in att_prev se allertata}`). ### Rilievo B8 [bug] FILE: pg:scripts/live/fee_watch.py:248-253 COSA: il cambio di fee viene consumato anche se Telegram fallisce: notify() ignorato, save_state() salva i nuovi valori subito dopo. SCENARIO: Deribit porta il taker da 5 a 8 bps (livello NOTA), invio fallito -> il giro dopo prev == cur, changes vuoto, livello NOTA non allerta: il cambio non sara' mai detto. (AZIONE >10 bps invece si ripete.) PROVA: VERIFICATO: lettura righe 248-253; stesso schema che §5.2 ha riparato in venue_watch/scale_watch/cuscino_watch. PROPOSTA: `ok = notify(...)`; salvare lo stato solo se ok (o se non c'erano cambi). ### Verifica fable B8 VERDETTO: CONFERMATO GRAVITA': medio PERCHE': `scripts/live/fee_watch.py:248-253`: `notify(...)` senza lettura del ritorno, poi `save_state(r["current"])` incondizionato -> un cambio NOTA con invio fallito non viene piu' detto (il giro dopo `changes` e' vuoto). AZIONE si ripete perche' `level=="AZIONE"` e' ricalcolato ogni giro. CORREZIONE: ok.
Adriano added the bug label 2026-09-27 13:12:13 +00:00
Author
Owner

ANALISI (passo 1, Opus) — unita' U3, ramo lavoro/goldrake-u3, repo gitea:Adriano/PythagorasGoal
RIF: #26 (B1), #29 (B2, B8), #31 (B7), #35 (solo B3, B4)
FILE: scripts/live/usde_convert.py, scripts/live/usde_watch.py, scripts/live/fee_watch.py, src/live/venue_watch.py, scripts/live/venue_watch.py, tests/

  1. #26 — usde_convert: ordini limit GTC mai cancellati. Il gateway cerbero-mcp NON accetta time_in_force (PlaceOrderReq senza il campo, extra ignorati: gitea:Adriano/Cerbero-mcp#1), quindi la correzione e' tutta in PG:
    a) funzione cancella_residui(c) -> list[str]: legge gli ordini aperti sullo spot U.SPOT (USDE_USDC) e cancella SOLO quelli con label che inizia per "usde-quota-". Per sapere come chiedere gli ordini aperti di uno spot leggi (SOLA LETTURA) /opt/docker/cerbero-mcp/src/cerbero_mcp/exchanges/deribit/tools.py e client.py (get_open_orders: parametri accettati; cancel_order: {"order_id"}). Se la lettura fallisce -> solleva (non si ordina al buio).
    b) in main() con --esegui: chiamare cancella_residui PRIMA del ciclo (stampare quanti) e, nel ciclo, dopo ogni ordine con filled < amt cancellare quell'order_id (c._post("/mcp-deribit/tools/cancel_order", {"order_id": ...})), registrarlo nel record (cancellato: true/errore). Se la cancel fallisce: stampa, registra e FERMA il ciclo (break) — mai un secondo ordine con un residuo vivo.
    c) il record finale e l'exit code non cambiano significato.
  2. #29 — usde_watch.py (B2) e fee_watch.py (B8): lo stato si salva prima dell'invio e il ritorno di notify() non si legge. Leggi src/live/notifier.py per sapere cosa ritorna notify (bool? solleva?). Schema di cuscino_watch.py (leggilo: e' il modello): il record porta allertati = condizioni il cui invio e' riuscito; nuove = att_now - {c in att_prev se c in prev.get("allertati", att_prev)} — compatibilita': un record vecchio senza allertati vale come tutto allertato. fee_watch: save_state solo se l'invio (quando serviva) e' riuscito.
  3. #31 — venue_watch BLIND: severity resta None e il titolo diventa 🚨 "PRIMO PASSO: prelievo di prova". Dare a BLIND una severity propria "blind" con titolo "⚠️ venue_watch CIECO — referenze non leggibili, nessun giudizio sul venue" in scripts/live/venue_watch.py::_titolo. La ripetizione oraria di BLIND e' voluta (commento esistente): non toccarla.
  4. #35 B3/B4 — usde_watch: togliere DECISIONE_QUOTA_DAL / quota_da_decidere e la notify "la decisione di QUOTA e' dovuta" (la quota e' derivata dal cuscino dal 10/09, config usde._nota_cuscino); testo IDONEO: usare c["quota_max_frac"] invece di "50%" cablato; la riga "margine" non deve dire "conto SEGREGATO": il modello e' Cross X:SM dal 31/08 — riscrivere la riga come "margine: ~$X USDC + USDE scontato (cross X:SM)" usando i numeri che la funzione ha gia', senza inventarne.

TEST (tests/test_usde_u3.py ecc., client finto, nessuna rete, time.sleep patchato):

  • ordine con filled 0 -> cancel chiamata con quell'order_id, ciclo fermo; cancel che solleva -> break, registrato.
  • residuo "usde-quota-0.64" aperto all'avvio -> cancellato; ordine con altra label -> NON toccato.
  • usde_watch: notify fallito -> al giro dopo la stessa condizione si rinvia; notify riuscito -> non si ripete.
  • fee_watch: invio fallito -> stato non salvato.
  • venue_watch BLIND -> titolo senza "prelievo".
  • usde_watch non emette piu' QUOTA_DA_DECIDERE.
    Suite completa: cd <worktree> && /opt/docker/PythagorasGoal/.venv/bin/python -m pytest -q -p no:cacheprovider (baseline 1098 passed, 3 skipped).

NON TOCCARE: src/live/usde.py (formula del cuscino: e' #28, altra unita'), cuscino_watch.py (salvo leggerlo), config/live.json, /opt/docker/cerbero-mcp (sola lettura), /opt/docker/PythagorasGoal. Nessuna rete, nessun ordine, nessun Telegram (notify va mockato nei test).

ANALISI (passo 1, Opus) — unita' U3, ramo lavoro/goldrake-u3, repo gitea:Adriano/PythagorasGoal RIF: #26 (B1), #29 (B2, B8), #31 (B7), #35 (solo B3, B4) FILE: scripts/live/usde_convert.py, scripts/live/usde_watch.py, scripts/live/fee_watch.py, src/live/venue_watch.py, scripts/live/venue_watch.py, tests/ 1. #26 — usde_convert: ordini limit GTC mai cancellati. Il gateway cerbero-mcp NON accetta time_in_force (PlaceOrderReq senza il campo, extra ignorati: gitea:Adriano/Cerbero-mcp#1), quindi la correzione e' tutta in PG: a) funzione `cancella_residui(c) -> list[str]`: legge gli ordini aperti sullo spot U.SPOT (USDE_USDC) e cancella SOLO quelli con label che inizia per "usde-quota-". Per sapere come chiedere gli ordini aperti di uno spot leggi (SOLA LETTURA) /opt/docker/cerbero-mcp/src/cerbero_mcp/exchanges/deribit/tools.py e client.py (get_open_orders: parametri accettati; cancel_order: {"order_id"}). Se la lettura fallisce -> solleva (non si ordina al buio). b) in main() con --esegui: chiamare cancella_residui PRIMA del ciclo (stampare quanti) e, nel ciclo, dopo ogni ordine con filled < amt cancellare quell'order_id (`c._post("/mcp-deribit/tools/cancel_order", {"order_id": ...})`), registrarlo nel record (`cancellato: true/errore`). Se la cancel fallisce: stampa, registra e FERMA il ciclo (break) — mai un secondo ordine con un residuo vivo. c) il record finale e l'exit code non cambiano significato. 2. #29 — usde_watch.py (B2) e fee_watch.py (B8): lo stato si salva prima dell'invio e il ritorno di notify() non si legge. Leggi src/live/notifier.py per sapere cosa ritorna notify (bool? solleva?). Schema di cuscino_watch.py (leggilo: e' il modello): il record porta `allertati` = condizioni il cui invio e' riuscito; `nuove = att_now - {c in att_prev se c in prev.get("allertati", att_prev)}` — compatibilita': un record vecchio senza `allertati` vale come tutto allertato. fee_watch: save_state solo se l'invio (quando serviva) e' riuscito. 3. #31 — venue_watch BLIND: severity resta None e il titolo diventa 🚨 "PRIMO PASSO: prelievo di prova". Dare a BLIND una severity propria "blind" con titolo "⚠️ venue_watch CIECO — referenze non leggibili, nessun giudizio sul venue" in scripts/live/venue_watch.py::_titolo. La ripetizione oraria di BLIND e' voluta (commento esistente): non toccarla. 4. #35 B3/B4 — usde_watch: togliere DECISIONE_QUOTA_DAL / quota_da_decidere e la notify "la decisione di QUOTA e' dovuta" (la quota e' derivata dal cuscino dal 10/09, config usde._nota_cuscino); testo IDONEO: usare c["quota_max_frac"] invece di "50%" cablato; la riga "margine" non deve dire "conto SEGREGATO": il modello e' Cross X:SM dal 31/08 — riscrivere la riga come "margine: ~$X USDC + USDE scontato (cross X:SM)" usando i numeri che la funzione ha gia', senza inventarne. TEST (tests/test_usde_u3.py ecc., client finto, nessuna rete, time.sleep patchato): - ordine con filled 0 -> cancel chiamata con quell'order_id, ciclo fermo; cancel che solleva -> break, registrato. - residuo "usde-quota-0.64" aperto all'avvio -> cancellato; ordine con altra label -> NON toccato. - usde_watch: notify fallito -> al giro dopo la stessa condizione si rinvia; notify riuscito -> non si ripete. - fee_watch: invio fallito -> stato non salvato. - venue_watch BLIND -> titolo senza "prelievo". - usde_watch non emette piu' QUOTA_DA_DECIDERE. Suite completa: `cd <worktree> && /opt/docker/PythagorasGoal/.venv/bin/python -m pytest -q -p no:cacheprovider` (baseline 1098 passed, 3 skipped). NON TOCCARE: src/live/usde.py (formula del cuscino: e' #28, altra unita'), cuscino_watch.py (salvo leggerlo), config/live.json, /opt/docker/cerbero-mcp (sola lettura), /opt/docker/PythagorasGoal. Nessuna rete, nessun ordine, nessun Telegram (notify va mockato nei test).
Author
Owner

ESITO: fatto sul ramo, non in produzione
RIF: gitea:Adriano/PythagorasGoal#29
COSA: correzione su lavoro/goldrake (pushato), analisi Opus, codice Sonnet, controllo finale Opus
FILE: commit 4725839 dda5d41
PROVA: /home/adriano/lavoro/PythagorasGoal pytest -q → 1166 passed, 3 skipped
MANCA: merge su main — richiede ok esplicito di Adriano (libro vivo). Chiusura con --soluzione dopo il merge.
PROSSIMO: ok di Adriano → merge lavoro/goldrake su main → git pull in /opt/docker/PythagorasGoal

ESITO: fatto sul ramo, non in produzione RIF: gitea:Adriano/PythagorasGoal#29 COSA: correzione su lavoro/goldrake (pushato), analisi Opus, codice Sonnet, controllo finale Opus FILE: commit 4725839 dda5d41 PROVA: /home/adriano/lavoro/PythagorasGoal pytest -q → 1166 passed, 3 skipped MANCA: merge su main — richiede ok esplicito di Adriano (libro vivo). Chiusura con --soluzione dopo il merge. PROSSIMO: ok di Adriano → merge lavoro/goldrake su main → git pull in /opt/docker/PythagorasGoal
Adriano added the attesa:adriano label 2026-09-27 14:17:41 +00:00
Author
Owner

Soluzione

usde_watch: record 'allertati' scritto dopo gli invii; fee_watch: save_state solo se l'invio e' riuscito.
COMMIT: 4725839 dda5d41, su main dal 27/09/2026 (merge con ok di Adriano). Produzione aggiornata.

**Soluzione** usde_watch: record 'allertati' scritto dopo gli invii; fee_watch: save_state solo se l'invio e' riuscito. COMMIT: 4725839 dda5d41, su main dal 27/09/2026 (merge con ok di Adriano). Produzione aggiornata.
Adriano removed the attesa:adriano label 2026-09-27 14:27:59 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Adriano/PythagorasGoal#29