Context
Slice 2 of #16741 (S7, epic #16168), per the on-ticket reshaped fork (author comment 2026-08-09T14:45Z, unchallenged since): push for latency, poll for truth. Slice 1 (#16800, PR #16796) shipped the truth half — poll-digest derives the caller's digest at read time. This slice builds the latency half: the wake daemon pushes to the composed fleet-server (a webhook target with a stable in-composition service-DNS name — no host bridging, no port drift), and the fleet-server fans out to connected cockpits over the authenticated ingress via SSE.
Producer correction (source-verified at intake, 2026-08-14): the signed dispatcher is WebhookDeliveryService.deliver (ai/services/memory-core/WebhookDeliveryService.mjs — HMAC-SHA256 over the exact body, the four X-Neo-Wake-* headers receiver.mjs verifies, refuses unsigned delivery, full backoff/degrade/resume machinery). It is URL-generic via harnessTargetMetadata.url, so a service-DNS target rides it unchanged — zero dispatcher changes. The daemon's deliverViaWebhookUrl (daemon.mjs:2795) is the UNSIGNED legacy channel and is NOT this slice's producer.
Key custody (source-verified): subscribe returns the minted server-issued signingKey to the caller (WakeSubscriptionService.mjs:1143) and rotate-key re-mints (:1302). The fleet-server self-arms at boot per subscription: ensure → rotate-key → hold the key in process memory only (process-bearer custody class; restart = rotation). No deployment secret.
Fan-out shape: per-viewer relay subscriptions — each authenticated SSE connect ensures a wake subscription for THAT identity targeting the fleet-server's /wake; an incoming digest routes ONLY to streams authenticated as its subscription's identity. No cross-identity fan-out; the content-grant separation holds by construction. The delegate pattern (fleet-server's plane credential + explicit target identity) follows the shipped relay precedent (planeMailboxClient); if an MC-side permission gate bites, it surfaces in this slice's PR as its own finding.
The Fix
POST /wake on fleetServer.mjs (427 lines; exact-route siblings GET /fleet/probe:318, POST /fleet:330) — the class-6 signed-wake receiver: HMAC verification per the subscription secret (ADR 0038 §2.5.1 row 6 — wake HMAC carries ZERO read/write authority), then fan-out + last-received bookkeeping (observational). Compose-internal only: no ingress exposure for /wake (the daemon reaches it via service DNS).
- SSE endpoint (e.g.
GET /fleet/events) behind fleetIngressAuth admission — one EventSource per cockpit, server fan-out on the existing trust boundary. Ingress-exposed (Caddy passes SSE natively); add the exact route beside /fleet + /fleet/probe in ai/deploy/Caddyfile (+ local-agent-os variant, both arms).
- Service-DNS wake subscription — provisioning/seeding for the fleet-server's own subscription (target
http://fleet-server:8083/wake), route class distinct from host-listener routes.
- Honest-degraded is an AC, not an aftermath (v1.1 fold): the SSE channel's death must render as absence-with-reason on the client contract — this slice defines the event/error vocabulary the slice-3 consumer renders.
Contract Ledger
| Surface |
Today |
After |
Consumers |
V-B-A anchor |
POST /wake (fleet-server, compose-internal) |
absent |
HMAC-verified wake receiver (mirrors receiver.mjs contract; imports verifyWakeSignature) |
MC WebhookDeliveryService (signed Shape-B dispatcher, unchanged) |
WebhookDeliveryService.mjs:125-146 signs + sends the four verified headers |
| SSE endpoint (ingress-exposed) |
absent |
authenticated event stream, fan-out of received wake digests |
slice-3 cockpit consumer |
fleetIngressAuth.mjs (123 lines, admission precedent) |
| Wake subscriptions (service-DNS target, per viewer identity) |
host-listener targets only |
+ per-viewer relay subscriptions, self-armed at SSE connect; keys held in fleet-server process memory (boot rotate-key) |
MC dispatch (CoalescingEngineService → WebhookDeliveryService) |
WakeSubscriptionService.mjs:1070/:1143 subscribe returns key; :1302 rotate-key |
ai/deploy/Caddyfile* |
/fleet + /fleet/probe exact routes |
+ SSE exact route (NOT /wake) |
ingress |
Caddyfile:57-60 handle_path prohibition note |
| Credential surface |
— |
NONE added — HMAC = existing class 6; SSE rides existing admission |
— |
ADR 0038 §2.5.1 non-alias rule |
Acceptance Criteria
Out of Scope
- The cockpit consumer + delivery-axis wiring (slice 3), pull-route telemetry (slice 4), any daemon changes, any new credential class.
Related
Parent: #16741 (S7) · sibling slice 1: #16800 (merged, PR #16796) · epic #16168 · ADR 0038 §2.5.1 row 6 + §2.8 remote-only journey AC · design authority: #16741 comments (Iris Design v1/v1.1 + author falsification pass + reshaped fork).
Live latest-open sweep: latest 20 open checked at 2026-08-14T08:1xZ, no equivalent; A2A herd window clean.
Origin Session ID: c4996813-01b9-4234-8bdd-ed3bf22c0970
Retrieval Hint: query_raw_memories("fleet-server wake receiver SSE fan-out service-DNS slice 2")
Context
Slice 2 of #16741 (S7, epic #16168), per the on-ticket reshaped fork (author comment 2026-08-09T14:45Z, unchallenged since): push for latency, poll for truth. Slice 1 (#16800, PR #16796) shipped the truth half —
poll-digestderives the caller's digest at read time. This slice builds the latency half: the wake daemon pushes to the composed fleet-server (a webhook target with a stable in-composition service-DNS name — no host bridging, no port drift), and the fleet-server fans out to connected cockpits over the authenticated ingress via SSE.Producer correction (source-verified at intake, 2026-08-14): the signed dispatcher is
WebhookDeliveryService.deliver(ai/services/memory-core/WebhookDeliveryService.mjs— HMAC-SHA256 over the exact body, the fourX-Neo-Wake-*headersreceiver.mjsverifies, refuses unsigned delivery, full backoff/degrade/resume machinery). It is URL-generic viaharnessTargetMetadata.url, so a service-DNS target rides it unchanged — zero dispatcher changes. The daemon'sdeliverViaWebhookUrl(daemon.mjs:2795) is the UNSIGNED legacy channel and is NOT this slice's producer.Key custody (source-verified):
subscribereturns the minted server-issued signingKey to the caller (WakeSubscriptionService.mjs:1143) androtate-keyre-mints (:1302). The fleet-server self-arms at boot per subscription: ensure → rotate-key → hold the key in process memory only (process-bearer custody class; restart = rotation). No deployment secret.Fan-out shape: per-viewer relay subscriptions — each authenticated SSE connect ensures a wake subscription for THAT identity targeting the fleet-server's
/wake; an incoming digest routes ONLY to streams authenticated as its subscription's identity. No cross-identity fan-out; the content-grant separation holds by construction. The delegate pattern (fleet-server's plane credential + explicit target identity) follows the shipped relay precedent (planeMailboxClient); if an MC-side permission gate bites, it surfaces in this slice's PR as its own finding.The Fix
POST /wakeonfleetServer.mjs(427 lines; exact-route siblingsGET /fleet/probe:318,POST /fleet:330) — the class-6 signed-wake receiver: HMAC verification per the subscription secret (ADR 0038 §2.5.1 row 6 — wake HMAC carries ZERO read/write authority), then fan-out + last-received bookkeeping (observational). Compose-internal only: no ingress exposure for/wake(the daemon reaches it via service DNS).GET /fleet/events) behindfleetIngressAuthadmission — one EventSource per cockpit, server fan-out on the existing trust boundary. Ingress-exposed (Caddy passes SSE natively); add the exact route beside/fleet+/fleet/probeinai/deploy/Caddyfile(+ local-agent-os variant, both arms).http://fleet-server:8083/wake), route class distinct from host-listener routes.Contract Ledger
POST /wake(fleet-server, compose-internal)receiver.mjscontract; importsverifyWakeSignature)WebhookDeliveryService(signed Shape-B dispatcher, unchanged)WebhookDeliveryService.mjs:125-146signs + sends the four verified headersfleetIngressAuth.mjs(123 lines, admission precedent)CoalescingEngineService→WebhookDeliveryService)WakeSubscriptionService.mjs:1070/:1143subscribe returns key;:1302rotate-keyai/deploy/Caddyfile*/fleet+/fleet/probeexact routes/wake)Acceptance Criteria
WebhookDeliveryServicedelivers to the fleet-server via its service-DNS URL unchanged; the receiver verifies the class-6 HMAC (sharedverifyWakeSignaturecontract) and rejects unsigned/invalid/unknown-subscription posts with the receiver's own error vocabulary./wakeis NOT ingress-reachable; the SSE endpoint IS, behind admission (negative + positive route tests).Out of Scope
Related
Parent: #16741 (S7) · sibling slice 1: #16800 (merged, PR #16796) · epic #16168 · ADR 0038 §2.5.1 row 6 + §2.8 remote-only journey AC · design authority: #16741 comments (Iris Design v1/v1.1 + author falsification pass + reshaped fork).
Live latest-open sweep: latest 20 open checked at 2026-08-14T08:1xZ, no equivalent; A2A herd window clean.
Origin Session ID: c4996813-01b9-4234-8bdd-ed3bf22c0970
Retrieval Hint:
query_raw_memories("fleet-server wake receiver SSE fan-out service-DNS slice 2")