Skip to content

notifications: fenced session runtime silently blackholes Telegram->session inbound while daemon ACKs #4528

Description

@Yeachan-Heo

Symptom

User sends a message in a session's Telegram topic. The daemon consumes the update (seen-updates advances), sets the QUEUED reaction (user sees an ACK), forwards user_message over the session ws — and the message never reaches the session. No log line anywhere.

Reproduced live (2026-08-14, ~10:05 KST)

  • Daemon healthy, freshly attached to the session's current endpoint (ws://127.0.0.1:52715, pid 59092), same endpoint the broker index advertises (live: true, mtime strict-equal).
  • Direct probe: connected to that endpoint with SdkClient.connect(url, token) and sent a well-formed user_message frame — accepted at the socket, silently discarded by the host. No sendUserMessage failed warn, no drop diagnostic.
  • The host runtime also stopped publishing outbound (turn receipts frozen), while its endpoint registration was never rotated or marked stale, and daemon-restart-triggered reconciliation never replaced it.

Root cause surfaces (src/sdk/bus/index.ts server.onInbound)

Two unconditionally silent drop gates:

  1. if (initializedRuntime.inboundFenced) return;inboundFenced is set during identity rotation / predecessor-terminal paths and is never reset; a fenced predecessor keeps its native server listening and its broker endpoint advertised, so the daemon keeps delivering into a blackhole indefinitely.
  2. if (runtime?.policySuspended && notificationOrigin) { …defer control_command…; return; } — swallows user_message/reply/config_command while policy is provisional; session-control.ts has exits that leave a runtime provisional forever (e.g. reconcile attempt exhaustion at the tail of #reconcile).

Compounding: the daemon flips the Telegram QUEUED reaction immediately after transport.send, before any session-side acceptance, so the user gets a positive ACK for a dropped message.

Fixed so far

PR #4526 (11e98cf6ce) adds bounded warn diagnostics at both drop gates. Not fixed (needs design):

  • successor lifecycle: a fenced runtime must either rotate its endpoint registration out of the broker index or be replaced so reconciliation can converge;
  • daemon ACK should reflect session acceptance, not socket write;
  • #reconcile must not exit leaving policySuspended = true on a live runtime.

Related: #4527 (silent reconcile non-convergence), PR #4526 (registry brick).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions