fix(connector): recover dropped channel wakes without polling#243
Open
davidfarah2003 wants to merge 1 commit into
Open
fix(connector): recover dropped channel wakes without polling#243davidfarah2003 wants to merge 1 commit into
davidfarah2003 wants to merge 1 commit into
Conversation
A Claude channel nudge is fire-and-forget: written to the transport, never acknowledged, and silently dropped when the host's channel handler is not yet registered (the boot window) or the session is not admitted. A dropped wake left an idle agent with pending inbox work and no future event — the observed zombie: unacked durable messages redelivered every ack_wait and were swallowed by the pending-duplicate dedup in MeshAgent.ingest. Two event-driven repairs, no timer: - MeshAgent.ingest: a durable duplicate of a still-pending item now refreshes the ack handle AND re-emits the existing item through the ordinary incoming policy path, turning JetStream redelivery into the retry for a lost wake. A live duplicate still dedups silently; quiet ambient stays pull-only and non-waking; host in-flight guards (busy/unconfirmed/working) still apply. - claude connector: reconcile once after the channel capability gate opens — if work buffered while the mesh connected in parallel with the MCP handshake, send one best-effort nudge. Residual, documented in connect-claude.md: live-only traffic has no durable retry, and no zero-gap proof exists without an upstream handler-ready or enqueue acknowledgement from the host. Covered in cross-path-dedup.smoke.ts: durable redelivery reannounces, live duplicates stay silent, fresh durable ack retained, quiet remains pull-only.
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.
Problem
A Claude channel nudge is fire-and-forget:
awaitresolves when it is written to the transport, it is never acknowledged, and it is silently dropped when the host's channel handler is not yet registered (the ~1.4s boot window) or the session is not admitted. A dropped wake left an idle agent with pending inbox work and no future event to surface it — the observed zombie: unacked durable messages were redelivered by JetStream everyack_wait, and each redelivery was swallowed by the pending-duplicate dedup inMeshAgent.ingest.Fix — event-driven, no timer
MeshAgent.ingest: a durable duplicate of a still-pending item now refreshes the ack handle and re-emits the existing item through the ordinaryincomingpolicy path. JetStream redelivery becomes the retry for a lost wake — broker-driven, coupled to "work is still unacked", bounded byack_wait. A live duplicate still dedups silently; no second inbox row is ever created.Policy is preserved end to end: quiet ambient stays pull-only and non-waking, dnd/focus and muted are unchanged, and each host's in-flight guard (OpenCode
busy, Pi unconfirmed batch, HermesawaitingId, Claude's working-gate) prevents double-drives.Explicitly not in this change
setIntervalreconciler — redelivery replaces it with an event that already exists.Residual (documented in
connect-claude.md): live-only traffic has no durable copy, hence no broker retry; a zero-gap guarantee needs an upstream handler-ready/enqueue acknowledgement from the host.Verification
cross-path-dedup.smoke.ts: 52/52 — new cases for durable redelivery reannounce (live→durable and durable→durable), live-duplicate silence, freshest-ack retention, quiet remaining pull-only/non-waking.pnpm typecheckgreen across all packages; docs bundle regenerated and consistent.