LearnNewsExamplesServices
Frontmatter
id15115
titleFM cockpit keyboard operability: listitem cards + native drill Button
stateOpen
labels
enhancementai
assigneesneo-opus-vega
createdAt12:49 AM
updatedAt12:49 AM
githubUrlhttps://github.com/neomjs/neo/issues/15115
authorneo-opus-vega
commentsCount0
parentIssue14619
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

FM cockpit keyboard operability: listitem cards + native drill Button

Open Backlog/active-chunk-5 enhancementai
neo-opus-vega
neo-opus-vega commented on 12:49 AM

Context

Decomposition leaf of #14619 (FM cockpit accessibility pass), created per @neo-gpt-emmy's gate-1 / gate-5 review disposition on PR #15094. #14619 is a 4-axis accessibility leaf (focus-order/keyboard, contrast, reduced-motion, token/contract-docs); PR #15094 delivers ONLY the keyboard/focus-order axis, so it must Resolve a scoped leaf rather than close the whole multi-axis epic. #14619 stays open for its remaining axes.

Live latest-open sweep: checked the latest 20 open issues at 2026-07-12T22:47Z; no equivalent keyboard-a11y leaf found. A2A in-flight claim sweep (latest 30, all read-states): no overlapping [lane-claim].

The Problem

The FM fleet cockpit's AgentCards were keyboard-inoperable in a WCAG-invalid way: each card carried role=button while CONTAINING native lifecycle buttons (start/stop/restart) — an invalid nested-interactive topology — and the roving tabindex + role were written to the vdom but did not reliably flush to the mounted DOM (cards were not actually focusable; a mounted whitebox-e2e caught this class of bug the .vdom unit assertions could not see). Screen-reader + keyboard users could not operate the roster correctly.

The Architectural Reality

  • apps/agentos/view/fleet/AgentCard.mjs — the card (a Neo.container.Base), its role, the drill affordance, the lifecycle control cluster.
  • apps/agentos/view/fleet/FleetGrid.mjs — the ranked card region + its keyboard model.
  • apps/agentos/view/fleet/AgentCardController.mjs — the drill (agentSelect) handler.
  • src/main/DomEvents.mjs — the shared main-thread neo-selection arrow-key scroll-suppression rule.
  • Neo Button (src/button/Base.mjs) renders a NATIVE <button type="button">, so native Enter/Space activation is a browser guarantee, not a hand-rolled key handler.

The Fix (implemented — branch agent/14619-fm-focus-order, commit 8c8932f62)

Per the reviewer disposition (the FM roster is a ranked responsive LIST, not a 2D data matrix, so a full ARIA grid composite is the wrong contract):

  • AgentCard → a NON-interactive role=listitem; the card-name becomes a dedicated NATIVE drill <button> (accessible name = the resident name); lifecycle toggle/restart stay as sibling native Buttons — every control a real element in ordinary Tab order (drill → toggle → restart). No card-level tabIndex.
  • FleetGrid → ordinary Tab replaces roving-tabindex; an OPTIONAL Up/Down efficiency shortcut jumps focus between drill Buttons ONLY (large-roster convenience without an outer roving tab stop or a hidden interaction mode); focus survives a roster rebuild, restored to the resident's EXACT semantic child, never the card root or a different agent.
  • DomEvents → reverts the shared Space scroll-suppression (native Buttons own Enter/Space); arrow-scroll suppression scoped to the drill Buttons via neo-selection.

Contract Ledger

N/A — no human/agent/external-consumed surface introduced or changed (the drill Button is an internal app-view component; no public method, config, or MCP tool).

Decision Record impact

none — no ADR interaction.

Acceptance Criteria

  • AgentCard is a non-interactive role=listitem (no card role=button, no card tabIndex) with a dedicated native drill <button> announced by the resident name.
  • Lifecycle toggle/restart are sibling native Buttons; every control in ordinary Tab order (drill → toggle → restart); no nested-interactive topology.
  • Optional Up/Down efficiency jump between drill Buttons only; the page does not scroll on the jump.
  • Focus survives a roster rebuild, restored to the resident's exact semantic child (identity, not index).
  • Unit specs green (agentCard + fleetGrid) + a mounted whitebox-e2e (FleetGridKeyboardA11y.spec.mjs) proving topology, native drill activation, drill-only jump, scroll stability, and semantic-child restoration on the real DOM.

Out of Scope

Contrast, reduced-motion, and token/contract-docs axes of #14619 (they remain #14619's open scope). The large-roster long-Tab UX (a fully-specified layout-grid / filter / search with AT evidence) is a future graduation, not this leaf.

Related

  • Parent epic: #14619 (FM cockpit accessibility pass).
  • Delivered by PR #15094.
  • Supersedes the roving-tabindex approach reviewed in PR #15094 review cycles 1–2 (@neo-gpt + @neo-gpt-emmy dispositions).

Origin Session ID: d99146da-0478-4f23-bc16-dff04f5d650c Retrieval Hint: "FM cockpit keyboard a11y native listitem drill Button gate-1 disposition"