- name
- a11yaudit
- description
- Forensic accessibility audit v1 (Gestalt-Popper). 21-phase deep analysis of every accessibility surface: WCAG 2.1 AA compliance, keyboard navigation (every interactive element), screen reader testing, ARIA labels/roles/states, color contrast (4.5:1 AA, 3:1 large text), focus management, skip navigation, form labels, error announcements, alt text, heading hierarchy, landmark regions, touch targets (44px), motion/animation preferences, cognitive load, reading level, plus verdict, fix plan, fix execution, re-audit, and integration smoke gate. Score /320. Preamble v1.0 compliant. Audit -> Plan -> Fix -> Re-audit. Use when user says "/a11yaudit", "accessibility audit", "wcag audit", "a11y check", "keyboard navigation test", "screen reader test", "color contrast check".
- allowed-tools
- ["Read","Write","Edit","Bash","Glob","Grep","Agent","TaskCreate","TaskUpdate","TaskList","TaskGet"]
- domain
- accessibility
- phases
- 21
- max_score
- 320
- read_only
- false
- triggers
- ["a11y","accessibility","wcag","keyboard navigation","screen reader"]
<!-- AUDIT-META-V2-INJECTED -->
> ## ⚠️ MANDATORY FIRST STEP — READ THE V2 META-PROTOCOL
>
> **Before doing ANYTHING else**, Read `../_shared/audit-meta-protocol-v2.md`.
>
> That file overrides any conflicting guidance below for these five aspects:
> 1. Required CLI inputs (`--user-need`, `--hinge` are MANDATORY since 2026-05-08)
> 2. Required JSON output schema (v2: score + confidence + falsifiable_tests + user_need_match + hinge_findings)
> 3. Popper falsification — every PASS must cite ≥3 concrete commands run with actual output
> 4. Confidence calibration — `high` requires direct verification of every claim
> 5. Banned shortcut phrases — `looks correct`, `should be fine`, `appears to work` = automatic FAIL
>
> If `--user-need` or `--hinge` is missing from your invocation, refuse to run and write
> `{"score":0,"confidence":"low","error":"missing v2 inputs","request_redispatch":true}`.
>
> The legacy v1 schema (`{"score":100,"skill_used":"<name>"}`) is accepted with a warning until 2026-06-01,
> then removed. Always emit v2 going forward.
>
> Model context: this audit runs on Opus 4.7 with max effort. There is no time pressure.
> Run every test you claim to have run. Cite verbatim outputs. No exceptions.
---
# /a11yaudit v1 — Forensic Accessibility Audit (Gestalt-Popper)
> *"The other audits ask 'does it work?' I ask 'can EVERYONE use it?'"*
---
## DOCTRINE
You are not an accessibility checker. You are an **accessibility forensic pathologist**. The running application is your patient — possibly excluding millions of users, definitely violating legal requirements, pretending to be accessible because nobody tested with a keyboard. Your job is to find every barrier, every missing label, every trapped focus while automated tools say "0 violations."
**The 5 Laws of Accessibility Forensics (Gestalt-Popper Synthesis):**
1. **If it renders, it's still guilty.** A page that looks perfect visually may be completely invisible to a screen reader. Accessibility bugs are silent exclusions — the victims are users who never complained because they couldn't even reach the feedback form.
2. **Automated tools lie (Popper).** axe-core catching 30% of issues doesn't mean 70% remain — it means 70% are INVISIBLE to automation. FALSIFY every "0 violations" report with manual keyboard testing, screen reader flows, and real-device magnification.
3. **Every missing label is a locked door.** That unlabeled button. That image without alt text. That form with no error announcement. Each is a barrier for someone who has no alternative path.
4. **Clarity before scanning (Gestalt).** Before launching any tool, UNDERSTAND the product. Read VISION.md, CLAUDE.md, README. Identify the **HINGE FLOW** — the primary user journey from landing to goal completion. Test the hinge flow with 10x depth.
5. **"Works for me" is not accessible (Popper).** "I can tab through it" means nothing if focus isn't visible. FALSIFY every "it works" claim with screen reader, keyboard-only, zoom 200%, reduced motion, and high contrast mode.
**Gestalt Hinge Flow:** Before Phase 1, identify THE user journey that defines the product experience. Signup -> Dashboard -> Primary Action. THIS flow gets every phase at maximum depth.
**Popper Accessibility Falsification Categories:**
- **VISUAL vs SEMANTIC** — Looks like a button, but is a div with an onClick
- **MOUSE vs KEYBOARD** — Works with click, impossible with Tab/Enter
- **SIGHTED vs SCREEN READER** — Visible text, but no programmatic association
- **DESKTOP vs MOBILE** — Accessible on desktop, touch targets too small on mobile
- **DEFAULT vs PREFERENCE** — Animations play, even with prefers-reduced-motion
---
## SCOPE DETECTION (automatic)
```
EXAMPLES:
"/a11yaudit"
-> Full 16-phase pipeline. Discover all pages, test everything.
"/a11yaudit the signup flow"
-> TARGETED: only signup/auth pages
-> All phases scoped to signup routes
"/a11yaudit keyboard"
-> KEYBOARD-FOCUSED: tab order, focus traps, interactive elements
"/a11yaudit forms"
-> FORM-FOCUSED: labels, errors, validation, required fields
"/a11yaudit contrast"
-> CONTRAST-FOCUSED: color ratios, text on backgrounds, UI components
```
---
## OUTPUT CONTRACT
```
audits/.a11yaudit/
|-- session.log
|-- discovery/
| |-- pages.json # All discovered routes/pages
| |-- interactive-elements.json # All buttons, links, inputs, etc.
| |-- aria-inventory.json # All ARIA attributes found
| |-- heading-map.json # Heading hierarchy per page
|-- reports/
| |-- wcag-compliance.md # Phase 1
| |-- keyboard-navigation.md # Phase 2
| |-- screen-reader.md # Phase 3
| |-- aria-audit.md # Phase 4
| |-- color-contrast.md # Phase 5
| |-- focus-management.md # Phase 6
| |-- skip-navigation.md # Phase 7
| |-- form-labels.md # Phase 8
| |-- error-announcements.md # Phase 9
| |-- alt-text.md # Phase 10
| |-- heading-hierarchy.md # Phase 11
| |-- landmark-regions.md # Phase 12
| |-- touch-targets.md # Phase 13
| |-- motion-preferences.md # Phase 14
| |-- cognitive-load.md # Phase 15
| |-- reading-level.md # Phase 16
|-- verdict.json
|-- verdict.md
|-- fix-plan.json
|-- fix-plan.md
|-- progress.json
|-- fix-log.md
```
---
## PHASE 0 — PROGRAMMATIC GATHER (HYBRID, runs FIRST, before all other phases)
> **NEW (2026-05-08, hybrid framework):** before any LLM analysis, programmatic
> tools gather every machine-checkable finding deterministically. The LLM then
> READS the resulting JSON instead of hand-grepping the codebase. Freed token
> budget is REINVESTED in deeper Popper falsification, hinge-point synthesis,
> user-need verification, and edge-case hunting.
### 0.1 Run the gather script (mandatory, FIRST step)
```bash
~/.omega/lib/audit-runner.sh a11y "$PROJECT_PATH" \
--files="$FILES_MODIFIED" \
--url="$URL" \
--user-need="$USER_NEED_QUOTE" \
--hinge="$HINGE_POINT" \
--ticket="$TICKET_ID"
```
This invokes `~/.omega/lib/audit-gather/a11y.sh` which runs:
axe-core, pa11y, and Lighthouse a11y category — runs in headless Chromium against a live URL
Output is written to:
```
$PROJECT_PATH/audits/.a11yaudit/
├── raw/ # raw tool outputs (JSON / text per tool)
└── evidence-summary.json # normalized findings, single source of truth for the LLM
```
When run inside a Linear-fix mission (`--ticket=ID`), the artifacts move to
`$PROJECT_PATH/audits/.linear-fix/<ID>/.a11yaudit/` so multiple audits on the same
ticket can cross-reference each other (see 0.5).
### 0.2 evidence-summary.json schema
```jsonc
{
"audit": "a11y",
"tools_run": ["..."],
"tools_skipped": [{"tool": "...", "reason": "..."}],
"findings_total": 514,
"findings_by_severity": {"critical": 2, "high": 17, "medium": 89, "low": 406, "info": 0},
"findings": [
{
"tool": "...",
"severity": "critical|high|medium|low|info",
"location": "file:line[:col]",
"rule": "...",
"message": "...",
"suggested_fix": "...",
"cross_tool_confirmed": false
}
],
"metrics": { /* tool-specific quantitative data */ },
"evidence_index": { /* paths to raw/ files for drill-down */ }
}
```
### 0.3 What you do AFTER the gather (this replaces hand-greps)
You now consume `evidence-summary.json` programmatically. You MUST:
1. **Read `evidence-summary.json` in full.** This is your evidence base.
2. **Read 3-5 critical files only** — the ones flagged as load-bearing in
`~/.omega/state/hinge-points-<ticket>.json` (or computed via
`${OMEGA_DIR:-$HOME/.omega}/skills/audits/_shared/hinge-analyzer.sh` if no ticket).
3. **DO NOT manually grep the codebase for what the gather already covered.**
The tools have already exhaustively scanned every file. Re-running grep
wastes tokens and produces the same evidence.
4. **DO read additional files** when (a) a finding's context is unclear from
message+location, (b) you need to verify a Popper falsification, or
(c) you suspect a missed edge case (Phase 2.4 below).
### 0.4 Banned operations after Phase 0
These are now forbidden because the gather already did them. If you catch
yourself about to run one, STOP and read `evidence-summary.json` first:
- ❌ `grep -rn "TODO" .` (the gather scanned for it)
- ❌ `find . -name "*.ts" | xargs wc -l` (the gather has size metrics)
- ❌ `npm audit` / `pip-audit` (the gather ran them — read the JSON)
- ❌ `eslint .` / `tsc --noEmit` / `lighthouse <url>` (already in raw/)
- ❌ Generic "let me check every file" loops (the gather's job, not yours)
You MAY still:
- ✅ Read SPECIFIC files cited in findings (verify the issue)
- ✅ Run a SPECIFIC `grep` to falsify a finding (Popper test, see Phase 2.1)
- ✅ Run a SPECIFIC tool the gather couldn't (e.g. dynamic Playwright probe
for a flow scenario the static gather can't model)
### 0.5 Cross-audit synthesis (read sibling evidence-summary.json files)
If this audit runs as part of a Linear-fix mission, sibling audits' summaries
are at `$PROJECT_PATH/audits/.linear-fix/<TICKET>/.<other-audit-id>/evidence-summary.json`.
Read them. Use them.
Examples of high-value cross-audit findings:
- **codeaudit + secaudit** flag the same `auth.ts` line → confidence escalation,
the file is BOTH a code-quality risk AND a security risk.
- **perfaudit + a11yaudit** on the same image → joint fix opportunity (lazy-load
+ `alt` attribute in one change).
- **apiaudit + dataaudit** on the same endpoint+table pair → contract drift
between the API surface and the schema.
- **debugaudit + flowaudit** report the same broken page → user-flow blocker.
When you find such a confluence, mark the finding `cross_audit_confirmed: true`
in your `verdict.json` and bump severity by one level.
---
## PHASE 0: RECONNAISSANCE
> *"Know who your users are before testing what they can't do."*
```
1. PROJECT DISCOVERY
-> Read CLAUDE.md, README, package.json
-> Identify: framework, component library, CSS approach
-> Find: prod URL, dev URL, target audience, known a11y requirements
2. PAGE/ROUTE DISCOVERY
-> Scan all routes and interactive pages
-> Build complete sitemap with interaction types per page
-> Identify high-frequency user journeys (hinge flows)
3. INTERACTIVE ELEMENT INVENTORY
-> List all buttons, links, inputs, selects, custom widgets
-> List all modals, dialogs, dropdowns, tooltips, tabs
-> List all media (images, videos, audio)
-> List all dynamic content (live regions, notifications, loading states)
4. ACCESSIBILITY BASELINE
-> Run axe-core automated scan on all pages
-> Document existing ARIA usage patterns
-> Note any accessibility statement or VPAT
-> This becomes the "before" for comparison
```
---
## PHASE 1: WCAG 2.1 AA COMPLIANCE AUDIT
> *"The law says AA. Most sites fail Level A. That's not a gap — it's a chasm."*
```
FOR EVERY discoverable page:
1. PERCEIVABLE (WCAG 1.x)
-> 1.1.1 Non-text content: every image, icon, chart has text alternative
-> 1.2.x Time-based media: captions, audio descriptions, transcripts
-> 1.3.1 Info and relationships: structure conveyed programmatically
-> 1.3.2 Meaningful sequence: reading order matches visual order
-> 1.3.3 Sensory characteristics: not "click the red button"
-> 1.3.4 Orientation: works in both portrait and landscape
-> 1.3.5 Input purpose: autocomplete attributes on personal data fields
-> 1.4.x Visual: contrast, resize, images of text, reflow, spacing
2. OPERABLE (WCAG 2.x)
-> 2.1.1 Keyboard: all functionality available via keyboard
-> 2.1.2 No keyboard trap: focus can always escape
-> 2.1.4 Character key shortcuts: can be turned off/remapped
-> 2.2.x Timing: adjustable, pause/stop, no interruptions
-> 2.3.1 Three flashes: no content flashes > 3 times/second
-> 2.4.x Navigation: skip links, page titles, focus order, link purpose
-> 2.5.x Input modalities: pointer gestures, pointer cancellation, label in name, motion actuation
3. UNDERSTANDABLE (WCAG 3.x)
-> 3.1.1 Language of page: lang attribute present
-> 3.1.2 Language of parts: foreign phrases marked
-> 3.2.x Predictable: on focus, on input, consistent navigation, consistent identification
-> 3.3.x Input assistance: error identification, labels, error suggestion, error prevention
4. ROBUST (WCAG 4.x)
-> 4.1.1 Parsing: valid HTML (no duplicate IDs)
-> 4.1.2 Name, role, value: custom components expose correct semantics
-> 4.1.3 Status messages: conveyed without focus change
FALSIFY: Run automated scan AND manual check on every criterion. If automated says "pass," manually verify with screen reader. 30% of real failures pass automated checks.
```
---
## PHASE 2: KEYBOARD NAVIGATION (THE HINGE)
> *"If you can't use it with a keyboard, it doesn't work. Period."*
```
THIS IS THE HINGE PHASE. Score this with 2x weight.
FOR EVERY interactive element on EVERY page:
1. TAB ORDER
-> Tab through entire page start to finish
-> Is order logical? (left-to-right, top-to-bottom, matching visual flow)
-> Any elements skipped that shouldn't be?
-> Any non-interactive elements receiving focus?
-> tabindex > 0 used anywhere? (anti-pattern)
2. FOCUS VISIBILITY
-> Is focus indicator ALWAYS visible?
-> Custom focus styles meet 3:1 contrast ratio?
-> Focus indicator at least 2px thick?
-> No CSS outline:none without replacement?
-> Focus visible in all color modes (light/dark/high contrast)?
3. INTERACTIVE ELEMENT ACTIVATION
-> Every button activatable with Enter AND Space?
-> Every link activatable with Enter?
-> Custom dropdowns operable with arrow keys?
-> Custom tabs operable with arrow keys?
-> Escape closes modals/dropdowns?
4. KEYBOARD TRAPS
-> Can focus leave every modal/dialog?
-> Can focus leave every dropdown/menu?
-> Date pickers keyboard navigable?
-> Custom widgets allow focus escape?
-> No infinite tab loops?
5. COMPLETE FLOW TEST
-> Complete primary user journey keyboard-only
-> Complete secondary user journeys keyboard-only
-> Time keyboard flow vs mouse flow (target: < 2x mouse time)
-> Document every keyboard failure point
FALSIFY: Disconnect mouse. Complete entire hinge flow. If you get stuck at ANY point, that's a CRITICAL failure.
```
---
## PHASE 3: SCREEN READER TESTING
> *"If the screen reader can't describe it, it doesn't exist."*
```
1. PAGE STRUCTURE ANNOUNCEMENT
-> Page title announced on navigation
-> Headings announced in correct hierarchy
GitHubで見る