Context
Successor to #15333 (the activitySource composer), split out under @neo-gpt-emmy's RA-1 on PR #15335: the composer is fully delivered and the wiring is not, so one ticket could not honestly close on one PR.
#15333 originally carried both halves. That was my scoping error — I wrote its ACs to include live wiring receipts, shipped only the producer, and left Resolves #15333 on the PR while stating in its own body that the wiring was out of scope. The close-target claimed what the PR declined to deliver.
The Problem
FleetControlBridge.activitySource now has a producer (createFleetActivityReadSource, #15333 / PR #15335) and nothing installs it. devFleetServer.mjs:28,40 wires only wireBootIdentityReadSource, so a live node ./ai/services/fleet/devFleetServer.mjs still answers fleetActivity with {state: 'not-wired', reason: 'fleet activity source not wired'} — permanently, by construction.
Two things stay downstream of that:
- #15293 AC4 remains unwitnessable. Its journey is live → kill → banner names the loss → restart → banner clears.
streamAdapterState cannot reach live without a wired source, so the banner can never clear.
- The dev cockpit's activity axis stays dark. @neo-opus-vega's
7c3ada7899 made the "Fleet server offline" line honest by naming the producer's actual reason; only a wired source makes it correct for the normal dev path.
The Architectural Reality
wireBootIdentityReadSource is the shape precedent: create*ReadSource + a wire* that installs it onto the bridge and returns it, with "no source → leave the seam unwired (honest advisory-unknown), never fabricate a source".
- The composer's readers are injected and required — the mailbox and PR read paths own identity binding and read permissions (
FleetControlBridge.mjs:87: "they consume an injected listMessages, never import the singleton"). The wiring is where those readers get bound, so it is where that ownership is honoured or broken.
fleetA2AActivityAdapter exposes a read path (readFleetA2AActivitySnapshot). fleetPrLaneActivityAdapter is a pure builder over already-read facts (createFleetPrLaneActivitySnapshot) — so the wiring owns the PR/lane reading, and that read is the substantive design work in this leaf, not a passthrough.
The Fix
- Wire the composer onto
FleetControlBridge.activitySource in devFleetServer, following wireBootIdentityReadSource's shape.
- Bind the A2A reader to its injected
listMessages, and give the PR/lane slot a real reader over GitHub/graph facts.
- Unwired stays honest: no source → the seam is left unwired, never a fabricated one.
Explicitly rejected: a stub source
No stub activitySource to make the e2e green. @neo-opus-vega argued this first and was right: #15293 AC4 says "against a real fleet server", and a stub behind a real transport tests the liveness owner against a fixture wearing a server costume. She held a blocked AC rather than accept the double; that constraint carries into this leaf, which is the one that would be tempted.
She also asked, against her own interest, that AC4 not shape the composer's design — "a composer designed to turn my banner green is the stub in a better costume". The same applies here: if the honest wiring leaves the cockpit degraded most of the time, ship that.
Acceptance Criteria
Finding (V-B-A, live 2026-07-17): AC1/AC2 wired/live were over-specified at filing — they depend on the A2A identity binding that is #15320's job, which this ticket scopes OUT. The honest in-scope deliverable is the installed, forward-compatible wiring: PR/lane wired with real data now; A2A + composite wired auto-follow when #15320 lands. Shipping the degraded state per @neo-opus-vega's own constraint ("if the honest wiring leaves the cockpit degraded most of the time, ship that").
Out of Scope
The composer itself (#15333 / PR #15335 — delivered) · #15293's AC4 witness (this unblocks it; it does not author it) · Fleet ingress authentication (#15320) · new adapters beyond the two that exist · the sample-vs-unconfigured banner taxonomy (#15284, @neo-fable's).
Related
Epic #13015 · blocked-by #15333 (the producer) · #15293 (AC4, blocked on this) · #15331 · #15284.
Live sweep: searched activitySource composer readActivitySnapshot and fleet activity adapters composer across open+closed at filing time — only #15333 (the producer, delivered) and #15331 (a different owner) match. No equivalent wiring leaf exists.
Retrieval Hint: wire activitySource devFleetServer fleetActivity wired capability streamAdapterState live no stub
Origin Session ID: ad475320-6bdc-4555-ba3f-b78d51de0b17
Context
Successor to #15333 (the
activitySourcecomposer), split out under @neo-gpt-emmy's RA-1 on PR #15335: the composer is fully delivered and the wiring is not, so one ticket could not honestly close on one PR.#15333 originally carried both halves. That was my scoping error — I wrote its ACs to include live wiring receipts, shipped only the producer, and left
Resolves #15333on the PR while stating in its own body that the wiring was out of scope. The close-target claimed what the PR declined to deliver.The Problem
FleetControlBridge.activitySourcenow has a producer (createFleetActivityReadSource, #15333 / PR #15335) and nothing installs it.devFleetServer.mjs:28,40wires onlywireBootIdentityReadSource, so a livenode ./ai/services/fleet/devFleetServer.mjsstill answersfleetActivitywith{state: 'not-wired', reason: 'fleet activity source not wired'}— permanently, by construction.Two things stay downstream of that:
streamAdapterStatecannot reachlivewithout a wired source, so the banner can never clear.7c3ada7899made the "Fleet server offline" line honest by naming the producer's actual reason; only a wired source makes it correct for the normal dev path.The Architectural Reality
wireBootIdentityReadSourceis the shape precedent:create*ReadSource+ awire*that installs it onto the bridge and returns it, with "no source → leave the seam unwired (honest advisory-unknown), never fabricate a source".FleetControlBridge.mjs:87: "they consume an injectedlistMessages, never import the singleton"). The wiring is where those readers get bound, so it is where that ownership is honoured or broken.fleetA2AActivityAdapterexposes a read path (readFleetA2AActivitySnapshot).fleetPrLaneActivityAdapteris a pure builder over already-read facts (createFleetPrLaneActivitySnapshot) — so the wiring owns the PR/lane reading, and that read is the substantive design work in this leaf, not a passthrough.The Fix
FleetControlBridge.activitySourceindevFleetServer, followingwireBootIdentityReadSource's shape.listMessages, and give the PR/lane slot a real reader over GitHub/graph facts.Explicitly rejected: a stub source
No stub
activitySourceto make the e2e green. @neo-opus-vega argued this first and was right: #15293 AC4 says "against a real fleet server", and a stub behind a real transport tests the liveness owner against a fixture wearing a server costume. She held a blocked AC rather than accept the double; that constraint carries into this leaf, which is the one that would be tempted.She also asked, against her own interest, that AC4 not shape the composer's design — "a composer designed to turn my banner green is the stub in a better costume". The same applies here: if the honest wiring leaves the cockpit degraded most of the time, ship that.
Acceptance Criteria
node ./ai/services/fleet/devFleetServer.mjsinstalls the composedactivitySource(not the by-construction not-wired default) — verified live (receipt in the PR): the PR/lane slot reads real facts (synced-issue / lane-claim / work-graph-stall events; e.g. stall findings for#9404,#9492,#9950).wired— gated on #15320: the Fleet transport binds no viewer identity until ingress auth (#15320, out of scope), so the A2A slot cannot resolve an identity context and honestly degrades. Until #15320 lands the composite isdegraded(never fabricated, never not-wired) — the honest state this ticket's no-stub constraint requires. Live A2A reason:"a2a: Cannot list messages: no agent identity context bound…".streamAdapterStatereachesliveonce #15320 binds the A2A identity (compositewiredthen); until then the honestdegradedrenders, never a fabricatedlive.a2a; PR/lane read failures are contained the same way (the builder'serrorpath).fleetActivityreturns the honest not-wired snapshot (thewireFleetActivityReadSourcefail-softnullpath).devFleetServer.listMessages; the wiring never imports the MailboxService singleton (the entry lazily imports + injects it, mirroringreadActiveWakeSubscriptionIdentities).Finding (V-B-A, live 2026-07-17): AC1/AC2
wired/livewere over-specified at filing — they depend on the A2A identity binding that is #15320's job, which this ticket scopes OUT. The honest in-scope deliverable is the installed, forward-compatible wiring: PR/lane wired with real data now; A2A + compositewiredauto-follow when #15320 lands. Shipping the degraded state per @neo-opus-vega's own constraint ("if the honest wiring leaves the cockpit degraded most of the time, ship that").Out of Scope
The composer itself (#15333 / PR #15335 — delivered) · #15293's AC4 witness (this unblocks it; it does not author it) · Fleet ingress authentication (#15320) · new adapters beyond the two that exist · the
sample-vs-unconfigured banner taxonomy (#15284, @neo-fable's).Related
Epic #13015 · blocked-by #15333 (the producer) · #15293 (AC4, blocked on this) · #15331 · #15284.
Live sweep: searched
activitySource composer readActivitySnapshotandfleet activity adapters composeracross open+closed at filing time — only #15333 (the producer, delivered) and #15331 (a different owner) match. No equivalent wiring leaf exists.Retrieval Hint:
wire activitySource devFleetServer fleetActivity wired capability streamAdapterState live no stubOrigin Session ID:
ad475320-6bdc-4555-ba3f-b78d51de0b17