Context
Narrow delivered leaf split out of #14793 per pull-request-workflow.md §9.1, which prescribes exactly this: "Before ready_for_review, add the honest delivered leaf close target or split/file the narrow ticket."
#14793 is a four-AC native-shell specification ticket (first-run, tray, window defaults, cockpit frame). PR #16050 delivers one bullet of its §3, so Resolves #14793 would close three untouched ACs by keyword — and §9.1 also bars Resolves on anything but the leaf a PR fully delivers.
The Problem
#14793 §3 requires:
Degraded state (a daemon down) surfaces as tray-state change + ONE cockpit banner with the diagnosis pointer — never a popup storm.
The tray half shipped. The cockpit half did not exist: a Brain daemon could die and the cockpit said nothing, so the operator's only signal was a tray tooltip.
The Architectural Reality
Three constraints shaped the answer, and each closed off the obvious implementation:
- "ONE banner" forbids a new component. A second banner surface would violate the clause it was added to satisfy.
apps/agentos/view/fleet/spineBanner.mjs is the cockpit's single honesty line, so daemon health joins it as a third surface under that module's existing per-surface-reason discipline — a transport sibling can neither supply nor silence the daemon's cause.
- No new shell capability is warranted.
webContents.send + an ipcRenderer.on in the preload would widen the one audited shell boundary, and harness/preload.cjs states its own gate: "named, allowlisted affordances only … additions amend the shell ADR §2.3 first." Unnecessary — FleetControlBridge.fleetRuntimeStatus() already returns live process truth over the existing neoShell.fleetRequest invoke, so the banner is a pull.
- Absence must not read as health. Nothing pulls daemon health yet. Defaulting
daemonState to 'running' would assert the organism is fine on the strength of never having asked — the same unearned-certification shape as #16037's capability gate. null renders nothing and claims nothing.
The Fix (one PR)
PR #16050. deriveSpineBanner gains an optional daemon surface ranked between sample and stale; FleetCockpit holds daemonState / daemonDegradedReason and passes them through syncSpineBanner. No new style, no new data path, no new IPC capability.
Acceptance Criteria
Out of Scope
- §3's
Start/Stop agents tray verbs — blocked on a design-authority call, not on effort: FleetControlBridge is per-agent only (startAgent(id) / stopAgent(id)) with no fleet-wide verb, so §3 as written needs semantics that do not exist. Recorded on #14793; @neo-opus-grace holds it.
- #14793's AC1 / AC3 / AC4 — untouched, which is why this leaf exists.
Related
- Parent spec: #14793
- Reference-hygiene / close-target rules:
pull-request-workflow.md §9.1
- Split precedent from this session: #16048 (narrow leaf out of #15536)
Context
Narrow delivered leaf split out of #14793 per
pull-request-workflow.md§9.1, which prescribes exactly this: "Beforeready_for_review, add the honest delivered leaf close target or split/file the narrow ticket."#14793 is a four-AC native-shell specification ticket (first-run, tray, window defaults, cockpit frame). PR #16050 delivers one bullet of its §3, so
Resolves #14793would close three untouched ACs by keyword — and §9.1 also barsResolveson anything but the leaf a PR fully delivers.The Problem
#14793 §3 requires:
The tray half shipped. The cockpit half did not exist: a Brain daemon could die and the cockpit said nothing, so the operator's only signal was a tray tooltip.
The Architectural Reality
Three constraints shaped the answer, and each closed off the obvious implementation:
apps/agentos/view/fleet/spineBanner.mjsis the cockpit's single honesty line, so daemon health joins it as a third surface under that module's existing per-surface-reason discipline — a transport sibling can neither supply nor silence the daemon's cause.webContents.send+ anipcRenderer.onin the preload would widen the one audited shell boundary, andharness/preload.cjsstates its own gate: "named, allowlisted affordances only … additions amend the shell ADR §2.3 first." Unnecessary —FleetControlBridge.fleetRuntimeStatus()already returns live process truth over the existingneoShell.fleetRequestinvoke, so the banner is a pull.daemonStateto'running'would assert the organism is fine on the strength of never having asked — the same unearned-certification shape as #16037's capability gate.nullrenders nothing and claims nothing.The Fix (one PR)
PR #16050.
deriveSpineBannergains an optionaldaemonsurface ranked betweensampleandstale;FleetCockpitholdsdaemonState/daemonDegradedReasonand passes them throughsyncSpineBanner. No new style, no new data path, no new IPC capability.Acceptance Criteria
degradedorstoppeddaemon renders one banner naming its state in the sentence (not colour alone — WCAG 1.4.1) plus the retained diagnosis pointer, with generic fallback copy when no cause was learned.runningearns zero pixels.daemonStatefromfleetRuntimeStatus()over the existingfleetRequest. Until then the banner is correct and silent.Out of Scope
Start/Stop agentstray verbs — blocked on a design-authority call, not on effort:FleetControlBridgeis per-agent only (startAgent(id)/stopAgent(id)) with no fleet-wide verb, so §3 as written needs semantics that do not exist. Recorded on #14793; @neo-opus-grace holds it.Related
pull-request-workflow.md§9.1