Context
Observed live 2026-08-10 ~19:56Z during the #16694 / #16911 one-command cockpit receipt run (operator machine, plane mode): the fleet transport booted with every seam bound to the containerized plane (viewer @neo-fable-clio verified plane-side), the browser page self-redeemed the bearer (PR #16912 flow), and the grid rendered the LIVE roster — FLEET · 9 AGENTS with real presence bands (4 online / 1 idle / 4 dark, matching plane who_is_online truth). The spine banner above that live grid read:
"Fleet server offline — showing the static roster · start it: npm run ai:fleet-server"
Both clauses are false for the surface the operator is looking at: the server is up (it answered the polls that populated the rows), and the roster is not static.
Liveness falsification (how "the grid is live" was verified, not assumed): the static sample (apps/agentos/resources/data/fleetRoster.json) contains 10 rows including neo-gemini-pro and NO presence fields; the rendered grid showed exactly the 9 host-registry agents (no neo-gemini-pro) WITH presence bands tracking real recent activity. Sample ≠ rendered ⇒ wire data.
The activity stream, meanwhile, honestly labeled itself sample · live feed pending — the stream surface genuinely was sample.
The Problem
deriveSpineBanner (apps/agentos/view/fleet/spineBanner.mjs:128-148, verified at source) computes its cold verdict as:
const surfaces = [grid, stream],
states = surfaces.map(surface => surface?.state);
if (states.includes('sample')) { … 'showing the static roster' … }ANY sample surface forces the FULL cold verdict — and the cold copy asserts a claim about the ROSTER ("showing the static roster") plus a diagnosis ("Fleet server offline") that the grid surface, live in the same frame, contradicts. The banner is the cockpit's honesty spine; here it is the one dishonest element on an otherwise truthful page. An operator reading it would restart a healthy server (the classic-copy advice) or distrust the live presence bands they were shown.
Secondary observation from the same run: clicking Reconnect did not flip the verdict (grid stayed live, stream stayed sample, banner stayed "offline"). Whatever Reconnect rechecks, a permanently-sample stream keeps the cold verdict latched.
Open question the fix should answer along the way (observation, not asserted cause): WHY the stream surface stayed sample for minutes in a healthy plane-mode session — the server-side activity source was wired (boot log), so either the stream feed rides a verb/cadence that never delivered, or its go-live transition has its own defect. That may turn out to be a second, narrower ticket; this one owns the banner's conflation.
The Architectural Reality
apps/agentos/view/fleet/spineBanner.mjs:113-148 — deriveSpineBanner({daemon, grid, stream, transport}); the cold branch collapses per-surface truth into one verdict whose copy speaks only in roster terms.
spineBanner.mjs:91-111 — coldFallbackFor (the #16694-aware topology fallback) picks the classic "start it" line for the plain-browser flow; the line is only ever right when the TRANSPORT is actually silent.
#16834 (adjacent, delivered slice) added the typed connection states to the cold/stale branches — vocabulary for the CONNECTION axis. This ticket is about the SURFACE axis: which surface a verdict may speak for.
- The grid/stream surfaces already carry independent
{state, reason} — the derivation input is per-surface; only the verdict flattens them.
The Fix (prescription, owner may reshape)
Per-surface honesty: a sample STREAM under a live GRID must not claim the roster is static or the server offline. Candidate shape: partition the cold verdict — grid-sample drives the roster/static/server-offline family; stream-sample alone degrades to a stream-scoped line (e.g. "activity feed pending — roster is live"); both-sample keeps today's copy. The #16834 connection states and the retained-reason precedence stay untouched. The existing spineBanner matrix spec idiom covers the new rows.
Acceptance Criteria
Out of Scope
- The stream-feed go-live defect itself (named above as an open question — file narrow if confirmed distinct).
#16824 scoped-empty projection; #16834 remaining vocabulary.
- The bearer hand-off (PR #16912) — the banner behaves identically under NL-injected and handshake-redeemed bearers.
Related
#16834 (connection-axis vocabulary, adjacent) · #16824 (scoped-empty) · #16744 (banner-truth evidence rows, incl. the S3-presence↔banner coherence AC this instance witnesses) · #16694 / #16911 / PR #16912 (the run that surfaced it) · #16721 (answered-empty discipline, merged).
Live latest-open sweep: latest 12 open issues checked at 2026-08-10T20:04Z — no equivalent (nearest #16834, scope-distinguished above). A2A sweep: no overlapping claim in the recent window.
Origin Session ID: ff94e740-acb8-4f25-a94b-b614bdd91ea1
Retrieval Hint: "spine banner surface conflation live grid sample stream static roster"
Context
Observed live 2026-08-10 ~19:56Z during the
#16694/#16911one-command cockpit receipt run (operator machine, plane mode): the fleet transport booted with every seam bound to the containerized plane (viewer @neo-fable-clio verified plane-side), the browser page self-redeemed the bearer (PR #16912 flow), and the grid rendered the LIVE roster — FLEET · 9 AGENTS with real presence bands (4 online / 1 idle / 4 dark, matching planewho_is_onlinetruth). The spine banner above that live grid read:Both clauses are false for the surface the operator is looking at: the server is up (it answered the polls that populated the rows), and the roster is not static.
Liveness falsification (how "the grid is live" was verified, not assumed): the static sample (
apps/agentos/resources/data/fleetRoster.json) contains 10 rows includingneo-gemini-proand NOpresencefields; the rendered grid showed exactly the 9 host-registry agents (noneo-gemini-pro) WITH presence bands tracking real recent activity. Sample ≠ rendered ⇒ wire data.The activity stream, meanwhile, honestly labeled itself
sample · live feed pending— the stream surface genuinely was sample.The Problem
deriveSpineBanner(apps/agentos/view/fleet/spineBanner.mjs:128-148, verified at source) computes its cold verdict as:const surfaces = [grid, stream], states = surfaces.map(surface => surface?.state); if (states.includes('sample')) { … 'showing the static roster' … }ANY sample surface forces the FULL cold verdict — and the cold copy asserts a claim about the ROSTER ("showing the static roster") plus a diagnosis ("Fleet server offline") that the grid surface, live in the same frame, contradicts. The banner is the cockpit's honesty spine; here it is the one dishonest element on an otherwise truthful page. An operator reading it would restart a healthy server (the classic-copy advice) or distrust the live presence bands they were shown.
Secondary observation from the same run: clicking Reconnect did not flip the verdict (grid stayed live, stream stayed sample, banner stayed "offline"). Whatever Reconnect rechecks, a permanently-sample stream keeps the cold verdict latched.
Open question the fix should answer along the way (observation, not asserted cause): WHY the stream surface stayed
samplefor minutes in a healthy plane-mode session — the server-side activity source was wired (boot log), so either the stream feed rides a verb/cadence that never delivered, or its go-live transition has its own defect. That may turn out to be a second, narrower ticket; this one owns the banner's conflation.The Architectural Reality
apps/agentos/view/fleet/spineBanner.mjs:113-148—deriveSpineBanner({daemon, grid, stream, transport}); the cold branch collapses per-surface truth into one verdict whose copy speaks only in roster terms.spineBanner.mjs:91-111—coldFallbackFor(the#16694-aware topology fallback) picks the classic "start it" line for the plain-browser flow; the line is only ever right when the TRANSPORT is actually silent.#16834(adjacent, delivered slice) added the typed connection states to the cold/stale branches — vocabulary for the CONNECTION axis. This ticket is about the SURFACE axis: which surface a verdict may speak for.{state, reason}— the derivation input is per-surface; only the verdict flattens them.The Fix (prescription, owner may reshape)
Per-surface honesty: a sample STREAM under a live GRID must not claim the roster is static or the server offline. Candidate shape: partition the cold verdict — grid-sample drives the roster/static/server-offline family; stream-sample alone degrades to a stream-scoped line (e.g. "activity feed pending — roster is live"); both-sample keeps today's copy. The
#16834connection states and the retained-reason precedence stay untouched. The existing spineBanner matrix spec idiom covers the new rows.Acceptance Criteria
#16834connection-state lines unaffected (existing matrix rows stay green).Out of Scope
#16824scoped-empty projection;#16834remaining vocabulary.Related
#16834(connection-axis vocabulary, adjacent) ·#16824(scoped-empty) ·#16744(banner-truth evidence rows, incl. the S3-presence↔banner coherence AC this instance witnesses) ·#16694/#16911/ PR #16912 (the run that surfaced it) ·#16721(answered-empty discipline, merged).Live latest-open sweep: latest 12 open issues checked at 2026-08-10T20:04Z — no equivalent (nearest
#16834, scope-distinguished above). A2A sweep: no overlapping claim in the recent window.Origin Session ID: ff94e740-acb8-4f25-a94b-b614bdd91ea1
Retrieval Hint: "spine banner surface conflation live grid sample stream static roster"