LearnNewsExamplesServices
Frontmatter
title>-
authorneo-opus-vega
stateClosed
createdAtJul 12, 2026, 9:29 AM
updatedAtJul 27, 2026, 12:05 AM
closedAtJul 12, 2026, 4:00 PM
mergedAt
branchesdevagent/14619-fm-aria
urlhttps://github.com/neomjs/neo/pull/15081
contentTrust
projected
quarantined0
signals[]
Closed
neo-opus-vega
neo-opus-vega commented on Jul 12, 2026, 9:29 AM

Resolves #14619

DRAFT — the FM cockpit accessibility pass, landing in non-colliding slices. This first commit ships the ActivityStream aria-live slice (drivable off dev now); the remaining slices accumulate on this branch before it flips to ready: focus-order (touches the drill spine — follows #15063 landing to avoid the collision) and contrast (token verdicts routed to @neo-opus-grace: faint→#666f80 large-text-only, alert→#e46060). Draft so it cannot merge / false-close #14619 until the full pass is here.

Evidence: L2 (unit — construct-probe that the feed root is a named, polite log region). The remaining focus-order slice's L3 (keyboard-nav e2e) lands with it.

What this slice ships

  • ActivityStream — the cockpit's live activity feed had zero aria: a feed whose rows update in place was silent to screen readers (no announcement of new A2A / PR / lane events). onConstructed now makes the root a named, polite log region (aria-live: 'polite', role: 'log', aria-label: 'Live fleet activity'), set before the first refreshFeed render flushes the vdom.

Deltas

  • Scope: this is the aria slice of the #14619 pass, split out because it is non-colliding (ActivityStream is not in #15063's diff) and independently valuable. Focus-order (drill spine, post-#15063) and contrast (Grace's tokens) are the remaining slices on this branch — hence draft.

Test Evidence

  • activityStream.spec.mjs (custom no-webServer config, --workers=1) — 11 passed, including the new a11y construct-probe (aria-live/role/aria-label on the feed root).
  • node --check · ticket-archaeology · block-alignment — green.

Post-Merge Validation

  • Before ready-for-review: the focus-order slice (roving-tabindex / logical tab sequence across the cockpit surfaces, incl. the drill) once #15063 lands; the contrast tokens confirmed applied (Grace); aria on the remaining zero-aria components (FamilyRail, EventChip).
  • Re-run trigger: changes to the ActivityStream render or the cockpit's focusable surfaces.

Authored by Vega (Claude Opus 4.8, Claude Code). Session d99146da-0478-4f23-bc16-dff04f5d650c.

neo-opus-vega
neo-opus-vega commented on Jul 12, 2026, 9:32 AM

Scope note (V-B-A on the other zero-aria FM components, so this slice reads as complete-for-the-real-gap, not missing pieces):

  • EventChip — zero aria attributes, but it renders the kind as visible text (kindLabel), so it is already accessible; adding an aria label would be redundant. No change needed.
  • FamilyRail — a color-only family rail (--fm-family-* token). Family is episode-metadata conveyed by color; an aria-label here is a low-priority nicety, best decided alongside the focus-order slice (whether family is already conveyed by the card's name/avatar row determines label-vs-aria-hidden). Deferred to that slice, not this one.

So the genuine, high-value aria gap was ActivityStream — a live-updating feed silent to screen readers — which this slice closes. The remaining #14619 work is focus-order (post-#15063) + contrast (Grace's tokens) + the FamilyRail label decision.


neo-opus-vega
neo-opus-vega commented on Jul 12, 2026, 4:00 PM

Superseded by #15094 — the aria-live activity log + named landmark regions from this branch (agent/14619-fm-aria) are merged into the consolidated #14619 keyboard-a11y PR #15094 (Euclid's option-B convergence: one complete #14619 PR, not two partial drafts). No work lost; closing to cut open-PR churn.