Vetrix Accessibility — Manual Verification Procedures
Companion to plans/accessibility.md §6 ("Verification checklist per page"). The
§6 checklist enumerates the what; this document is the how. It gives
step-by-step walkthrough scripts that a reviewer can execute end-to-end on
https://www.gitvetrix.test/ (or any deployed Vetrix environment) to confirm
a release's assistive-technology behaviour before sign-off.
Every script is deliberately concrete: it names the keystrokes, the expected screen-reader utterance, and the pass/fail observation. No hand-waving. A pass means "the SR said the expected sentence and focus landed on the expected element"; a fail is filed as a ticket with the script step that broke.
This is a docs-only reference. It does not change application behaviour. When the application changes, update the relevant expected-utterance lines here in the same PR.
0. Preconditions — one-time environment setup
0.1 Host machines and browser matrix
The three combinations below are mandatory. The plan §6 calls for all three; never substitute one for another.
| # | Screen reader | Browser | Host OS | Notes |
|---|---|---|---|---|
| 1 | NVDA 2024.x | Firefox ESR | Windows 10 / 11 | Preferred on Windows; works best with Firefox + UIA. |
| 2 | VoiceOver | Safari current | macOS 14 or later | Built-in. Use a non-US keyboard layout only if paired. |
| 3 | Orca 46+ | Firefox ESR | Ubuntu 22.04 / 24.04 | Run under a GNOME session (Wayland or X11). |
Chrome-based browsers with NVDA or VO are not an acceptable substitute —
behaviour diverges, particularly around live regions, aria-current, and the
Tabs pattern.
0.2 Accounts and fixture data
Sign in as three users before starting any walkthrough so you don't blow your flow on a login redirect mid-test:
vetrix_admin(admin) —/adminaccess.vetrix_dev1(developer) — ownsvetrix_dev1/hello-phprepo.vetrix_reviewer(read-only on repo) — cannot merge, cannot admin.
Fixture repo requirements:
- At least one open issue with ≥3 comments, labels, an assignee, and a workflow state other than "To do".
- At least one MR in "Review requested" with an inline comment thread on a diff line.
- At least one pipeline with a succeeded and a failed job (for log viewer).
- A board with three columns and ≥5 cards per column (for keyboard DnD).
- A user list in
/admin/userswith ≥20 users so pagination appears.
0.3 Common SR shortcuts used below
| Action | NVDA | VoiceOver | Orca |
|---|---|---|---|
| Start / stop SR | Insert+Ctrl+N / Insert+Q | Cmd+F5 | Super+Alt+S |
| Next heading | H |
VO+Cmd+H | H (browse mode) |
| Previous heading | Shift+H |
VO+Cmd+Shift+H | Shift+H |
| List of landmarks | NVDA+F7 → Landmarks | VO+U → Landmarks | Orca+L → Landmarks |
| Read current focus | NVDA+Tab | VO+F5 | Orca+KP_Plus |
| Next form field | F |
VO+Cmd+J | F |
| Read the whole page | NVDA+Down Arrow | VO+A | Orca+KP_Plus twice |
| Toggle browse/focus (virtual buffer) | NVDA+Space | (not applicable) | Insert+Space |
Keep a note-taker open. The pass criterion is "the SR said the expected sentence"; an approximate match is not a pass.
1. NVDA + Firefox ESR on Windows — walkthrough scripts
NVDA must be restarted between pages if the speech viewer starts truncating
long output (rare but happens on the MR diff page). Run with the Speech Viewer
open (NVDA menu → Tools → Speech Viewer) so you can capture exact utterances
for tickets.
1.1 Login — /login
- Cold-load
https://www.gitvetrix.test/loginin a fresh Firefox profile.- Expected: Page title announced as "Sign in · Vetrix". NVDA reads the
<h1>"Sign in to Vetrix".
- Expected: Page title announced as "Sign in · Vetrix". NVDA reads the
- Press
Tabonce.- Expected: "Skip to main content, link". Pressing
Entermoves focus to<main id="main-content">.
- Expected: "Skip to main content, link". Pressing
- Press
Tabuntil focus reaches the first form field.- Expected: "Username, required, edit, blank". Not "Enter username" (placeholder-as-label is a fail).
- Type an invalid username, Tab to Password, type anything, press
Enter.- Expected: NVDA announces the error alert once, e.g. "Alert —
Incorrect username or password. Try again." The error region must have
role="alert"(§3.2). The Username field regains focus.
- Expected: NVDA announces the error alert once, e.g. "Alert —
Incorrect username or password. Try again." The error region must have
- Fix the credentials, press
Enter.- Expected: After redirect, NVDA reads the new
<h1>("Repositories" or your landing heading). Focus lands on<main>or<h1>, not on the<body>(§1.1 route-change focus).
- Expected: After redirect, NVDA reads the new
- If MFA challenge is enabled: the 6-digit code input must be announced as
"Enter 6-digit code, required, edit" and focus must move to it
automatically (§4.2
/login).
Fail if: skip link missing, error is silent, focus jumps to the URL bar after login, or MFA input does not receive focus.
1.2 Repository browse — /vetrix_dev1/hello-php
- Navigate to the repo landing page. Press
Dto jump to the repo sub-nav landmark.- Expected: "Repository, navigation". Arrow-keys walk Code / Issues / Pull requests / Pipelines / Packages / Pages / Settings.
- Expected: The active tab reports "current page" (from
aria-current, not styling alone — §1.2).
- Press
Hrepeatedly to walk headings.- Expected: one
<h1>= "vetrix_dev1 / hello-php", followed by<h2>s for each section (README, About, Clone, Stats). No<h3>appears before an<h2>.
- Expected: one
- Tab to the Clone disclosure.
- Expected: "Clone, button, collapsed".
EnterorSpaceexpands it to "expanded"; the HTTPS/SSH panel is announced.
- Expected: "Clone, button, collapsed".
- Tab to the Copy HTTPS URL button inside the Clone panel.
- Expected: Accessible name spells the URL, e.g. "Copy HTTPS clone
URL, https://gitvetrix.test/vetrix_dev1/hello-php.git, button". Press
Enter; a polite live region announces "Copied".
- Expected: Accessible name spells the URL, e.g. "Copy HTTPS clone
URL, https://gitvetrix.test/vetrix_dev1/hello-php.git, button". Press
- Switch to Code tab, then Tab into the file list.
- If the tree renders as a table: each row announces
<th scope="row">file/directory name plus "(directory)" or "(file)" (§4.7). - If the tree is a WAI-ARIA tree: Right Arrow expands a collapsed
<treeitem>and NVDA says "expanded, level 2" etc.
- If the tree renders as a table: each row announces
- Open a file (
src/index.php). PressFto step through interactive buttons.- Expected: "Raw, link", "Blame, link", "History, link" — each has a unique accessible name (§2.15/§4.7).
1.3 Issue detail — /vetrix_dev1/hello-php/issues/1
- Land on the page. Press
H.- Expected:
<h1>reads the issue title (not the number, not the status — §4.9). Status badge is a sibling with a text value ("In Progress"), announced as part of reading order.
- Expected:
- Press
R(next landmark region) or NVDA+F7 to list landmarks.- Expected: Regions include
<main>, a<section aria-label="Issue sidebar">, and<section aria-label="Comments">.
- Expected: Regions include
- Tab through the sidebar metadata.
- Expected: Each field announces as a pair: "Assignees: alice, bob", "Labels: bug, priority: high", "Milestone: v1.0", "Due date: 2026-05-01". Empty fields announce "Not set" as text, never silence (§4.9).
- Tab to the Watching toggle.
- Expected: "Watching, toggle button, pressed" (or "not pressed"). Space flips it; SR announces the new state.
- Jump to the comment composer with
E(edit field).- Expected: Composer is a labelled textarea ("Write a comment"). MarkdownEditor toolbar is exposed as a toolbar region with labelled buttons ("Bold", "Italic", etc. — §2.18).
- Submit an empty comment.
- Expected:
role="alert"announces "Comment body is required". Focus returns to the textarea.
- Expected:
- Click Move to In Progress (workflow transition). If a pre-condition fails, a polite live region announces the failure reason (§4.9). Do not accept inline red text as a substitute.
1.4 Merge request review — /vetrix_dev1/hello-php/pulls/1
- Press
Hto confirm the<h1>is the MR title. - Press
T(next tab stop) or Tab until you hit the Tabs group (Conversation / Commits / Files / Checks).- Expected: NVDA announces "Conversation, tab, selected, 1 of 4". Right Arrow moves to Commits and announces "Commits, tab, 2 of 4". Count badges inside tabs are part of the accessible name ("Files, 4 of 4, 12 changed" — §2.8).
- Switch to Files. Tab into the DiffViewer.
- Expected: The "+" / "-" glyph in each diff line is read as text, not skipped (§2.16). A line-number is either aria-hidden or part of a proper table.
- Tab to a "Add comment on line N" button.
- Expected: "Add comment on line 42 of src/index.php, button"
(§4.8). Pressing
Enteropens an inline thread composer with focus trapped until you submit or dismiss.
- Expected: "Add comment on line 42 of src/index.php, button"
(§4.8). Pressing
- Submit a review.
- Expected: The approve/request-changes/comment radio group is
wrapped in
<fieldset>with legend "Review decision" (§4.8).
- Expected: The approve/request-changes/comment radio group is
wrapped in
- Confirm the merge button.
- Expected: ConfirmModal title = "Merge pull request", button label = "Merge pull request #1 into develop" (§3.4). Escape closes and returns focus to the Merge trigger.
- Toggle Mark as viewed on one file.
- Expected: "Mark src/index.php as viewed, checkbox, checked".
1.5 Board — /vetrix_dev1/hello-php/boards/1
This is the single most important SR test — the kanban board is a 🔴 blocker risk zone (§4.9).
- Press
Rto list regions.- Expected: each column is
<section aria-label="To do, 5 cards">etc. — never an unlabelled div stack.
- Expected: each column is
- Tab to the first card in "To do".
- Expected: NVDA reads "ISSUE-123 Fix login redirect, priority high, assigned to alice, 1 of 5, listitem". The card is a single focus stop.
- With focus on the card, open its actions menu (Enter or a visible "Card
menu" button).
- Expected: Menu contains "Move to next column", "Move to previous column", "Move to top of column", "Move to bottom of column", and "Open". No DnD-required step should be keyboard-exclusive (§4.9).
- Activate "Move to next column".
- Expected: a polite live region announces "Moved ISSUE-123 to In progress". The column region labels update their counts ("To do, 4 cards"; "In progress, 6 cards"). Focus stays on the moved card.
- Let the test board receive a WebSocket update (another user moves a
card).
- Expected: a batched polite utterance fires no more than once per ~5 seconds: "3 cards moved in the last 5 seconds" (§3.5). Each individual move does not announce.
1.6 Pipeline log — /vetrix_dev1/hello-php/pipelines/1
- Navigate in. Press
Hto confirm<h1>= pipeline name + run number. - Tab into the stage/job graph region.
- Expected: A text-list fallback exists (
<ul>) reading "{stage}: {job} — {status}" for each node (§4.10). If only an SVG graph is present, that is a fail.
- Expected: A text-list fallback exists (
- Open the log panel for a running job. NVDA with default verbosity must
not announce every new log line (sensory overload — §3.5).
- Expected: A polite live region announces only the terminal state ("Build succeeded" or "Build failed, exit code 1").
- Tab to the Pause autoscroll toggle.
- Expected: "Pause autoscroll, toggle button, not pressed". Space pauses; the log stops jumping but continues rendering.
- Tab to Cancel.
- Expected: Activating Cancel opens
<ConfirmModal>labelled "Cancel pipeline run", confirm button = "Cancel run #1"; Escape returns focus (§3.4 / §4.10).
- Expected: Activating Cancel opens
1.7 Admin user list — /admin/users
- Press
Dfor the Admin sub-nav landmark; NVDA says "Admin, navigation, Users, current page" (§4.14). - Press
Tto jump to the user table.- Expected:
<caption>(visually hidden) reads e.g. "All users, 137 rows". Every column header hasscope="col"; each username cell is<th scope="row">(§2.9).
- Expected:
- Arrow keys inside the table navigate cells (NVDA table-nav: Ctrl+Alt +Arrows). Column header announces on every cross-column move.
- Tab to a row-action button.
- Expected: "Impersonate user alice@example.com, button"; never plain "Impersonate" (§2.9 row actions).
- Activate Impersonate.
- Expected: ConfirmModal, title "Impersonate user", body explains
the 4-hour session and audit-log entry, confirm button labelled
"Impersonate alice@example.com". On accept, a
role="status"banner ("You are impersonating alice — 4 h remaining, Stop impersonating") is announced once (§1.2).
- Expected: ConfirmModal, title "Impersonate user", body explains
the 4-hour session and audit-log entry, confirm button labelled
"Impersonate alice@example.com". On accept, a
- Filter search.
- Expected: The search input is
type="search". After debounce, a polite live region announces "42 results" once (§3.1).
- Expected: The search input is
2. VoiceOver + Safari on macOS — walkthrough scripts
Before starting:
System Settings → Accessibility → VoiceOver → Open VoiceOver Utility → Verbosity → Text: set "When text is selected" to "Speak text". Set punctuation to "All" for the duration of the review.System Settings → Accessibility → VoiceOver → Commanders → Quick Nav: enable Quick Nav (toggle with Left+Right Arrow held together) so single-key navigation (H,F,R) matches NVDA usage.- Safari:
Develop → Enable JavaScript from Apple EventsandSafari → Settings → Advanced → Press Tab to highlight each item on a webpageon — Safari defaults to skipping non-link controls otherwise.
2.1 Login, repo browse, issue detail, MR review, board, pipeline log, admin
Re-run the seven scripts from §1 against VoiceOver with the following substitutions:
| NVDA step | VoiceOver equivalent |
|---|---|
| NVDA+F7 → Landmarks | VO+U → Landmarks menu |
H / Shift+H |
H / Shift+H (with Quick Nav) or VO+Cmd+H / VO+Cmd+Shift+H |
| NVDA+Down Arrow (read all) | VO+A |
| Read current focus | VO+F5 |
| Enter forms mode | VoiceOver doesn't have a forms mode; interactors always active |
| Ctrl+Alt+Arrow (table nav) | VO+Cmd+Arrow |
| Toggle browse / focus | (VoiceOver is always live) |
Points where Safari/VO behaviour must specifically be observed (NVDA passing doesn't imply VO passes):
- Skip-to-content link (§1.1). VO+F5 after first Tab must report "Skip
to main content" — Safari sometimes skips this if
display:noneis used instead ofclip: rect(…)+position:absolute. If VO says nothing, that is a fail even if NVDA passed. role="alert"firing. Safari + VO is historically stricter — a fresh DOM insertion of a node withrole="alert"is announced; a pre-existing node whose text changed is not. The login error and the empty-comment error must therefore be inserted, not merely filled. If VO is silent on error but NVDA announced it, file a ticket.- Tab pattern (§2.8). VO announces "Conversation, tab 1 of 4, selected"
only if
aria-selectedis present; if the implementation instead usesaria-currenton a link-styled tab, VO will say "current page" which is wrong for tab semantics (§2.8). - Live-region chattiness. VO with
politeregions will still queue multiple messages; if a burst of SSE log lines slips past the §3.5 debounce, VO will read them all. This is a common regression — test it. - Combobox (§2.4). In Safari, Headless UI's Combobox must expose
aria-expandedon the input; without it VO doesn't announce the listbox opening. Test the assignees picker on/issues/newand confirm VO says "expanded, 8 items" when you open the menu. <progress>on milestones (§4.9). Safari narrates<progress>with its value only; VO users rely on the visible text equivalent ("8 of 12 issues closed, 67%"). If the text equivalent is absent, VO will read only "67%" with no subject.- PDF-like content (docs/): not applicable — Vetrix does not render PDFs inline today. Skip.
2.2 Reduced motion, forced color scheme (macOS)
System Settings → Accessibility → Display → Reduce motion on. Re-visit:
/pipelines/[id]— the line-anchor jump must not scroll smoothly; reduce-motion must snap to the line (§2.15 —scrollIntoView({ behavior: "smooth" })is a fail)./boards/[id]— card move animations must be ≤0.01s; the DnD reorder must not slide when reduced-motion is on.
System Settings → General → Appearance → Dark. Re-visit all seven pages
above and confirm dark-mode tokens resolve — no invisible text, no blocks of
black-on-black (§1.3).
2.3 Voice Control spot-check (macOS)
Voice Control is a macOS feature orthogonal to VO — it turns visible labels into activation phrases. Any control whose accessible name ≠ visible label is a Voice Control fail (WCAG 2.5.3 "Label in Name").
Procedure:
System Settings → Accessibility → Voice Control→ on. Say "Show numbers" to overlay activation numbers on every control; say "Hide numbers" to clear.- On
/login, say "Click Sign in".- Expected: the Sign in button activates. If you have to fall back to "Click 3" (the number overlay), the accessible name drifted from the visible label — file a ticket.
- On
/vetrix_dev1/hello-php/issues/1, say "Click Move to In Progress".- Expected: the workflow transition activates. If VO announced
"Move issue to In Progress, button" but Voice Control requires "Click
Move issue to In Progress" to dispatch, that's a Label-in-Name
violation. Fix by visibly displaying the full accessible name or
shortening
aria-labelto match.
- Expected: the workflow transition activates. If VO announced
"Move issue to In Progress, button" but Voice Control requires "Click
Move issue to In Progress" to dispatch, that's a Label-in-Name
violation. Fix by visibly displaying the full accessible name or
shortening
- On
/admin/users, say "Click Impersonate alice at example dot com".- Expected: the impersonate action opens for Alice. If the button's
visible label is just "Impersonate" and its
aria-labelis "Impersonate user alice@example.com", Voice Control will fail this step — §2.9 requires the row-subject to be part of the visible composition (e.g. the button sits adjacent to the username cell) or the accessible name to begin with the visible text.
- Expected: the impersonate action opens for Alice. If the button's
visible label is just "Impersonate" and its
Run the Voice Control spot-check on:
/login→ "Click Sign in"/vetrix_dev1/hello-php→ "Click Clone"/vetrix_dev1/hello-php/issues/new→ "Click Submit issue"/vetrix_dev1/hello-php/pulls/1→ "Click Merge pull request"/admin/users→ "Click Impersonate"
A failure on any of the five is a 🟠 ticket against the specific page.
3. Orca + Firefox ESR on Ubuntu — walkthrough scripts
Orca is the only Linux target; Firefox is the only supported browser. Chromium with Orca is out of scope.
3.1 Orca preflight
Settings → Accessibility → Screen readeron, orSuper+Alt+S.- Orca preferences (
Orca+Space):- General → Keyboard layout: set to match your physical layout (Laptop keyboard layouts use Caps Lock as the Orca modifier; Desktop uses KP_Insert).
- Voice → Verbosity: Verbose during verification.
- Web → "Present layout tables" off (Vetrix should not ship layout
tables; toggling this off surfaces any accidental
<table>used for layout). - Web → "Automatically start speaking a page when it is loaded" on.
3.2 Login, repo browse, issue detail, MR review, board, pipeline log, admin
Re-run §1's seven scripts. Orca-specific notes:
- Browse mode is on by default on web content; press
Orca+Ato toggle focus mode for rich widgets (MarkdownEditor, Combobox listboxes). Vetrix must operate in browse mode for reading and focus mode only when necessary — if/boards/[id]requires focus mode to interact with cards, that's a UX regression, file it (§4.9). - Landmarks list:
Orca+Lopens the Navigation list; select "Landmarks". Each page from §1 must exposebanner,main, anavper nav region, andcontentinfoon the footer. - Skip-link behaviour: Orca + Firefox sometimes fails to announce a pre-existing skip link; it must actually receive focus on first Tab so that focus mode kicks in and Orca re-reads. The script above (§1.1 step 2) therefore holds.
- Live region flake: Orca's polite-queue is empirically the slowest of
the three SRs. After a toast, wait ~2 s before interacting — if Orca
hasn't announced by then, the
aria-liveregion is wrong (§1.5). - Table column header re-announcement: when you move to a cell in a
different column inside
<table>, Orca announces the column header name only if<th scope="col">is set. Missingscopeis a silent failure in NVDA (it announces anyway via header discovery) but a loud failure in Orca (silence). Use Orca as the authoritative test for §2.9scopecorrectness. - Combobox (§2.4): Orca announces "expanded" on the trigger only if
aria-expandedis on the same element that receives focus. Headless UI satisfies this; custom wrappers sometimes do not. Test on/issues/newand/pulls/newreviewer pickers. <progress>: Orca announces both the visible text and the progressbar value, so a correct milestone row reads "Milestone v1.0, 8 of 12 issues closed, 67%, progress bar, 67%".
3.3 Orca + reduced motion
GNOME offers Settings → Accessibility → Reduced animation — toggle it on
and re-run the reduced-motion subset from §2.2.
3.4 Orca voice-control note
Orca is not a voice-control tool. Skip §2.3 on Linux — there is no supported Linux voice-control product to verify Label-in-Name against. macOS Voice Control covers the Label-in-Name obligation for the matrix.
4. 400% zoom + 200% text zoom (WCAG 1.4.10 / 1.4.12) — procedure
Run on Firefox with default window sizing 1280×1024. If you use a larger
monitor, resize the Firefox window to 1280×1024 first so reflow behaviour
matches the spec's reference viewport.
4.1 Page zoom to 400%
- Open each page from the test matrix (§1.1–§1.7).
Ctrl++(Cmd+Plus on macOS) five times to reach 400%. Firefox shows "400%" in the URL bar's zoom indicator.- Observe the page for:
- No horizontal scrollbar on the document (reflow per 1.4.10). Vertical scroll is expected and fine.
- No clipped content. The full TopNav actions must still be reachable (collapsed into a menu if necessary, as long as the menu is keyboard-operable).
- All interactive elements still visible and activatable. Buttons don't overflow their row; inputs don't become unreadably narrow.
- Perform one representative action per page at 400%:
/login— sign in./vetrix_dev1/hello-php— open the Clone disclosure and copy the URL./issues/1— post a comment./pulls/1— switch tabs and open an inline comment thread./boards/1— move a card to the next column./pipelines/1— toggle pause-autoscroll./admin/users— filter the list and impersonate.
Fail: any of the above causes a horizontal scrollbar to appear on the document root, or any control needed for the action is clipped off-screen.
4.2 Text-only zoom to 200%
Firefox: View → Zoom → Zoom Text Only checkbox on, then Ctrl++ until the
zoom indicator reports 200%.
- Revisit each page from the matrix.
- Observe for:
- No text truncation with
…in visible labels (WCAG 1.4.12 text spacing and 1.4.4 resize text). If a label becomesComp…, that is a fail — widen or allow wrapping. - No loss of functionality. Buttons still clickable; dropdowns still open within the viewport.
- Line-height preserved. At 200% text zoom with UA default line-height, nothing should overlap.
- No text truncation with
- At 200% text-only zoom, confirm specific widgets:
- Badges (§2.7) wrap their text without the background losing shape.
- Tabs (§2.8) with count suffixes ("Files, 12 changed") don't truncate the count.
- Tables (§2.9) scroll horizontally inside their wrapper but the document itself does not.
Fail: any clipped label, any overlapping line, any lost-to-viewport control.
4.3 Zoom combined with reduced motion
Toggle prefers-reduced-motion: reduce via Firefox DevTools (Accessibility
panel → "Simulate", or about:config → ui.prefersReducedMotion = 1) and
re-run §4.1 once. Zoom and reduced motion must not interact badly (e.g.
reflow must not rely on animation to stabilise the layout).
5. Chrome DevTools colour-blindness emulation — checklist per status badge
WCAG 1.4.1 forbids colour as the sole indicator. Vetrix has a lot of status badges; every one must pass under every vision-deficiency filter. Chrome DevTools is the canonical tool (Firefox DevTools lacks the matrix).
5.1 Procedure
- Chrome: open DevTools →
⋮(top-right of DevTools) → More tools → Rendering. - In the Rendering panel, find Emulate vision deficiencies. Available
modes:
- No emulation (baseline)
- Blurred vision
- Reduced contrast
- Protanopia (red-blind)
- Deuteranopia (green-blind)
- Tritanopia (blue-blind)
- Achromatopsia (total colour blindness)
- For each status surface listed in §5.2, switch through all seven modes in order and verify the non-colour signal at each step.
5.2 Surfaces and the non-colour signal that must be present
Every cell must pass under every filter. "Pass" = the status is legible without reference to hue.
| Surface | Plan ref | Non-colour signal required |
|---|---|---|
IssueStatusBadge (Open / In Progress / Done) |
§2.7 | Text label + glyph prefix; distinct backgrounds in grayscale. |
PriorityBadge (Low / Med / High / Critical) |
§2.7 | Arrow glyph and text ("High"). The arrow alone fails. |
WorkflowStateBadge |
§2.7 | Category word ("To do" / "In progress" / "Done") spelled in text next to the badge. |
IssueTypeBadge (Bug / Deficiency / Task) |
§2.7 | Type icon + text label. |
| Pipeline job status (Running / Success / Failed) | §4.10 | Glyph (↻ / ✓ / ✗) + text; the "running" spinner must also expose role="status" with "Running" text. |
| Pipeline log level (info / warn / error) | §3.5 | Level word in the line prefix ([WARN], [ERROR]) — never colour-only. |
| Deployment status (Succeeded / Failed / Rolled back) | §4.10 | Text label in cell; green/red border plus glyph. |
| Security severity (Critical / High / Med / Low) | §4.10 | Text label + glyph (double-up-arrow / up-arrow / dash / down-arrow). |
| MR check status (Pending / Passed / Failed) | §4.8 | Glyph + text; red/green on row stripe must not be the only carrier. |
| Board card priority hue stripe | §4.9 | Priority text in the card body — never infer priority from stripe colour alone. |
| Environment state (Active / Stopped / Locked) | §4.10 | Text label + glyph; the green pulse on Active must not be the only signal. |
<progress> on milestones (§4.9) |
§4.9 | Textual fraction ("8 of 12 issues closed") as a sibling of the bar. |
| Admin status pill (Active / Suspended / Deleted) | §4.14 | Text label + a glyph or a distinct outline. |
/status service health (Operational / Degraded / Down) |
§4.2 | Text + glyph (✓ / ⚠ / ✗); also expose in accessible name. |
5.3 Reporting
For every failure, capture:
- Page URL.
- Filter mode that surfaced the failure.
- Screenshot with the filter active.
- The element's DOM snapshot (right-click → Copy element) for the ticket.
File a sub-ticket with a clear title (e.g. "PriorityBadge fails deuteranopia — arrow-only differentiator").
6. Keyboard-only walkthrough (baseline for all three SR matrices)
Before starting any screen-reader script above, do a dry keyboard pass of the seven target pages (§1.1–§1.7) with the SR off. This catches keyboard traps that would otherwise be blamed on the SR.
6.1 Procedure per page
- Load the page. Click once in the URL bar and then
Tabback to the document. - Tab through every interactive element in order.
- Pass: a visible focus ring (from
--vetrix-focus-ring, §1.3) is present on every stop; the tab order matches the visual order. - Fail: a stop has no visible ring (violates WCAG 2.4.7); tab order jumps disorientingly (e.g. from a sidebar link to a deeply nested button on the other side of the viewport).
- Pass: a visible focus ring (from
- At every stop, confirm you can activate with the expected key:
- Buttons: Enter and Space.
- Links: Enter only (per spec; Space must not also activate, or screen magnifier users get unexpected navigation).
- Toggles / switches: Space.
- Combobox: Down Arrow opens, Enter selects, Escape closes.
- Tabs: Left/Right/Home/End navigates, Tab moves out of the tablist.
- Shift+Tab back through. Order must reverse exactly.
- Escape from every modal, dropdown, combobox. Focus must return to the originating trigger — not the body, not the top of the page (§2.6).
6.2 Specific trap checks
/boards/[id]— after moving a card with the menu (§1.5),Escmust not move focus away from the card./pulls/[number]— opening an inline comment thread must trapTabinside the composer until submit/cancel;Esccancels./pipelines/[id]— pressingTabwhile the log is scrolling must be possible (the autoscroll must not race the focus)./admin/users— paginationNextbutton must remain focused after the table re-renders; if focus falls back to<body>, that is a §1.1 focus- management fail (§2.10 must also announce page change).
7. Reporting and ticket hygiene
A failure in any of §1–§6 is a defect. File with:
- Title:
{page} {SR/browser} {brief symptom}— e.g./pulls/[n] VoiceOver Safari — review radio group missing fieldset legend. - Body: the exact step from this document that failed (quote the step number and the expected utterance), the actual utterance captured from the SR's speech viewer, screenshots at 400% / under the relevant vision filter if applicable.
- Severity: use
plans/accessibility.md§0 legend (🔴 Blocker / 🟠 High / 🟡 Medium / 🟢 Polish). - AC reference: cite the
plans/accessibility.mdsection whose requirement the failure violates (e.g. §2.9, §4.9).
Do not file a ticket per SR — if NVDA, VO, and Orca all fail the same way, one ticket with a matrix ("NVDA+FF fail, VO+Safari fail, Orca+FF fail") is sufficient.
8. Pre-release sign-off checklist
Per release, the a11y gatekeeper runs:
- §1 NVDA + Firefox: all seven pages green.
- §2 VoiceOver + Safari: all seven pages green (including §2.2 reduced motion + dark).
- §2.3 Voice Control spot-check: five actions green.
- §3 Orca + Firefox: all seven pages green.
- §4 400% zoom: all seven pages reflow without horizontal scroll.
- §4.2 200% text-only zoom: no truncation on any page.
- §5 Chrome DevTools vision filters: every status surface readable under all seven modes.
- §6 Keyboard-only pass: no trap, visible focus on every stop.
A red item blocks the release until fixed or a documented waiver is signed by the a11y gatekeeper. The waiver names the section, the regression, and the ticket tracking the fix.