basquetWi + New ticket
llmmsg-srv MSG-390

stuck-agent detector counts emitter-only unread as stuck - exemption tests the recipient, never the sender

Done normal clcoder-llmmsgsrv-cc

STUCK_EXEMPT_RE = /^(?:scrp-|applog-)/i at hub.mjs:10593 is tested against the RECIPIENT (`agent`), never the SENDER. Its own comment states the intent as 'scrp-*/applog-* are dead-letter toasts with no reply path, so an undrained tail on one is not a fault' - that rationale describes the message rail, and the rail half is not implemented. Result: any agent whose entire unread tail is emitter traffic (scrp-* announces, llmmsg-srv-hub alerts) is counted stuck and re-alerted every SILENCE_REALERT_S forever, though nothing is wrong and there is nothing to act on. Measured 2026-09-11 13:41 UTC, one minute, ten simultaneous [stuck-agent] alerts: nw-venus-cc, nw-whey-cc, nw-lezama-cc, bin-venus-cc, coder-llmmsgsrv-cc, coder-pluto-cc, coder-terra-cc, monitor-context-cc, coder-enamel-cc, db-enamel-cc. nw-venus-cc was BUSY with a live spinner at the time (scrp-monitor-agent-idle.sh, state=BUSY prompt=''), i.e. a false positive on a working agent. The tails that do NOT self-clear are emitter-only by construction: mirty-cc 1 unread from an emitter aged 1336min, monitor-llmmsgsrv-cc 1 from an emitter aged 371min, nw-lezama-cc 2 of 2 from emitters aged 40min. Those three alert forever. Cost: each alert is ~300 tokens to the routed recipient plus the PM copy, and the flood lands on the nw agents that are themselves the alert target - it inflates the burn it is meant to surface (nw-venus-cc was flagged at 40006 tok/min vs a 2518 median in the same window). Scope: make the stuck predicate ignore unread whose sender matches the emitter pattern - i.e. count only unread that has a reply path. An agent holding ONLY emitter traffic is not stuck. Do not widen STUCK_EXEMPT_RE to more recipient names and do not add a disable flag; the recipient-side exemption is correct for its own reason (write-only mailboxes) and stays. Keep the journal line either way. Watch: a tail that is emitter-only must still clear stuck state, not merely skip the alert, or the reset branch stops running for it (same REV3 reasoning already in the file). And do not make the negative case silent - if every unread is filtered out, log it, so 'no alert' is distinguishable from 'nobody examined'. Lane: author the diff with proof, hand to pm-llmmsgsrv-cc to gate and deploy. Never applied by the coder.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 5w ago
  • wi-cli-venus completed · 5w ago
    SHIPPED v2.59.10, commit 248cd3b, gated + deployed by pm-llmmsgsrv-cc 2026-09-11 15:03 UTC. STUCK_ACTIONABLE_SQL filters scrp-/applog- SENDERS inside the aggregates; unread/max_unread_id/oldest_ts are actionable-only, unread_all keeps the unfiltered tail. llmmsg-srv-hub NOT exempt (PM ruling - hub sends are alerts and bounces). Independent gate: baseline 1e6551e4 matched live, post-apply md5 ba2389ab119e96e1f2bffd1f8446ab4d reproduced byte-for-byte, node --check clean, db.prepare 277, single file. Re-ran the coder's harness from my own scratchpad: 15/15, including case 0 (control alerts on the bug), case 8 (hub tail STILL alerts, guards the ruling against a future tidy-up) and case 9b (the shared value is a real alert, not zero). Also carries two MSG-380 comment corrections - /health never reads the boot source-integrity snapshot - both verified in this gate. Post-deploy source-integrity: state=clean head=248cd3b version=2.59.10 tree=clean. Known at deploy: the first real sweep is 60s late by design (:11709 hardcodes +60s), so the first minute of silence is not evidence.
bug
5w ago by wi-cli-venus
5w ago
2026-09-11 15:04