fix(scheduler): non allertare l'owner su wake non consegnato se l'agente è vivo - #1010
Open
ziomik wants to merge 1 commit into
Open
fix(scheduler): non allertare l'owner su wake non consegnato se l'agente è vivo#1010ziomik wants to merge 1 commit into
ziomik wants to merge 1 commit into
Conversation
Un wake schedulato senza ricevuta di consegna paga l'owner con
"FIRED BUT UNDELIVERED" anche quando l'agente e' palesemente vivo e sta
solo elaborando: il wake persistito viene poi rigiocato da solo, quindi
l'alert e' rumore.
_record_schedule_undelivered ora sopprime il SOLO alert owner quando
l'agente ha scritto un heartbeat di origine agente negli ultimi 120s.
Log, activity e persistenza durevole del wake restano invariati, e il
timeout di consegna (600s) non viene toccato: un agente davvero morto
paga l'owner come prima.
Fonte dati: get_latest_agent_heartbeat (non get_latest_heartbeat), che
esclude le righe sintetiche server_presence scritte dallo scheduler
stesso — altrimenti il modo di fallire tipico ("transport CONNECTED ma
reader loop bloccato su una chiamata LLM") userebbe come prova di vita
una riga scritta dal daemon, nascondendo un crash reale. Fail-closed su
riga assente, status non agent-authored o errore di lettura.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problema
Quando un wake schedulato non ottiene la ricevuta di consegna entro il timeout,
_record_schedule_undeliveredpaga l'owner con🚨 FIRED BUT UNDELIVERED— anche quando l'agente è palesemente vivo e sta solo elaborando (turno lungo, chiamata LLM in corso). In quel caso il wake è già stato persistito e viene rigiocato da solo alla sessione successiva: l'alert è puro rumore per l'owner.Fix
In
_record_schedule_undelivered, prima di_queue_owner_alert, si controlla se l'agente ha dato segni di vita negli ultimi 120s. Se sì, si sopprime solo l'alert owner.Restano invariati:
FIRED BUT UNDELIVEREDsu stderr (la diagnostica non si perde);schedule_undelivered;Un agente davvero morto continua a pagare l'owner esattamente come prima.
Scelta della fonte dati (deviazione motivata rispetto al suggerimento iniziale)
Il suggerimento era di usare la stessa fonte di
_reconcile_server_liveness/_check_heartbeats, cioèget_latest_heartbeat()+agent.last_seen_at. Ho usato inveceregistry.get_latest_agent_heartbeat(), per due ragioni:get_latest_heartbeat()include le righe sintetichemetadata.source='server_presence'che lo scheduler scrive da sé quando vede il transportCONNECTED. Ma il modo di fallire tipico di "FIRED BUT UNDELIVERED" è proprio "transport CONNECTED ma reader loop bloccato su una chiamata LLM": userei come prova di vita una riga scritta dal daemon stesso e nasconderei il crash. È esattamente la distinzione documentata nel docstring diget_latest_agent_heartbeat(review Murzik di feat(api): /admin/force-restart-agent/{name} for wedged agents (#103) #573, endpoint force-restart feat: Replace HEARTBEAT_OK text with send_heartbeat() MCP tool for agent health monitoring #103).last_seen_atè stampato su consegna inbound riuscita (broker.py:1738), non su risposta dell'agente. Usarlo sarebbe circolare: la consegna del wake stessa potrebbe averlo appena aggiornato, sopprimendo ogni alert.get_latest_agent_heartbeatapplica due tagli — escludeserver_presenceed escludestale/dead— cioè restituisce esattamente "l'agente ha detto lui di essere vivo". È già la convenzione del repo per la domanda "l'agente è davvero responsivo?". Il controllo aggiuntivo su_PROVEN_LIVE_HEARTBEAT_STATUSES(alive/ok/busy/finishing) e il fail-closed su riga assente o errore di lettura completano la garanzia: in dubbio, l'alert parte.Test (TDD)
Tre nuovi test in
tests/test_scheduler.py:test_undelivered_skips_owner_alert_when_agent_proved_live— heartbeatbusyrecente → nessun alert, ma il wake resta persistito e replayabile. Scritto per primo, verificato rosso prima del fix.test_undelivered_alerts_when_only_server_presence_is_fresh— guardia: una rigaserver_presencefresca non sopprime l'alert.test_undelivered_alerts_when_agent_heartbeat_is_stale— guardia: heartbeat agent-origin di un'ora fa → alert regolare.Suite:
tests/test_scheduler.py132 passed;test_daemon.py/test_api.pyfiltrati su schedule/undelivered verdi;ruff checkpulito.🤖 Opened by Engineer