Accessibility audit record
Tracks the findings from the S39 WCAG AA pass and their
disposition (closed / accepted with rationale). Pair with the
tooling under tests/a11y/ (pa11y-ci + axe-core via Puppeteer)
and the manual screen-reader passes.
Status. This file is the operator log. Entries get added as findings come in; nothing here yet because the live audit happens against the staging instance, not at code-write time. The structure below shows the format the operator uses.
Audited route set
The S39 acceptance gate is "pa11y reports zero high-severity issues across the audited route set." Routes under audit:
- Anonymous:
/,/signup,/login,/explore,/-/health - Authenticated: dashboard,
/settings/profile,/settings/security/2fa,/new,/notifications, one repo overview, one issue view, one PR view (with diff), one PR review form - Admin:
/admin/,/admin/users,/admin/users/{id}
Specifics for the manual SR pass on top of the automated runs:
- Diff view labelling old/new sides for SR users.
- Modal dialogs (delete-repo confirm, transfer-repo confirm, rotate-secret confirm) trap focus and announce on open.
- Form errors associated with their fields via
aria-describedby. - Tables (issue lists, PR lists, audit log) have proper
<th scope>headers. - Keyboard order matches visual order on every form.
Findings template
Each finding is one row:
### F-NN — <short title>
- **Found by:** pa11y / axe / manual SR / manual keyboard / dev review
- **Route:** /…/…
- **Tool rule (if automated):** WCAG2AA.<...>
- **Impact:** critical / serious / moderate / minor
- **Description:** what's wrong, in one paragraph.
- **Disposition:** fixed in <commit-sha> / accepted: <rationale> / deferred to <sprint>
- **Re-tested on:** <date>
Dispositions accepted with rationale
These are findings we acknowledge but do not fix in S39:
(none yet)
Manual SR notes
NVDA + Firefox / VoiceOver + Safari — keep notes here so we don't re-discover the same SR-readability nuances across sprints.
(none yet)
CI integration
The audit-a11y-pa11y Makefile target runs pa11y-ci against the
URL list. Hooked into a manual-trigger CI job (not the main ci
target — it needs a running shithub on the runner, which the
default CI environment doesn't provide). The run produces the
findings list that gets transcribed into this file.
Re-audit cadence
- Every sprint that touches
internal/web/templates/orinternal/web/static/css/. - Every release that adds a new top-level route.
- Quarterly full audit (matches the security re-audit cadence).
View source
| 1 | # Accessibility audit record |
| 2 | |
| 3 | Tracks the findings from the S39 WCAG AA pass and their |
| 4 | disposition (closed / accepted with rationale). Pair with the |
| 5 | tooling under `tests/a11y/` (pa11y-ci + axe-core via Puppeteer) |
| 6 | and the manual screen-reader passes. |
| 7 | |
| 8 | > **Status.** This file is the operator log. Entries get added |
| 9 | > as findings come in; nothing here yet because the live audit |
| 10 | > happens against the staging instance, not at code-write time. |
| 11 | > The structure below shows the format the operator uses. |
| 12 | |
| 13 | ## Audited route set |
| 14 | |
| 15 | The S39 acceptance gate is "pa11y reports zero high-severity |
| 16 | issues across the audited route set." Routes under audit: |
| 17 | |
| 18 | - Anonymous: `/`, `/signup`, `/login`, `/explore`, `/-/health` |
| 19 | - Authenticated: dashboard, `/settings/profile`, |
| 20 | `/settings/security/2fa`, `/new`, `/notifications`, |
| 21 | one repo overview, one issue view, one PR view (with diff), |
| 22 | one PR review form |
| 23 | - Admin: `/admin/`, `/admin/users`, `/admin/users/{id}` |
| 24 | |
| 25 | Specifics for the manual SR pass on top of the automated runs: |
| 26 | |
| 27 | - Diff view labelling old/new sides for SR users. |
| 28 | - Modal dialogs (delete-repo confirm, transfer-repo confirm, |
| 29 | rotate-secret confirm) trap focus and announce on open. |
| 30 | - Form errors associated with their fields via `aria-describedby`. |
| 31 | - Tables (issue lists, PR lists, audit log) have proper `<th |
| 32 | scope>` headers. |
| 33 | - Keyboard order matches visual order on every form. |
| 34 | |
| 35 | ## Findings template |
| 36 | |
| 37 | Each finding is one row: |
| 38 | |
| 39 | ``` |
| 40 | ### F-NN — <short title> |
| 41 | |
| 42 | - **Found by:** pa11y / axe / manual SR / manual keyboard / dev review |
| 43 | - **Route:** /…/… |
| 44 | - **Tool rule (if automated):** WCAG2AA.<...> |
| 45 | - **Impact:** critical / serious / moderate / minor |
| 46 | - **Description:** what's wrong, in one paragraph. |
| 47 | - **Disposition:** fixed in <commit-sha> / accepted: <rationale> / deferred to <sprint> |
| 48 | - **Re-tested on:** <date> |
| 49 | ``` |
| 50 | |
| 51 | ## Dispositions accepted with rationale |
| 52 | |
| 53 | These are findings we acknowledge but do not fix in S39: |
| 54 | |
| 55 | (none yet) |
| 56 | |
| 57 | ## Manual SR notes |
| 58 | |
| 59 | NVDA + Firefox / VoiceOver + Safari — keep notes here so we don't |
| 60 | re-discover the same SR-readability nuances across sprints. |
| 61 | |
| 62 | (none yet) |
| 63 | |
| 64 | ## CI integration |
| 65 | |
| 66 | The `audit-a11y-pa11y` Makefile target runs pa11y-ci against the |
| 67 | URL list. Hooked into a manual-trigger CI job (not the main `ci` |
| 68 | target — it needs a running shithub on the runner, which the |
| 69 | default CI environment doesn't provide). The run produces the |
| 70 | findings list that gets transcribed into this file. |
| 71 | |
| 72 | ## Re-audit cadence |
| 73 | |
| 74 | - Every sprint that touches `internal/web/templates/` or |
| 75 | `internal/web/static/css/`. |
| 76 | - Every release that adds a new top-level route. |
| 77 | - Quarterly full audit (matches the security re-audit cadence). |