Composed-server brokered poll-digest for the browser wake consumer
Context
#17130 leg 2 (the cockpit's store-bound wake rendering) surfaced a topology fact at build time: the browser consumer's pollDigest seam — the catch-up truth lane the frozen slice-2/slice-3 wire names ("poll-digest {subscriptionId, sinceLogId} fires once per connection") — has no reachable implementation in the direct-browser topology. The seam exists, the consumer honors it, the cockpit passes it through (wakePollDigest), and nothing in the deployed browser path can supply it.
The Problem
Verified this session (V-B-A, all read-only):
manage_wake_subscription {action: 'poll-digest'} is an authenticated MC-plane call — WakeSubscriptionService.pollDigest throws unboundIdentityError without a bound caller (ai/services/memory-core/WakeSubscriptionService.mjs:1594).
- The browser page holds no plane credential by design: both mints live in the registry bridge's closures (
apps/agentos/fleet/installFleetBridge.mjs — Option-D custody), so the cockpit cannot build an MC-authenticated poll itself without breaking custody.
- The composed fleet server exposes
/wake, /fleet/probe, /fleet/events, POST /fleet (ai/services/fleet/fleetServer.mjs) — no viewer-facing digest-poll surface, and the wire-verb twin lists (fleetWireMethods.mjs) carry no digest verb.
- The relay topology is fine:
devFleetServer.mjs:168 wires pollDigest through its proven plane client. Only the browser half is unreachable.
Consequence: a cold-started or reconnecting browser viewer receives new pushes but cannot drain pending wakes — #17130's "cold start drains pending wakes from the vouched handshake id alone" AC is client-unreachable until a server surface exists. The client side ships honest absence (the telltale renders catch-up: no observation), which is correct and insufficient.
The Architectural Reality
The composed server already brokers viewer-credentialed MC calls: connect-time arming (fleetServer.mjs /fleet/events handler) takes the viewer's class-3 mint from x-neo-mc-authorization, builds an in-flight MC client with the viewer's own authority, and never persists the credential. Poll-digest is the SAME credential class and the same in-flight lifetime — the pattern exists, only the second consumer of it is missing.
The Fix
- Server: a sibling endpoint on the events origin — e.g.
POST /fleet/events/digest — taking exactly the stream's two headers (class-1 admission on Authorization, class-3 on x-neo-mc-authorization), running manage_wake_subscription {action: 'poll-digest', subscriptionId, sinceLogId} through the same in-flight viewer-credentialed context the arming path builds, and returning the digest result as a wire envelope. Byte-identical pairs refused exactly like arming. No change to any existing frame or verb — additive sibling, wire twins untouched.
- Client:
openWakeStream (the bridge capability) gains an internal default pollDigest built from the SAME pinned fetchImpl + header closure it already owns — zero cockpit change (FleetCockpit.wakePollDigest stays the test-injection override; the capability default only engages when no explicit seam is supplied). The consumer's existing catch-up mechanics (fleetWakeStreamConsumer.mjs — cold drain from the vouched id, watermark echo, fresh ≠ empty ≠ failed) light up unchanged.
- Evidence: extend the
FleetCockpitViewerWakeNL e2e (shipped in #17130 leg 2 with the production fan-out fixture) with the digest-poll leg — the fixture answers the sibling endpoint, and the cold-drain journey closes end-to-end in the page.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
POST /fleet/events/digest (new) |
ai/services/fleet/fleetServer.mjs (sibling of /fleet/events) |
viewer-credentialed MC poll-digest, brokered in-flight |
absent class-3 header → honest refusal envelope (not-armed vocabulary) |
endpoint JSDoc + #16741-family notes |
new unit + e2e digest leg |
openWakeStream capability default pollDigest |
apps/agentos/fleet/installFleetBridge.mjs |
closure-built default against the sibling endpoint; explicit observational pollDigest option still overrides |
no endpoint (older server) → the consumer's honest failed catch-up observation carrying the endpoint-absent reason (per amended AC 4) |
capability JSDoc |
installFleetBridge.spec.mjs extension |
Decision Record impact
aligned-with the FM client topology ADR (remote-only journey; custodian shapes) — the same record #17130 builds against. Additive to the frozen slice-2/slice-3 wire: no existing frame, header, or verb changes.
Acceptance Criteria
Out of Scope
- Relay-side catch-up (
devFleetServer — already wired through the plane client).
- Wake delivery over the ingress for host-listener-less clients (
#16741).
- Any change to the SSE frame grammar or the wire-verb twin lists.
Avoided Traps
- A wire verb on
POST /fleet: would extend the class-3 credential surface onto the general wire POST and mutate both frozen verb twins; the events-origin sibling keeps the push lane's credential shape exactly where it already lives.
- Page-side MC client: breaks Option-D custody (mints would need to reach the page realm) — rejected outright.
- Server-side drain-on-connect (pushing pending as wake frames at arming): duplicates derive-at-read into the push lane and inverts "push is latency, poll is truth".
Related
#17130 (the client half + the seam this closes) · #16742 (C1 custody) · #16741 (ingress delivery, different clients) · PR #17194 (leg 1 consumer) · epic #16168.
Live latest-open sweep: checked latest 20 open issues at 2026-08-16T20:19Z, no equivalent; A2A in-flight claim sweep (last hour, all read-states) clean — active claims are npmignore/who_is_online/theme lanes, no overlap.
Origin Session ID: 71baabc5-3ebe-46ff-99ce-a301e78cb7c5
Retrieval Hint: query_raw_memories("browser poll-digest brokered composed server viewer credential events sibling endpoint")
Composed-server brokered poll-digest for the browser wake consumer
Context
#17130leg 2 (the cockpit's store-bound wake rendering) surfaced a topology fact at build time: the browser consumer'spollDigestseam — the catch-up truth lane the frozen slice-2/slice-3 wire names ("poll-digest {subscriptionId, sinceLogId}fires once per connection") — has no reachable implementation in the direct-browser topology. The seam exists, the consumer honors it, the cockpit passes it through (wakePollDigest), and nothing in the deployed browser path can supply it.The Problem
Verified this session (V-B-A, all read-only):
manage_wake_subscription {action: 'poll-digest'}is an authenticated MC-plane call —WakeSubscriptionService.pollDigestthrowsunboundIdentityErrorwithout a bound caller (ai/services/memory-core/WakeSubscriptionService.mjs:1594).apps/agentos/fleet/installFleetBridge.mjs— Option-D custody), so the cockpit cannot build an MC-authenticated poll itself without breaking custody./wake,/fleet/probe,/fleet/events,POST /fleet(ai/services/fleet/fleetServer.mjs) — no viewer-facing digest-poll surface, and the wire-verb twin lists (fleetWireMethods.mjs) carry no digest verb.devFleetServer.mjs:168wirespollDigestthrough its proven plane client. Only the browser half is unreachable.Consequence: a cold-started or reconnecting browser viewer receives new pushes but cannot drain pending wakes —
#17130's "cold start drains pending wakes from the vouched handshake id alone" AC is client-unreachable until a server surface exists. The client side ships honest absence (the telltale renderscatch-up: no observation), which is correct and insufficient.The Architectural Reality
The composed server already brokers viewer-credentialed MC calls: connect-time arming (
fleetServer.mjs/fleet/eventshandler) takes the viewer's class-3 mint fromx-neo-mc-authorization, builds an in-flight MC client with the viewer's own authority, and never persists the credential. Poll-digest is the SAME credential class and the same in-flight lifetime — the pattern exists, only the second consumer of it is missing.The Fix
POST /fleet/events/digest— taking exactly the stream's two headers (class-1 admission onAuthorization, class-3 onx-neo-mc-authorization), runningmanage_wake_subscription {action: 'poll-digest', subscriptionId, sinceLogId}through the same in-flight viewer-credentialed context the arming path builds, and returning the digest result as a wire envelope. Byte-identical pairs refused exactly like arming. No change to any existing frame or verb — additive sibling, wire twins untouched.openWakeStream(the bridge capability) gains an internal defaultpollDigestbuilt from the SAME pinnedfetchImpl+ header closure it already owns — zero cockpit change (FleetCockpit.wakePollDigeststays the test-injection override; the capability default only engages when no explicit seam is supplied). The consumer's existing catch-up mechanics (fleetWakeStreamConsumer.mjs— cold drain from the vouched id, watermark echo,fresh ≠ empty ≠ failed) light up unchanged.FleetCockpitViewerWakeNLe2e (shipped in#17130leg 2 with the production fan-out fixture) with the digest-poll leg — the fixture answers the sibling endpoint, and the cold-drain journey closes end-to-end in the page.Contract Ledger
POST /fleet/events/digest(new)ai/services/fleet/fleetServer.mjs(sibling of/fleet/events)#16741-family notesopenWakeStreamcapability defaultpollDigestapps/agentos/fleet/installFleetBridge.mjspollDigestoption still overridesfailedcatch-up observation carrying the endpoint-absent reason (per amended AC 4)installFleetBridge.spec.mjsextensionDecision Record impact
aligned-with the FM client topology ADR (remote-only journey; custodian shapes) — the same record
#17130builds against. Additive to the frozen slice-2/slice-3 wire: no existing frame, header, or verb changes.Acceptance Criteria
failedcatch-up observation carrying the endpoint-absent reason — once per connection, bounded, no retry storm, never a fabricated drain. (Amended 2026-08-16 pre-PR:failed-with-reason is the truthful observation — a poll WAS attempted and refused; rendering that as absence would hide a real signal. The absence state stays reserved for genuinely unwired seams.)#17130's residual cold-drain AC clause is closed by reference from this ticket.Out of Scope
devFleetServer— already wired through the plane client).#16741).Avoided Traps
POST /fleet: would extend the class-3 credential surface onto the general wire POST and mutate both frozen verb twins; the events-origin sibling keeps the push lane's credential shape exactly where it already lives.Related
#17130(the client half + the seam this closes) ·#16742(C1 custody) ·#16741(ingress delivery, different clients) · PR#17194(leg 1 consumer) · epic#16168.Live latest-open sweep: checked latest 20 open issues at 2026-08-16T20:19Z, no equivalent; A2A in-flight claim sweep (last hour, all read-states) clean — active claims are npmignore/who_is_online/theme lanes, no overlap.
Origin Session ID: 71baabc5-3ebe-46ff-99ce-a301e78cb7c5
Retrieval Hint:
query_raw_memories("browser poll-digest brokered composed server viewer credential events sibling endpoint")