Why
There is currently no CI on pull requests. .github/workflows/release.yml triggers only on release: created, so nothing runs npm test when a PR opens, and nothing checks accessibility at all.
Without a gate, the 16 accessibility fixes in the remediation plan will erode. Several of them are the kind of thing a well-meaning refactor silently undoes — a focus call removed, an aria-selected dropped, a token overridden.
Scope
Add .github/workflows/pr.yml triggered on pull_request:
The axe gate
The audit harness already does this and can be adapted directly. It boots the app, drives it through five states (empty, streaming, populated, settings modal, settings modal with dropdown open), and scans each in light and dark.
Two adaptations needed for CI:
- No live agent. The audit run had working Octavus credentials, so it could send a real prompt and scan a populated conversation. CI will not. Either stub the API endpoints, or reduce the CI scan to the states reachable without a backend and keep the full sweep as a manual job.
- Baseline, not zero. The app does not pass axe cleanly today. Capture the current violations as a checked-in baseline and fail the build when a new violation appears or a fixed one returns. The baseline should only ever shrink; each fix PR updates it downward.
Known baseline as of the audit
Per state, consistent across both themes:
| Rule |
Impact |
Nodes |
color-contrast |
serious |
3 (4 in dark, settings modal) |
nested-interactive |
serious |
2 (3 with the modal open) |
aria-allowed-role |
minor |
1 |
landmark-one-main |
moderate |
1 |
page-has-heading-one |
moderate |
1 |
region |
moderate |
1 (6 with the dropdown open) |
aria-input-field-name |
serious |
1 (dropdown open only) |
Important limitation to document
axe cannot detect A1, the most severe finding in the audit. A live region that re-announces its entire contents is valid HTML; only a screen reader reveals the problem. This gate is a floor, not a ceiling — the plan's manual VoiceOver checks stay mandatory regardless of CI status.
Worth stating in the workflow file itself so nobody mistakes a green badge for conformance.
Acceptance criteria
Reference
a11y-audits/8-5-26/resolution-plan.md → Wave 0 → P0-2
Why
There is currently no CI on pull requests.
.github/workflows/release.ymltriggers only onrelease: created, so nothing runsnpm testwhen a PR opens, and nothing checks accessibility at all.Without a gate, the 16 accessibility fixes in the remediation plan will erode. Several of them are the kind of thing a well-meaning refactor silently undoes — a focus call removed, an
aria-selecteddropped, a token overridden.Scope
Add
.github/workflows/pr.ymltriggered onpull_request:git submodule update --init(the design system is required to render)npm ci, matching the existing release workflownpm testnpm run buildThe axe gate
The audit harness already does this and can be adapted directly. It boots the app, drives it through five states (empty, streaming, populated, settings modal, settings modal with dropdown open), and scans each in light and dark.
Two adaptations needed for CI:
Known baseline as of the audit
Per state, consistent across both themes:
color-contrastnested-interactivearia-allowed-rolelandmark-one-mainpage-has-heading-oneregionaria-input-field-nameImportant limitation to document
axe cannot detect A1, the most severe finding in the audit. A live region that re-announces its entire contents is valid HTML; only a screen reader reveals the problem. This gate is a floor, not a ceiling — the plan's manual VoiceOver checks stay mandatory regardless of CI status.
Worth stating in the workflow file itself so nobody mistakes a green badge for conformance.
Acceptance criteria
Reference
a11y-audits/8-5-26/resolution-plan.md→ Wave 0 → P0-2