Skip to content
Back to skills

A11y Audit

ASecurity

Dedicated WCAG 2.2 AA/AAA accessibility audit across 10 dimensions (A1-A10) covering semantic HTML, keyboard navigation, ARIA patterns, color contrast, forms, images/media, responsive/zoom, motion/animation, reading/content, and legal compliance. Goes far beyond surface-level design-review checks with deep compliance-focused analysis, WCAG criterion mapping, and legal risk assessment (ADA Title II, EAA, Section 508). Critical gates on keyboard (A2) and contrast (A4). Flags: [path] | full | --...

  • 8 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 28, 2026
developmentjavascripttypescriptpythongojavaphpkotlinbashsqlreact

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned September 21, 2026

npx -y skills add greglas75/zuvo --skill a11y-audit --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of A11y Audit?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for A11y Audit
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/greglas75-a11y-audit/badge)](https://www.skillsdirectory.com/skills/greglas75-a11y-audit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: a11y-audit
description: >
  Dedicated WCAG 2.2 AA/AAA accessibility audit across 10 dimensions (A1-A10)
  covering semantic HTML, keyboard navigation, ARIA patterns, color contrast,
  forms, images/media, responsive/zoom, motion/animation, reading/content, and
  legal compliance. Goes far beyond surface-level design-review checks with
  deep compliance-focused analysis, WCAG criterion mapping, and legal risk
  assessment (ADA Title II, EAA, Section 508). Critical gates on keyboard (A2)
  and contrast (A4). Flags: [path] | full | --live-url <url> | --quick |
  --fix | --standard AA|AAA | --legal ada|eaa|508.
category: Accessibility
codesift_tools:
  always:
    - analyze_project
    - index_status
    - index_folder
    - index_file
    - plan_turn
    - get_file_tree
    - get_file_outline
    - search_text              # aria-*, role=, alt=, tabindex, lang attrs
    - search_symbols           # interactive component discovery
    - get_symbol
    - search_patterns          # WCAG anti-patterns (missing alt, nested interactive, etc.)
    - audit_scan
  by_stack:
    typescript: [get_type_info]
    javascript: []
    python: [python_audit, analyze_async_correctness]
    php: [php_project_audit, php_security_scan, resolve_php_namespace]
    kotlin: [analyze_sealed_hierarchy, find_extension_functions, trace_flow_chain, trace_suspend_chain, trace_compose_tree, analyze_compose_recomposition, trace_hilt_graph, trace_room_schema, analyze_kmp_declarations, extract_kotlin_serialization_contract]
    nestjs: [nest_audit]
    nextjs: [framework_audit, nextjs_route_map]
    astro: [astro_audit, astro_actions_audit, astro_hydration_audit, astro_image_audit, astro_svg_components]
    hono: [analyze_hono_app, audit_hono_security]
    express: []
    fastify: []
    react: [react_quickstart, analyze_hooks, analyze_renders, trace_component_tree]
    django: [analyze_django_settings, effective_django_view_security, taint_trace]
    fastapi: [trace_fastapi_depends, get_pydantic_models]
    flask: [find_framework_wiring]
    jest: []
    yii: [resolve_php_service, find_php_views]
    prisma: [analyze_prisma_schema]
    drizzle: []
    sql: [sql_audit]
    postgres: [migration_lint]
---

# zuvo:a11y-audit — WCAG 2.2 Accessibility Audit

Deep, compliance-focused accessibility audit across 10 weighted dimensions with WCAG 2.2 criterion mapping, legal risk assessment, and actionable fix generation. Every finding maps to a specific WCAG success criterion and severity level.

**When to use:** Before public launches, when targeting WCAG compliance, after ADA/EAA legal requirements surface, periodic accessibility health checks, when onboarding a codebase that must meet compliance standards, after adding interactive components or forms.
**Out of scope:** Surface-level design consistency (`zuvo:design-review`), visual design quality (`zuvo:ui-design-team`), code quality (`zuvo:code-audit`), penetration testing (`zuvo:pentest`).

## Argument Parsing

Parse `$ARGUMENTS` for these flags:

| Argument | Effect |
|----------|--------|
| `[path]` | Audit a specific directory or component |
| `full` | Audit the entire project |
| `--live-url <url>` | Enable browser-based testing (axe-core via MCP) |
| `--quick` | Critical gates only (A2 Keyboard, A4 Contrast) |
| `--fix` | Generate fix code for all findings |
| `--standard AA\|AAA` | Compliance level (default: AA) |
| `--legal ada\|eaa\|508` | Focus on a specific legal standard |
| `--max-files [N]` | Cap audit to N files (default: 40) |
| `--persist-backlog` | Emit backlog entries for CRITICAL/HIGH findings |

| Mode | Scope | Phases | Browser |
|------|-------|--------|---------|
| `[path]` | Directory/component | 0-5 | No |
| `full` | Entire project | 0-5 | No |
| `--live-url` | Project + URL | 0-5 incl. Phase 2 browser | Yes |
| `--quick` | Project | 0, 1 (A2+A4 only), 5 | No |

## Mandatory File Loading

Read these files before any work begins. Print the checklist with status.

**Stage 1 -- Before Phase 0 (STOP if any missing):**

```
CORE FILES LOADED:
  1. ../../shared/includes/codesift-setup.md  -- [READ | MISSING -> STOP]
  2. ../../shared/includes/env-compat.md      -- [READ | MISSING -> STOP]
```

**Stage 2 -- Before Phase 5 (report writing):**

```
  3. ../../shared/includes/run-logger.md      -- [READ | MISSING -> STOP]
  4. ../../shared/includes/retrospective.md      -- [READ | MISSING -> STOP]
  5. ../../shared/includes/backlog-protocol.md -- [READ | MISSING -> degraded]
```

Stage 2 deferred to save upfront context.

## Environment Compatibility

Read `../../shared/includes/env-compat.md` for agent dispatch patterns, path resolution, and progress tracking across all supported platforms.

## MANDATORY TOOL CALLS — A11y Audit Validity Gate

**INVALID if any tool below is skipped.** "DEFERRED", "N/A" NOT valid reasons.

| Tool | Trigger | Skip allowed? |
|------|---------|---------------|
| `get_file_tree` | Always | **NO** |
| `search_text` | Always | **NO** — aria-*, role=, alt=, tabindex, lang attrs |
| `search_symbols` | Always | **NO** — interactive component discovery |
| `search_patterns` | Always | **NO** — WCAG anti-patterns (missing alt, nested interactive) |
| `audit_scan` | Always | **NO** — compound check |
| React tools (analyze_hooks, trace_component_tree) | React detected | **NO** when React |

Forbidden: same as above (skipped/N/A/codesift unavailable when deferred — REJECTED).

POSTAMBLE: report on disk → retro appended → `~/.zuvo/append-runlog` exit 0. Every A-dim finding needs `path/to/file.ext:LINE` (verify-audit gate).

```
Mandatory-tools-acknowledgment: I will run get_file_tree + search_text + search_symbols + search_patterns + audit_scan + React tools (when React) for this a11y audit. Every A-dim finding will cite a `path/to/file.ext:LINE` resolving in the current tree.
```

**Use the deterministic preload helper FIRST.** Run `~/.zuvo/compute-preload a11y-audit "$PWD"`. Math gate enforced.

---

## CodeSift Integration

Read `../../shared/includes/codesift-setup.md` for the full initialization sequence.

**a11y-audit CodeSift usage:**
- `search_text(repo, "aria-|role=", regex=true, file_pattern="*.tsx")` -- ARIA attribute scan
- `search_text(repo, "<h[1-6]", regex=true, file_pattern="*.tsx")` -- heading inventory
- `search_text(repo, "tabindex\|tabIndex", regex=true)` -- tabindex usage
- `search_text(repo, ":focus-visible\|:focus", regex=true, file_pattern="*.css")` -- focus style scan
- `search_text(repo, "prefers-reduced-motion", file_pattern="*.css")` -- motion media query
- `search_text(repo, "alt=", file_pattern="*.tsx")` -- alt text coverage
- `search_symbols(repo, "useReducedMotion|usePrefersReducedMotion", include_source=true)` -- motion hook usage

### Degraded Mode (CodeSift unavailable)

| CodeSift tool | Fallback | Lost capability |
|---------------|----------|-----------------|
| `search_text` (ARIA) | `Grep` for ARIA attributes | Same coverage, more tokens |
| `search_symbols` (hooks) | `Grep` for hook names | Less precise matches |
| `get_file_tree` | `find` command | Slower, no symbol counts |
| `get_file_outline` | `Read` each file | More tokens consumed |

---

## Dimensions (A1-A10)

### A1: Semantic HTML (weight 10)

| Check | WCAG | Detection |
|-------|------|-----------|
| Heading hierarchy (h1-h6 in order, no skips) | 1.3.1 | Scan for `<h1>`-`<h6>` ordering per page/component |
| Landmark regions (nav, main, aside, footer, header) | 1.3.1 | Grep for landmark elements or ARIA landmark roles |
| Lists used for list content (not divs) | 1.3.1 | Pattern: repeated sibling divs that should be `<ul>/<li>` |
| Tables with proper thead/th/scope | 1.3.1 | Grep for `<table>` without `<th>` or missing `scope` |
| Buttons vs links (button for actions, a for navigation) | 4.1.2 | `<a>` with `onClick` and no `href`, `<div>` with click handlers |

### A2: Keyboard Navigation (weight 12, CRITICAL GATE)

| Check | WCAG | Detection |
|-------|------|-----------|
| All interactive elements focusable | 2.1.1 | `<div onClick>` without `tabIndex` or `role="button"` |
| Tab order matches visual order (no positive tabindex) | 2.4.3 | `tabindex` values > 0 |
| Focus visible on all interactive elements | 2.4.7 | `:focus-visible` or `:focus` styles present for interactive elements |
| No keyboard traps | 2.1.2 | Modal/dialog without escape handler, custom widgets without blur path |
| Skip navigation link present | 2.4.1 | First focusable element links to `#main` or `#content` |
| Custom component keyboard handlers | 2.1.1 | Custom interactive elements missing `onKeyDown`/`onKeyUp` for Enter, Space, Escape, Arrow keys |
| Modal/dialog focus management | 2.4.3 | Focus trapped inside modal, focus returns to trigger on close |

### A3: ARIA Patterns (weight 10)

| Check | WCAG | Detection |
|-------|------|-----------|
| ARIA roles match component behavior | 4.1.2 | Role attribute vs actual element behavior |
| aria-label/aria-labelledby on elements without visible text | 4.1.2 | Icon buttons, image-only links without label |
| aria-expanded on toggleable elements | 4.1.2 | Dropdowns, accordions missing `aria-expanded` |
| aria-live regions for dynamic content | 4.1.3 | Toast, notification, status updates without `aria-live` |
| aria-hidden on decorative elements | 4.1.2 | Decorative icons/images without `aria-hidden="true"` |
| No redundant ARIA | 4.1.2 | `role="button"` on `<button>`, `role="link"` on `<a>` |
| aria-describedby for form field help text | 1.3.1 | Help text near inputs without association |

### A4: Color & Contrast (weight 10, CRITICAL GATE)

| Check | WCAG | Detection |
|-------|------|-----------|
| Text contrast >= 4.5:1 (normal), >= 3:1 (large) | 1.4.3 | Extract color values from CSS/tokens, compute ratios |
| UI component contrast >= 3:1 | 1.4.11 | Border, icon, form control colors vs background |
| Information not conveyed by color alone | 1.4.1 | Status indicators, error states using only color |
| Focus indicator contrast >= 3:1 | 1.4.11 | Focus ring color vs surrounding background |
| Light and dark theme coverage | 1.4.3 | Both themes checked if `prefers-color-scheme` or theme toggle exists |

### A5: Forms & Inputs (weight 10)

| Check | WCAG | Detection |
|-------|------|-----------|
| Every input has associated label | 1.3.1, 3.3.2 | `<input>` without `<label>`, `aria-label`, or `aria-labelledby` |
| Error messages linked to fields | 3.3.1 | Error elements without `aria-describedby` or `aria-errormessage` |
| Required fields marked | 3.3.2 | Missing `aria-required="true"` and no visual indicator |
| Autocomplete attributes on common fields | 1.3.5 | Name, email, phone, address inputs without `autocomplete` |
| Form validation errors announced | 4.1.3 | Error summary not in `aria-live` region |
| Related fields grouped | 1.3.1 | Radio groups, address fields without `<fieldset>`/`<legend>` |

### A6: Images & Media (weight 8)

| Check | WCAG | Detection |
|-------|------|-----------|
| Informative images have alt text | 1.1.1 | `<img>` without `alt`, or `alt="image"` / `alt="photo"` |
| Decorative images have alt="" or aria-hidden | 1.1.1 | Decorative images with meaningful alt |
| Complex images have long description | 1.1.1 | Charts, diagrams without `aria-describedby` or `<figcaption>` |
| Video has captions/subtitles | 1.2.2 | `<video>` without `<track kind="captions">` |
| Audio has transcript | 1.2.1 | `<audio>` without transcript link |
| SVG has title or aria-label | 1.1.1, 4.1.2 | `<svg>` without `<title>` or `aria-label` |
| No auto-playing media | 1.4.2 | `autoplay` attribute without pause control |

### A7: Responsive & Zoom (weight 6)

| Check | WCAG | Detection |
|-------|------|-----------|
| Content reflows at 320px width | 1.4.10 | Horizontal scroll triggers, fixed-width containers |
| Text resizable to 200% | 1.4.4 | Font sizes in `px` instead of `rem`/`em` |
| Touch targets minimum 44x44px | 2.5.8 | Small click/tap targets (links, buttons, icons) |
| No content hidden at zoom | 1.4.10 | `overflow: hidden` on containers with text |
| Viewport no disable scaling | 1.4.4 | `maximum-scale=1` or `user-scalable=no` in viewport meta |

### A8: Motion & Animation (weight 5)

| Check | WCAG | Detection |
|-------|------|-----------|
| prefers-reduced-motion respected | 2.3.3 | CSS `@media (prefers-reduced-motion)` present |
| No content flashes > 3 times/sec | 2.3.1 | Animation durations < 333ms with repeating patterns |
| Animations can be paused/stopped | 2.2.2 | Auto-playing animations without pause control |
| Carousels have pause control | 2.2.2 | Auto-advancing carousels without pause button |
| Page transitions respect reduced motion | 2.3.3 | Route transitions without motion preference check |

### A9: Reading & Content (weight 5)

| Check | WCAG | Detection |
|-------|------|-----------|
| html lang attribute set | 3.1.1 | `<html>` without `lang` attribute |
| Language changes marked | 3.1.2 | Foreign-language content without `lang` attribute |
| Link text is descriptive | 2.4.4 | "click here", "read more", "learn more" without context |
| Consistent navigation | 3.2.3 | Nav component differs across pages |
| Page titles descriptive and unique | 2.4.2 | Missing `<title>`, duplicate titles, generic titles |

### A10: Legal Compliance Status (NOT scored — separate legal risk section)

A10 is a **qualitative legal risk assessment**, not a scored dimension. It does NOT contribute to the numerical score (to avoid double-counting A1-A9 results). It appears as a standalone section in the report.

| Check | Standard | Detection |
|-------|----------|-----------|
| ADA Title II compliance (deadline: 2026-04-24) | ADA | Map A1-A9 failures to ADA requirements. If audit date < deadline: flag as APPROACHING. If audit date >= deadline: flag as POST-DEADLINE (compliance now mandatory). |
| European Accessibility Act compliance | EAA | Map failures to EAA requirements (if EU-facing) |
| Section 508 compliance | 508 | Map failures to Section 508 (if government) |
| VPAT readiness | VPAT | Assess documentation completeness for VPAT generation |
| Accessibility statement present | All | Check for /accessibility page or statement in footer |

---

## Phase 0: Detection

1. **Detect framework:** React, Next.js, Vue, Nuxt, Svelte, SvelteKit, Astro, Angular, plain HTML
   - Check `package.json` dependencies, config files (`next.config.*`, `astro.config.*`, `svelte.config.*`, `angular.json`)
2. **Detect component library:** MUI, Chakra, Radix, Headless UI, shadcn, Mantine, Ant Design, none
   - Check `package.json` dependencies
3. **Detect existing a11y tooling:**
   - `eslint-plugin-jsx-a11y` in devDependencies
   - `axe-core` or `@axe-core/*` in devDependencies
   - `pa11y` in devDependencies or global
   - `jest-axe` or `vitest-axe` in devDependencies
   - Storybook a11y addon (`@storybook/addon-a11y`)
4. **Detect existing a11y config:**
   - `.axerc` or `axe.config.js`
   - `.pa11y` or `.pa11yci`
   - `eslintrc` with jsx-a11y rules
5. **Estimate scope:** Count pages/components for workload sizing

Output:
```
A11Y DETECTION
  Framework:   [name]
  Components:  [library or "custom"]
  A11y tools:  [list or "none detected"]
  A11y config: [list or "none"]
  Scope:       [N pages, N components]
  Standard:    WCAG 2.2 [AA|AAA]
  Legal focus:  [ADA Title II | EAA | Section 508 | N/A]
```

---

## Phase 1: Static Code Analysis (A1-A9)

Scan templates, JSX/TSX, CSS, and config files against all dimension checks.

### 1.1 Batch Scans

Run grep/CodeSift scans across the codebase for:

| Scan | Target | Dimension |
|------|--------|-----------|
| Heading inventory | `<h1>`-`<h6>` elements per file | A1 |
| Landmark elements | `<nav>`, `<main>`, `<aside>`, `<header>`, `<footer>` | A1 |
| ARIA attributes | `aria-*` attribute usage and coverage | A3 |
| Focus styles | `:focus-visible`, `:focus`, `outline:` in CSS | A2 |
| Tabindex usage | `tabindex`/`tabIndex` values | A2 |
| Skip nav link | First focusable element pattern | A2 |
| Keyboard handlers | `onKeyDown`, `onKeyUp`, `onKeyPress` on custom elements | A2 |
| Color values | Hardcoded hex/rgb in CSS, contrast-relevant variables | A4 |
| Alt text | `alt=` attribute presence and quality | A6 |
| Form labels | `<label>`, `aria-label`, `aria-labelledby` on inputs | A5 |
| Autocomplete | `autocomplete` on common input types | A5 |
| Viewport meta | `viewport` meta tag content | A7 |
| Reduced motion | `prefers-reduced-motion` media query | A8 |
| Lang attribute | `<html lang=` in root templates | A9 |
| Link text | "click here", "read more", "learn more" patterns | A9 |
| SVG accessibility | `<title>` or `aria-label` on SVGs | A6 |

### 1.2 eslint-plugin-jsx-a11y Integration

If `eslint-plugin-jsx-a11y` is detected:
1. **Grep the ESLint config** for disabled `jsx-a11y/*` rules — note each as an intentional exception
2. **Run with project config:** `npx eslint --ext .jsx,.tsx [scope]` — captures what the project considers violations
3. **Run baseline scan:** `npx eslint --no-eslintrc --plugin jsx-a11y --rule '{...}' [scope]` — captures ALL violations including intentionally suppressed ones
4. **Diff the two runs** — suppressions found in config but not in baseline are intentional exceptions. Report them as `[SUPPRESSED]` findings (user decided to allow this) vs `[ACTIVE]` findings (violations the project config also flags)

If not available: skip, rely on manual scan.

### 1.3 Per-Component Scoring

For each page/component in scope, evaluate A1-A9 checks:

```
### [file path]
Component type: [PAGE | FEATURE | SHARED]
| Dim | Score | Max | Evidence |
|-----|-------|-----|----------|
| A1  | [N]   | 10  | [summary] |
| A2  | [N]   | 12  | [summary] |
| A3  | [N]   | 10  | [summary] |
| A4  | [N]   | 10  | [summary] |
| A5  | [N]   | 10  | [summary] |
| A6  | [N]   | 8   | [summary] |
| A7  | [N]   | 6   | [summary] |
| A8  | [N]   | 5   | [summary] |
| A9  | [N]   | 5   | [summary] |
Critical gates: A2=[N]/12 A4=[N]/10 -- [PASS/FAIL]
```

**Scoring per dimension:** Each check within a dimension scores proportionally. Example: A1 has 5 checks, each worth 2 points (total 10). A check scores 0 (fail), 1 (partial), or full points (pass).

Dispatch follows `../../shared/includes/execution-policy.md` through env-compat. Reuse existing
authorization within that policy; session restrictions take precedence. Run each required gate
and report its actual independence or an unmet requirement.

**If >10 components:** Split into batches of 5. Dispatch background agents where env-compat supports parallel dispatch.

---

## Phase 2: Automated Testing

### 2.1 Browser-Based (if --live-url and browser MCP available)

If `mcp-accessibility-scanner` is available:
- `scan_page(url)` per route for axe-core violations
- `scan_page_matrix(url, variants=["mobile", "forced-colors", "reduced-motion", "zoom-200%"])` for variant testing
- `audit_keyboard(url)` for tab order, focus visibility, keyboard traps

If `chrome-devtools` MCP is available but not accessibility-scanner:
- Navigate to pages via `navigate_page`
- Run `evaluate_script` with axe-core injection
- Take screenshots at multiple viewport sizes

**axe-core results override static scan findings:** Where automated tools provide definitive results, they take precedence over grep-based analysis.

### 2.2 pa11y Integration (if available)

If `pa11y` is available:
```bash
npx pa11y [url] --reporter json --standard WCAG2AA
```
Parse JSON output, map violations to A1-A10 dimensions.

### 2.3 Automated Coverage Note

Automated tools catch approximately 30-57% of WCAG issues. The following CANNOT be caught by automated tools and require manual verification:
- Meaningful alt text quality (automated can detect presence, not quality)
- Keyboard trap detection in complex widgets
- Logical reading order
- Content comprehension at different zoom levels
- Whether color alone conveys information (context-dependent)
- Focus management correctness in SPAs
- Screen reader announcement quality

---

## Phase 3: Manual Checklist Verification

For each dimension, verify against WCAG 2.2 success criteria:

1. Map every finding to a specific WCAG criterion (e.g., "1.1.1 Non-text Content", "2.1.1 Keyboard")
2. Classify each check as:
   - **PASS** -- criterion satisfied with evidence
   - **FAIL** -- criterion violated with evidence
   - **CANNOT DETERMINE** -- requires manual verification (e.g., screen reader testing, cognitive assessment)
3. For CANNOT DETERMINE items, describe what manual test is needed

**WCAG Level mapping:**
- Level A (minimum): 1.1.1, 1.2.1, 1.3.1, 1.4.1, 2.1.1, 2.1.2, 2.2.2, 2.3.1, 2.4.1, 2.4.2, 2.4.3, 2.4.4, 3.1.1, 3.2.1, 3.3.1, 3.3.2, 4.1.2
- Level AA (standard target): Level A + 1.3.5, 1.4.3, 1.4.4, 1.4.10, 1.4.11, 2.4.7, 3.1.2, 3.2.3, 3.3.3, 4.1.3
- Level AAA (if `--standard AAA`): Level AA + 1.4.6 (7:1 contrast), 2.3.3, 2.4.9, 2.5.8, 3.1.5, 3.1.6

---

## Phase 4: Fix Generation (if --fix or findings exist)

For each finding, generate a specific code fix:

```
### A11Y-[NNN]: [Title]
Dimension: A[N]
WCAG: [criterion number] [criterion name]
Severity: CRITICAL | HIGH | MEDIUM
Level: A | AA | AAA
File: [path:line]
Impact: [who is affected and how]

Before:
  [code snippet showing the violation]

After:
  [code snippet with the fix applied]

Notes: [implementation considerations]
```

**Prioritization order:**
1. Legal risk (CRITICAL findings in dimensions relevant to `--legal` standard)
2. User impact (keyboard/screen reader blockers > visual issues > enhancements)
3. Effort (quick wins first within same priority tier)

If `--dry-run` flag is set: report all fixes without applying. Show before/after code for each fix.

If `--fix` flag is set:
1. **Create rollback tag:** `git tag a11y-fix-YYYY-MM-DD` before applying any changes
2. Apply all CRITICAL and HIGH fixes automatically. MEDIUM fixes are reported but not auto-applied.
3. Run verification: check that fixes don't break existing tests
4. If tests fail after a fix: revert that specific fix, keep the tag for manual rollback

**Scope guard:** Fixes touch only accessibility attributes, ARIA properties, semantic elements, CSS focus/contrast styles, and meta tags. Fixes do NOT modify business logic, data fetching, or application state.

---

## Phase 5: Report & Backlog

### 5.1 Read Stage 2 Files

Read deferred files:
```
  3. ../../shared/includes/run-logger.md      -- [READ | MISSING -> STOP]
  4. ../../shared/includes/retrospective.md      -- [READ | MISSING -> STOP]
  5. ../../shared/includes/backlog-protocol.md -- [READ | MISSING -> degraded]
```

### 5.2 Scoring

**Per-dimension scoring:** Each dimension has a max weight. Score = sum of check scores within dimension.

**Overall score:** `(total earned / total possible) * 100` — A10 excluded from score (legal risk section only, max = 76 from A1-A9).

**Critical gates (explicit pass thresholds):**
- A2 (Keyboard Navigation) < 6/12 --> automatic FAIL regardless of overall score
- A4 (Color & Contrast) < 5/10 --> automatic FAIL regardless of overall score

**Grade thresholds:**
| Grade | Score | Condition |
|-------|-------|-----------|
| A | >= 85% | All critical gates pass |
| B | >= 70% and < 85% | All critical gates pass |
| FAIL | < 70% | OR any critical gate fails |

VERDICT mapping for run log — **A → PASS, B → WARN, FAIL → FAIL**; a failing critical gate forces
FAIL at any score.

Two things this table used to get wrong. The bands were written `70-84` / `>= 85`, so a real 84.4%
matched neither. And the verdict line said "PASS (A or B), WARN (B with critical gate borderline)",
which both contradicted the field-resolution section below (there, 70-84% maps to WARN, not PASS)
and invented a state the table forbids — B already requires every critical gate to pass, so
"B with a borderline gate" cannot occur, and "borderline" is defined nowhere. A critical gate is
PASS or FAIL; there is no third position.

### 5.3 Report Output

**REQUIRED:** emit the Tool Availability Block (template in `../../shared/includes/codesift-setup.md`) at the top of the report, after the title and before findings. Auditing degraded runs depends on this — do NOT skip it.

```
ACCESSIBILITY AUDIT REPORT
===============================================
Project: [name]
Date: [ISO-8601 date]
Framework: [detected]
Component Library: [detected or "custom"]
Standard: WCAG 2.2 [AA|AAA]
Legal: [ADA Title II | EAA | Section 508 | N/A]
A11y Tooling: [detected tools or "none"]

SCORE: [N]% -- Grade [A/B/C/FAIL]
===============================================

## Critical Gate Status
  A2 (Keyboard Navigation): [PASS/FAIL] ([N]/12)
  A4 (Color & Contrast):    [PASS/FAIL] ([N]/10)

## Dimension Scores
| # | Dimension | Score | Max | Key WCAG Criteria |
|---|-----------|-------|-----|-------------------|
| A1 | Semantic HTML | [N] | 10 | 1.3.1, 4.1.2 |
| A2 | Keyboard Navigation | [N] | 12 | 2.1.1, 2.1.2, 2.4.7 |
| A3 | ARIA Patterns | [N] | 10 | 4.1.2, 4.1.3 |
| A4 | Color & Contrast | [N] | 10 | 1.4.1, 1.4.3, 1.4.11 |
| A5 | Forms & Inputs | [N] | 10 | 1.3.1, 3.3.1, 3.3.2 |
| A6 | Images & Media | [N] | 8 | 1.1.1, 1.2.1, 1.2.2 |
| A7 | Responsive & Zoom | [N] | 6 | 1.4.4, 1.4.10 |
| A8 | Motion & Animation | [N] | 5 | 2.2.2, 2.3.1, 2.3.3 |
| A9 | Reading & Content | [N] | 5 | 2.4.2, 3.1.1, 3.2.3 |
| A10 | Legal Compliance | [N] | 4 | (aggregate) |
| | **Total** | **[N]** | **80** | |

## Findings (sorted by legal risk, then user impact)

### A11Y-001: [Title]
  Dimension: A[N]
  WCAG: [criterion number and name]
  Severity: CRITICAL | HIGH | MEDIUM
  File: [path:line]
  Impact: [who is affected and how]
  Fix: [specific code change or reference to Phase 4 fix]

### A11Y-002: [Title]
  ...

## Legal Compliance Summary
| Standard | Status | Key Gaps |
|----------|--------|----------|
| WCAG 2.2 AA | [PASS / PARTIAL / FAIL] | [summary] |
| ADA Title II | [COMPLIANT / AT RISK / NON-COMPLIANT / N/A] | [summary] |
| EAA | [COMPLIANT / AT RISK / NON-COMPLIANT / N/A] | [summary] |
| Section 508 | [COMPLIANT / AT RISK / NON-COMPLIANT / N/A] | [summary] |

## Automated vs Manual Coverage
  Automated checks (axe-core/pa11y): [N issues found | "not run"]
  Static code analysis: [N issues found]
  Manual verification needed: [N items flagged as CANNOT DETERMINE]

## Per-Component Breakdown
| File | A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8 | A9 | Total | Grade |
|------|----|----|----|----|----|----|----|----|----|----- -|-------|
| [path] | [N] | [N] | [N] | [N] | [N] | [N] | [N] | [N] | [N] | [N]% | [A-FAIL] |
```

### 5.4 Backlog Persistence

If `--persist-backlog` is set or CRITICAL findings exist:

For each CRITICAL or HIGH finding, persist to `memory/backlog.md`:
```markdown
- B-{N} | {file}:{line} | A11Y-{NNN} | {WCAG criterion}: {description} | seen:1 | confidence:{0-100} | source:a11y-audit | {date}
```

**Dedup:** If the same `file|WCAG criterion` combo exists, increment `seen:N` and update the date.

### 5.5 Save Report

Save to: `zuvo/audits/a11y-audit-YYYY-MM-DD.md` — at the **project root** (`zuvo/` resolves via `git rev-parse --show-toplevel`; override `$ZUVO_OUTPUT_DIR`. See `../../shared/includes/report-output-location.md`).

### 5.6 Propose Next Actions

| Finding | Action | Command |
|---------|--------|---------|
| Critical gate A2 failure | Fix keyboard navigation | `zuvo:build fix keyboard traps in [component]` |
| Critical gate A4 failure | Fix contrast | `zuvo:build update color tokens for WCAG contrast` |
| Multiple A3 ARIA issues | Fix ARIA patterns | `zuvo:build add ARIA attributes to [component]` |
| A5 form issues | Fix form accessibility | `zuvo:build add form labels and error association` |
| No a11y tooling | Add eslint-plugin-jsx-a11y | `zuvo:build add eslint-plugin-jsx-a11y` |
| Broad failures (Grade C/FAIL) | Full multi-agent UI review | `zuvo:ui-design-team [path]` |
| DX12-DX17 also failing | Run design-review | `zuvo:design-review [path]` |

---

## Completion Gate Check

Before printing the final output block, verify every item. Unfinished items = pipeline incomplete.

```
COMPLETION GATE CHECK
[ ] A11y tooling detection printed
[ ] Critical gates printed: A2 (Keyboard) and A4 (Contrast)
[ ] Per-component score table present with all A1-A9 dimensions
[ ] Findings sorted by legal risk first
[ ] Report saved to zuvo/audits/
[ ] Run: line printed and appended to log
```

## Completion

After completing the audit, print:

```
A11Y-AUDIT COMPLETE
-----
Components audited: [N]
Standard: WCAG 2.2 [AA|AAA]
Score: [N]% -- Grade [A/B/C/FAIL]
Critical gates: A2=[PASS/FAIL] A4=[PASS/FAIL]
Findings: [N] CRITICAL, [N] HIGH, [N] MEDIUM
Fixes generated: [N] (if --fix)
Legal: [status summary]
Run: <ISO-8601-Z>	a11y-audit	<project>	<score>%	-	<VERDICT>	-	<N>-dimensions	<NOTES>	<BRANCH>	<SHA7>	<INCLUDES>	<TIER>
-----
```

### Validity Gate (REQUIRED — print BEFORE Run line, AFTER retro append + append-runlog)

```
VALIDITY GATE
  required_tool_calls:
    get_file_tree: [<N> | NOT_CALLED]
    search_text: [<N> | NOT_CALLED]
    search_symbols: [<N> | NOT_CALLED]
    search_patterns: [<N> | NOT_CALLED]
    audit_scan: [<N> | NOT_CALLED]
    react_tools: [<result> | not_required | NOT_CALLED]
  postamble:
    retros_log_appended: [yes(bytes_added=N) | NOT_APPENDED]
    retros_md_appended: [yes(entry_count=N) | NOT_APPENDED]
    verify_audit_pass: [yes(<verified>/<total>) | NOT_RUN | REJECTED]
  gate_status: [PASS | FAIL]
```

If `gate_status = FAIL` → VERDICT = INCOMPLETE. Append the Run line via the retro-gated wrapper (NOT direct `>> runs.log`):

```bash
printf '%b\n' "$RUN_LINE" | ~/.zuvo/append-runlog
```


### Retrospective (REQUIRED)

Follow the retrospective protocol from `retrospective.md`.
Gate check → structured questions → TSV emit → markdown append.
If gate check skips: print "RETRO: skipped (trivial session)" and proceed.

After printing this block, append the `Run:` line value (without the `Run: ` prefix) to the log file path resolved per `run-logger.md`.

**Field resolution:**
- `CQ_SCORE`: `<score>%` (overall percentage)
- `Q_SCORE`: `-` (not applicable)
- `VERDICT`: `PASS` (>= 85%), `WARN` (>= 70% and < 85%), `FAIL` (< 70%, or any critical gate fails)
- `TASKS`: `-`
- `DURATION`: `<N>-dimensions` (number of dimensions scored, typically 10)
- `NOTES`: `WCAG2.2-[AA|AAA] [N]-findings [legal-status]` (max 80 chars)

---

## Next-Action Routing

| Finding | Action | Command |
|---------|--------|---------|
| Keyboard traps, missing focus | Fix keyboard navigation | `zuvo:build [description]` |
| Contrast failures | Fix color tokens | `zuvo:build [description]` |
| Missing ARIA on components | Fix ARIA patterns | `zuvo:build [description]` |
| Form a11y gaps | Fix form accessibility | `zuvo:build [description]` |
| Broad design issues | Multi-agent UI review | `zuvo:ui-design-team [path]` |
| Surface-level DX checks | Design consistency audit | `zuvo:design-review [path]` |
| Security concerns surfaced | Security audit | `zuvo:security-audit [path]` |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.