fix(a11y): valid ARIA role on TuxCodeMaroon + non-empty headings on /install #56

Open
A-Guevara wants to merge 1 commit from claude/strange-hopper-6f122c into main
Owner

Fixes the 6 axe-core violations that had the contrast audit (WCAG 2.2 AAA) workflow red on main. Both are pre-existing and identical across the #54 and #55 merges — neither release introduced them.

1 · TuxCodeMaroon emitted role="error" — 4 nodes, [critical] aria-roles

The v2 vocabulary batch renamed the alert tone to error and swept the role attribute along with it (8f7d5e4), so every banner has shipped an ARIA role that doesn't exist since 2.0.0.

The role now derives from the tone, the same split TuxStatusToast already uses:

tone role aria-live
error, warning alert assertive
info status polite

Safety tones interrupt when a banner appears mid-session; a scheduled-drill notice waits its turn. The blanket aria-live="assertive" on the info tone goes with it.

Kept the roles rather than dropping them: the banner is genuinely dynamic — production wiring drives active from the Rellis alert feed, and the docs specimens toggle on a button — so the live region is doing real work, not decorating a static specimen.

2 · Two /install call sites passed title= to TuxSectionHeader — [minor] empty-heading ×2

TuxSectionHeader takes its text from the default slot and has no title prop, so the string fell through to the wrapping <header> as an HTML tooltip and the <h2> rendered empty. Same mistake shape as the TuxCallout kind fix in 2.2.0: a TuxPageHeader prop used on a component that doesn't take one.

Every other call site across the site already uses the slot, so this is fixed at the two call sites — the component is untouched.

Verification

gate result
npm run audit:a11y 0 violations across 176 pages (was 6 on 2 pages)
AUDIT_LEVEL=AAA npm run audit:contrast 276/276 AAA across tti / tti-dark / tti-hc
npx vitest run 115/115
npx eslint . clean
npm run typecheck clean (stays at zero)
node scripts/ports-manifest.mjs --check clean

TuxCodeMaroon.vue changed, so the ports drift bot will queue it for re-porting on merge — expected. The manifest is deliberately left un-synced here so the bot owns that commit.

Fixes the 6 axe-core violations that had the **contrast audit (WCAG 2.2 AAA)** workflow red on `main`. Both are pre-existing and identical across the #54 and #55 merges — neither release introduced them. ### 1 · `TuxCodeMaroon` emitted `role="error"` — 4 nodes, `[critical] aria-roles` The v2 vocabulary batch renamed the `alert` tone to `error` and swept the role attribute along with it (`8f7d5e4`), so every banner has shipped an ARIA role that doesn't exist since 2.0.0. The role now derives from the tone, the same split `TuxStatusToast` already uses: | tone | role | aria-live | |---|---|---| | `error`, `warning` | `alert` | `assertive` | | `info` | `status` | `polite` | Safety tones interrupt when a banner appears mid-session; a scheduled-drill notice waits its turn. The blanket `aria-live="assertive"` on the `info` tone goes with it. Kept the roles rather than dropping them: the banner is genuinely dynamic — production wiring drives `active` from the Rellis alert feed, and the docs specimens toggle on a button — so the live region is doing real work, not decorating a static specimen. ### 2 · Two `/install` call sites passed `title=` to `TuxSectionHeader` — `[minor] empty-heading` ×2 `TuxSectionHeader` takes its text from the default slot and has no `title` prop, so the string fell through to the wrapping `<header>` as an HTML tooltip and the `<h2>` rendered empty. Same mistake shape as the `TuxCallout` `kind` fix in 2.2.0: a `TuxPageHeader` prop used on a component that doesn't take one. Every other call site across the site already uses the slot, so this is fixed at the two call sites — **the component is untouched**. ### Verification | gate | result | |---|---| | `npm run audit:a11y` | **0 violations across 176 pages** (was 6 on 2 pages) | | `AUDIT_LEVEL=AAA npm run audit:contrast` | 276/276 AAA across `tti` / `tti-dark` / `tti-hc` | | `npx vitest run` | 115/115 | | `npx eslint .` | clean | | `npm run typecheck` | clean (stays at zero) | | `node scripts/ports-manifest.mjs --check` | clean | `TuxCodeMaroon.vue` changed, so the ports drift bot will queue it for re-porting on merge — expected. The manifest is deliberately left un-synced here so the bot owns that commit.
fix(a11y): valid ARIA role on TuxCodeMaroon + non-empty headings on /install
All checks were successful
scan / trivy-fs (push) Successful in 58s
baseline-security / baseline (push) Successful in 1m54s
baseline-security / baseline (pull_request) Successful in 1m43s
scan / trivy-fs (pull_request) Successful in 43s
ai-review / review (pull_request) Successful in 2m5s
46d678a385
The two axe violations that had the audit workflow red on main. Both
pre-existing and identical across the #54 and #55 merges.

TuxCodeMaroon emitted role="error" (4 nodes, [critical] aria-roles).
The v2 vocabulary batch renamed the `alert` tone to `error` and swept
the role attribute along with it (8f7d5e4), shipping an ARIA role that
doesn't exist. Role now derives from tone the way TuxStatusToast does:
error/warning -> role="alert" + aria-live="assertive"; info ->
role="status" + aria-live="polite", replacing the blanket assertive.

Two /install call sites passed title= to TuxSectionHeader, which takes
its text from the default slot. The string fell through to the wrapping
<header> as an HTML tooltip and the <h2> rendered empty ([minor]
empty-heading x2). Every other call site already uses the slot, so this
is a call-site fix; the component is untouched.

npm run audit:a11y: 0 violations across 176 pages (was 6 on 2 pages).
AUDIT_LEVEL=AAA npm run audit:contrast: 276/276 across all three themes.
vitest 115/115, eslint clean, nuxt typecheck clean, ports --check clean.
ai-review-bot left a comment

AI review · advisory

Verdict: nothing confirmed — 4 single-reviewer observations in the debate digest below.

⚑ panel: GPT-OSS 120B · Gemma 4 31B · Devstral 2 123B · Laguna S 2.1 — 4 distinct, 0 confirmed, 4 below threshold, 0 refuted · web: not used · context: 3 files under review · 90 codebase · 14 standards chunks (best-grounded: GPT-OSS 120B; smaller windows saw less)

Panel debate — how this review was reached

Grounding — context: 3 files under review · 90 codebase · 14 standards chunks (best-grounded: GPT-OSS 120B; smaller windows saw less)

Round 1 — independent reviews

  • GPT-OSS 120B (0 findings, confidence 0.97): No issues detected in the changed code; the ARIA role fix and TuxSectionHeader usage corrections appear correct.
  • Gemma 4 31B (0 findings, confidence 1.0): The changes correctly resolve the identified accessibility violations by implementing dynamic ARIA roles/politeness based on tone in TuxCodeMaroon and correcting the prop usage of TuxSectionHeader
  • Devstral 2 123B (4 findings, confidence 0.95): The changes address critical accessibility issues by fixing invalid ARIA roles and ensuring proper use of component props.
  • Laguna S 2.1 (0 findings, confidence 0.98): The diff correctly addresses both axe violations: TuxCodeMaroon now derives role/aria-live from tone instead of emitting the nonexistent role="error", and the two TuxSectionHeader call sites on /insta

Round 2 — cross-examination

  • Devstral 2 123B#1 Invalid ARIA role 'error' · confirmed: Gemma 4 31B · refuted: GPT-OSS 120B, Laguna S 2.1 · support 1
  • Devstral 2 123B#4 Invalid prop 'title' passed to TuxSectionHeader · confirmed: Gemma 4 31B · refuted: GPT-OSS 120B, Laguna S 2.1 · support 1
  • Devstral 2 123B#3 Invalid prop 'title' passed to TuxSectionHeader · confirmed: Gemma 4 31B · refuted: GPT-OSS 120B, Laguna S 2.1 · support 1
  • Devstral 2 123B#2 Hardcoded aria-live value · confirmed: Gemma 4 31B · refuted: GPT-OSS 120B, Laguna S 2.1 · support 1

Not posted (support < 2, or contested at a severity where one refutation vetoes)

  • Devstral 2 123B#1 Invalid ARIA role 'error' (support 1, vetoed by a refutation)
  • Devstral 2 123B#4 Invalid prop 'title' passed to TuxSectionHeader (support 1)
  • Devstral 2 123B#3 Invalid prop 'title' passed to TuxSectionHeader (support 1)
  • Devstral 2 123B#2 Hardcoded aria-live value (support 1)

Synthesis — Laguna S 2.1 wrote the final review from 0 confirmed findings (+4 below threshold) · promotion: support ≥ 2, and no refutation at high severity.

Transcript rv-20260908171100-b2d790 — full round outputs, web results, and model reasoning are viewable by anyone with access to this repository via the AI gateway.

Advisory — never a merge gate. Findings are ordered by how well the panel's own evidence checks out, strongest first. React 👍/👎 on any inline comment to tell it whether it was worth flagging — that is the only feedback this system gets, and every threshold in it is tuned from those reactions. Transcript rv-20260908171100-b2d790.

### AI review · advisory <!-- tti-rv:rv-20260908171100-b2d790: --> **Verdict: nothing confirmed** — 4 single-reviewer observations in the debate digest below. <sub>⚑ panel: GPT-OSS 120B · Gemma 4 31B · Devstral 2 123B · Laguna S 2.1 — 4 distinct, 0 confirmed, 4 below threshold, 0 refuted · web: not used · context: 3 files under review · 90 codebase · 14 standards chunks (best-grounded: GPT-OSS 120B; smaller windows saw less)</sub> <details> <summary>Panel debate — how this review was reached</summary> **Grounding** — context: 3 files under review · 90 codebase · 14 standards chunks (best-grounded: GPT-OSS 120B; smaller windows saw less) **Round 1 — independent reviews** - **GPT-OSS 120B** (0 findings, confidence 0.97): No issues detected in the changed code; the ARIA role fix and TuxSectionHeader usage corrections appear correct. - **Gemma 4 31B** (0 findings, confidence 1.0): The changes correctly resolve the identified accessibility violations by implementing dynamic ARIA roles/politeness based on tone in `TuxCodeMaroon` and correcting the prop usage of `TuxSectionHeader` - **Devstral 2 123B** (4 findings, confidence 0.95): The changes address critical accessibility issues by fixing invalid ARIA roles and ensuring proper use of component props. - **Laguna S 2.1** (0 findings, confidence 0.98): The diff correctly addresses both axe violations: TuxCodeMaroon now derives role/aria-live from tone instead of emitting the nonexistent role="error", and the two TuxSectionHeader call sites on /insta **Round 2 — cross-examination** - `Devstral 2 123B#1` Invalid ARIA role 'error' · confirmed: Gemma 4 31B · refuted: GPT-OSS 120B, Laguna S 2.1 · support 1 - `Devstral 2 123B#4` Invalid prop 'title' passed to TuxSectionHeader · confirmed: Gemma 4 31B · refuted: GPT-OSS 120B, Laguna S 2.1 · support 1 - `Devstral 2 123B#3` Invalid prop 'title' passed to TuxSectionHeader · confirmed: Gemma 4 31B · refuted: GPT-OSS 120B, Laguna S 2.1 · support 1 - `Devstral 2 123B#2` Hardcoded aria-live value · confirmed: Gemma 4 31B · refuted: GPT-OSS 120B, Laguna S 2.1 · support 1 **Not posted** (support < 2, or contested at a severity where one refutation vetoes) - `Devstral 2 123B#1` Invalid ARIA role 'error' (support 1, vetoed by a refutation) - `Devstral 2 123B#4` Invalid prop 'title' passed to TuxSectionHeader (support 1) - `Devstral 2 123B#3` Invalid prop 'title' passed to TuxSectionHeader (support 1) - `Devstral 2 123B#2` Hardcoded aria-live value (support 1) **Synthesis** — Laguna S 2.1 wrote the final review from 0 confirmed findings (+4 below threshold) · promotion: support ≥ 2, and no refutation at high severity. <sub>Transcript `rv-20260908171100-b2d790` — full round outputs, web results, and model reasoning are viewable by anyone with access to this repository via the AI gateway.</sub> </details> <sub>Advisory — never a merge gate. Findings are ordered by how well the panel's own evidence checks out, strongest first. React 👍/👎 on any inline comment to tell it whether it was worth flagging — that is the only feedback this system gets, and every threshold in it is tuned from those reactions. Transcript `rv-20260908171100-b2d790`.</sub>
All checks were successful
scan / trivy-fs (push) Successful in 58s
baseline-security / baseline (push) Successful in 1m54s
baseline-security / baseline (pull_request) Successful in 1m43s
Required
Details
scan / trivy-fs (pull_request) Successful in 43s
ai-review / review (pull_request) Successful in 2m5s
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin claude/strange-hopper-6f122c:claude/strange-hopper-6f122c
git switch claude/strange-hopper-6f122c
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
tti/tti-ux!56
No description provided.