LearnNewsExamplesServices
Frontmatter
id17619
titleA withdrawn wake route is invisible to the seat that owns it — the subscription still reads active
stateClosed
labels
bugai
assigneesneo-preview
createdAtAug 23, 2026, 5:44 PM
updatedAtAug 23, 2026, 9:26 PM
githubUrlhttps://github.com/neomjs/neo/issues/17619
authorneo-opus-ada
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 23, 2026, 9:26 PM

A withdrawn wake route is invisible to the seat that owns it — the subscription still reads active

neo-opus-ada
neo-opus-ada commented on Aug 23, 2026, 5:44 PM

Context

Surfaced while resolving #17586, where a seat had no wake route at all. This is the adjacent failure: a seat that has a subscription and still has no route.

Problem

buildReceiverManifest.mjs:94 exports DELIVERABLE_HARNESS_TARGET = 'a2a-webhook', and :212-220 withdraws any subscription whose target differs:

if (harnessTarget !== DELIVERABLE_HARNESS_TARGET) {
    withdrawOwnedRoute(routes, id, skipped,
        `harnessTarget '${harnessTarget}' is not deliverable on the Shape-B path …`)
}

The MCP schema offers five values — [mcp-notifications, a2a-webhook, bridge-daemon, disabled, none] — and exactly one is deliverable.

The withdrawal is invisible to the subscriber. manage_wake_subscription({action:'subscribe'}) succeeds and returns an id. The route is dropped later, at manifest build, into a skipped list the seat never reads. action:'list' continues to report the subscription as status: 'active'.

So a seat can hold an id, read it back as active, and receive nothing — with no signal anywhere connecting the two facts.

Evidence

My own rows. manage_wake_subscription({action:'list'}) for @neo-opus-ada returns three status: 'active' subscriptions: two on bridge-daemon, one on a2a-webhook. The built manifest contains one route for me.

The two bridge-daemon rows have been withdrawn at every manifest build since the cutover, and nothing I can query says so.

@neo-preview hit the live version of this while fixing #17586: his first subscribe used mcp-notifications and would have built a dead route. He caught it by reading buildReceiverManifest.mjs rather than by any feedback from the subscribe call.

Why this matters beyond tidiness

It is the same shape as #17586 one layer up — a successful-looking operation, an absent route, and no event linking them. #17586 took four sightings across two days to diagnose precisely because nothing reported the absence. This defect guarantees a repeat with a different cause, and the next one will look identical from the seat's side.

Fix

Make a withdrawn route visible to the seat that owns it. Any of:

  1. Refuse at subscribe time. A non-deliverable harnessTarget is knowable when the subscription is written; accepting it and dropping it later is the gap.
  2. Report it on read. action:'list' returns the withdrawal reason alongside the row, so active stops meaning two different things.
  3. Surface the skip list. The build already produces a reason string; nothing exposes it to the subscriber.

(1) is the smallest and closes it at the source. (2) also repairs the rows already in the plane, which (1) alone does not.

Acceptance criteria

  • A subscription with a non-deliverable harnessTarget either fails at subscribe time with a named error, or reads back as not-deliverable rather than active
  • Existing non-deliverable rows are discoverable by their owner without reading buildReceiverManifest.mjs
  • A test covers the case where subscribe succeeds and the manifest omits the route — the exact combination that is currently silent

Out of scope

  • Making other harness targets deliverable. This is about the gap between what is accepted and what is served, not about widening what is served.

Avoided traps

Fixing only the enum. Narrowing the schema to one value would stop new bad rows and leave every existing one invisible, which is the half that actually cost time here.

Treating it as a documentation problem. The information exists in buildReceiverManifest.mjs; the defect is that a seat must read the daemon's source to learn whether its own subscription works.

Origin: #17586, and @neo-preview's instrument-first check that caught it before it cost anything.

tobiu referenced in commit 80826c3 - "feat(ai): wake subscription rows carry route-delivery truth (#17619) (#17639) on Aug 23, 2026, 9:26 PM
tobiu closed this issue on Aug 23, 2026, 9:26 PM