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:
- Refuse at subscribe time. A non-deliverable
harnessTarget is knowable when the subscription is written; accepting it and dropping it later is the gap.
- Report it on read.
action:'list' returns the withdrawal reason alongside the row, so active stops meaning two different things.
- 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
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.
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:94exportsDELIVERABLE_HARNESS_TARGET = 'a2a-webhook', and:212-220withdraws 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 askippedlist the seat never reads.action:'list'continues to report the subscription asstatus: '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-adareturns threestatus: 'active'subscriptions: two onbridge-daemon, one ona2a-webhook. The built manifest contains one route for me.The two
bridge-daemonrows have been withdrawn at every manifest build since the cutover, and nothing I can query says so.@neo-previewhit the live version of this while fixing #17586: his first subscribe usedmcp-notificationsand would have built a dead route. He caught it by readingbuildReceiverManifest.mjsrather 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:
harnessTargetis knowable when the subscription is written; accepting it and dropping it later is the gap.action:'list'returns the withdrawal reason alongside the row, soactivestops meaning two different things.(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
harnessTargeteither fails at subscribe time with a named error, or reads back as not-deliverable rather thanactivebuildReceiverManifest.mjsOut of scope
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.