Context
Operator live observation (2026-07-21, current dev, during the #15631 film-surface check): three small Fleet-cockpit surface bugs, all independently verified in source the same hour. Bundled per the anti-over-fragmentation rule — three one-area fixes, one review.
Live latest-open sweep: checked the live tracker (created-desc, 12 latest) at 2026-07-21T11:55Z; no equivalent. A2A in-flight sweep: latest 30 messages; no claim on this scope (Vega's #15624 is the AgentCard anatomy leaf — adjacent, disjoint). KB ticket sweep: #14560 (FM cockpit epic), #14619 (a11y pass) — no equivalent.
The Problem
- The roster badge lies about provenance. The fleet header shows
sample roster while the roster it renders is derived from the graph's identityRoots (buildScripts/util/deriveFleetRoster.mjs → apps/agentos/resources/data/fleetRoster.json, shipped in #15621). The badge conflates "statically served" (no live bridge) with "sample data" — on the film surface this mislabels our real fleet as fake data.
- The fleet grid cannot scroll vertically. With the derived ten-resident roster at 3-column cockpit-zone heights, overflowing cards are unreachable — no scroll path exists.
- The right-edge rail tabs have no hover affordance. The
#15633 quiet-rail reset stripped the chrome but added no hover state, so the navigation reads as inert until clicked (the bar buttons kept theirs).
The Architectural Reality
apps/agentos/view/fleet/FleetGrid.mjs:305 — adapterState === 'sample' → 'sample roster'; the state defaults to 'sample' at apps/agentos/view/fleet/FleetCockpit.mjs:203 (rosterSourceMode) and :290 (gridAdapterState). The derived-roster work (#15621) changed the data's truth but not the badge's semantics: sample now means "static seed of graph-derived identities", not fabricated sample agents.
resources/scss/src/apps/agentos/fleet/FleetGrid.scss — .fm-fleet-grid / .fm-fleet-cards carry padding/gap but no overflow-y anywhere in the chain (compare OperatorComposeForm.scss:11, which solved the identical overflow symptom with overflow-y: auto).
resources/scss/src/apps/agentos/fleet/FleetCockpit.scss:9-20 — the rail-tab reset (background: transparent; border: 0; box-shadow: none) defines no &:hover block, unlike the sibling bar buttons (.fm-preset-button:hover at :39, .fm-fleet-start:hover at :66) which kept the --motion-fast transition idiom.
The Fix
- Badge honesty: rename/rework the
sample adapter state to name provenance, not fabrication — e.g. static/derived rendering as derived roster · offline (or the design owner's wording). The stale/live paths are unaffected. Touch points: FleetCockpit.mjs state defaults + FleetGrid.mjs:305 render branch; keep rosterSourceMode's ingress-policy contract (non-reactive by design, :199-201) intact.
- Scroll: give the fleet grid a vertical scroll path (
overflow-y: auto on the scroll-owning element — verify against the dock projection's sizing so the zone keeps owning layout), mirroring the OperatorComposeForm.scss precedent.
- Hover: add a quiet
&:hover state for .neo-dashboard-dock-rail-tab.neo-button inside .fm-fleet-cockpit (ink-dim → ink on text, panel-toned background lift, the existing --motion-fast / --ease-out-soft tokens) — affordance without re-introducing the blue slab the reset removed.
Acceptance Criteria
Out of Scope
- Live-bridge wiring/bearer hand-off (separate launch-contract lane).
- Activity-stream and AgentDetail overflow behaviors (already handled per-component).
- Any rail behavior change (reveal/pin/auto-hide semantics) — this ticket is surface-only.
Related
#15621 (derived roster from identityRoots — made the badge a liar) · #15633 (quiet rail tabs — dropped the hover) · #15624 (Vega's AgentCard anatomy leaf — adjacent, disjoint) · #14619 (FM a11y pass — hover-affordance adjacency) · #15631 (the film-surface lane that surfaced these)
Origin Session ID: 557fd3c7-7307-499b-9c35-d07fe1c2efcd
Retrieval Hint: fleet cockpit sample roster badge honesty vertical scroll rail tab hover FleetGrid FleetCockpit.scss film surface
Context
Operator live observation (2026-07-21, current
dev, during the#15631film-surface check): three small Fleet-cockpit surface bugs, all independently verified in source the same hour. Bundled per the anti-over-fragmentation rule — three one-area fixes, one review.Live latest-open sweep: checked the live tracker (created-desc, 12 latest) at 2026-07-21T11:55Z; no equivalent. A2A in-flight sweep: latest 30 messages; no claim on this scope (Vega's
#15624is the AgentCard anatomy leaf — adjacent, disjoint). KB ticket sweep:#14560(FM cockpit epic),#14619(a11y pass) — no equivalent.The Problem
sample rosterwhile the roster it renders is derived from the graph's identityRoots (buildScripts/util/deriveFleetRoster.mjs→apps/agentos/resources/data/fleetRoster.json, shipped in#15621). The badge conflates "statically served" (no live bridge) with "sample data" — on the film surface this mislabels our real fleet as fake data.#15633quiet-rail reset stripped the chrome but added no hover state, so the navigation reads as inert until clicked (the bar buttons kept theirs).The Architectural Reality
apps/agentos/view/fleet/FleetGrid.mjs:305—adapterState === 'sample' → 'sample roster'; the state defaults to'sample'atapps/agentos/view/fleet/FleetCockpit.mjs:203(rosterSourceMode) and:290(gridAdapterState). The derived-roster work (#15621) changed the data's truth but not the badge's semantics:samplenow means "static seed of graph-derived identities", not fabricated sample agents.resources/scss/src/apps/agentos/fleet/FleetGrid.scss—.fm-fleet-grid/.fm-fleet-cardscarry padding/gap but nooverflow-yanywhere in the chain (compareOperatorComposeForm.scss:11, which solved the identical overflow symptom withoverflow-y: auto).resources/scss/src/apps/agentos/fleet/FleetCockpit.scss:9-20— the rail-tab reset (background: transparent; border: 0; box-shadow: none) defines no&:hoverblock, unlike the sibling bar buttons (.fm-preset-button:hoverat:39,.fm-fleet-start:hoverat:66) which kept the--motion-fasttransition idiom.The Fix
sampleadapter state to name provenance, not fabrication — e.g.static/derivedrendering asderived roster · offline(or the design owner's wording). The stale/live paths are unaffected. Touch points:FleetCockpit.mjsstate defaults +FleetGrid.mjs:305render branch; keeprosterSourceMode's ingress-policy contract (non-reactive by design,:199-201) intact.overflow-y: autoon the scroll-owning element — verify against the dock projection's sizing so the zone keeps owning layout), mirroring theOperatorComposeForm.scssprecedent.&:hoverstate for.neo-dashboard-dock-rail-tab.neo-buttoninside.fm-fleet-cockpit(ink-dim → ink on text, panel-toned background lift, the existing--motion-fast/--ease-out-softtokens) — affordance without re-introducing the blue slab the reset removed.Acceptance Criteria
npm run build-themesconsumes the SCSS changes cleanly; no token-layer (CSS-in-JS) violations introduced.Out of Scope
Related
#15621(derived roster from identityRoots — made the badge a liar) ·#15633(quiet rail tabs — dropped the hover) ·#15624(Vega's AgentCard anatomy leaf — adjacent, disjoint) ·#14619(FM a11y pass — hover-affordance adjacency) ·#15631(the film-surface lane that surfaced these)Origin Session ID: 557fd3c7-7307-499b-9c35-d07fe1c2efcd
Retrieval Hint:
fleet cockpit sample roster badge honesty vertical scroll rail tab hover FleetGrid FleetCockpit.scss film surface