Product design skills

references/audit.md

A supporting file of the ultra11y skill.

Audit existing code → WCAG report

Goal: produce a dated, reliable WCAG 2.2 AA compliance report. The engine decides the automatable subset; the AI agent adjudicates the judgment criteria (verify --manual, gated) and routes the rendering criteria to scan; the gates stop any hallucinated non-conformity.

The loop

  1. Scope it. Which files / components? HTML, JSX/TSX and Vue/Svelte/Astro components (.vue/.svelte/.astro) are walked by default; add server templates (Twig, ERB, Handlebars…) with --ext .twig,.erb. Test/spec/story markup (*.test.*, *.spec.*, *.stories.*, __tests__/) is excluded by default — it is bad-by-design and never shipped; pass --no-default-excludes (or name the file) to audit it anyway. .vue/.svelte/.astro are audited as SOURCE templates: slots, snippets and dynamic bindings are invisible, so their findings are flagged preliminary and the run carries a scope.sourceTemplate caveat — audit the rendered output to confirm (step 3, and references/rendered.md).
  2. Run the engine:
    node scripts/ultra11y.mjs audit "src/**/*.html" --json > audit.json
    or on a snippet: node scripts/ultra11y.mjs audit - < page.html --json. The AuditResult classes each success criterion as C / NC / NA (static) or manual (rendering / judgment, listed in residualRisks). It also records the repo's declared language(s) as scope.langs (the primary <html lang> subtags seen, most frequent first, e.g. ["fr"]) — the repo signal --lang auto resolves from downstream.
  3. Triage the results:
    • engine NC = confirmed candidates (each finding cites file:line);
    • manual needs-rendering criteria (contrast 1.4.3, focus visible 2.4.7, reflow 1.4.10…) → route to scan, never silently C. Note: contrast on inline literal colours is now decided statically (1.4.3 turns NC for that subset); contrast via external CSS or variables stays residual (→ dynamic tier);
    • manual judgment criteria (alt relevance under 1.1.1, link purpose 2.4.4, reading / tab order…) → the AI agent adjudicates them from context via verify --manual (gated).
  4. Decide each applicable criterion: C, NC or NA (with a justification). For a criterion's detail and grounding: node scripts/ultra11y.mjs criteria 1.1.1.
  5. Render the report:
    node scripts/ultra11y.mjs report --in audit.json --out audits
    audits/wcag-YYYY-MM-DD.md (5 sections, see references/methodology.md); section 2 renders one auditor conformance block per NC criterion (theme, criterion + official wording, test(s), WCAG mapping + level, finding, expected state, verification, file:line occurrences), grouped by severity — the SAME block prd and tickets emit (see references/prd.md), so report and backlog never drift. For a country standard, add --standard rgaa (see references/standards.md). Pass --lang to match your conversation; without it, auto resolves the audit's scope.langs → the standard's default locale → English. Add --json to report for a machine summary ({path, conformancePct, date, standard}) instead of just the path.
  6. Check integrity:
    node scripts/ultra11y.mjs check --report audits/wcag-YYYY-MM-DD.md
    Fails if a section is missing, a cited criterion does not exist, or an NA is unjustified.
  7. High assurance (optional): references/verify.md — prove every non-conformity is real before you ship.

The normative page sample (échantillon) — country-standard audits

A file-tree audit answers "is this markup conformant?"; a country-standard audit (RGAA, Section 508…) is normatively defined over a representative page sample, not the whole repo. Declare that sample once in .ultra11yrc.json:

{ "standard": "rgaa",
  "sample": {
    "pages": [
      { "id": "accueil", "name": "Page d'accueil", "url": "http://localhost:3000/" },
      { "id": "contact", "name": "Contact", "url": "http://localhost:3000/contact" },
      { "id": "compte", "name": "Mon compte", "url": "http://localhost:3000/compte", "auth": true, "storageState": ".auth/user.json", "notes": "connecté" }
    ],
    "transverse": ["header", "navigation principale", "pied de page"]
  } }
  • sample.pages[] are the audited URLs (each may sit behind auth with a per-page storageState); transverse names the elements audited on every page (header, nav, footer, modals…). The storageState path is used but its content is never read into any output.
  • Lint the coverage: node scripts/ultra11y.mjs sample check reports which required page kinds the active standard's sampleMethodology expects but the sample lacks (RGAA: accueil, contact, mentions légales, déclaration d'accessibilité, plan du site, aide, authentification…). Advisory (exit 0) unless the sample block is malformed (exit 2).
  • Scan the sample: scan --sample --merge audits/audit-latest.json iterates every page, keeps each finding's page name + auth flag as provenance, and merges the rendered verdicts in (see references/dynamic.md).
  • Partial-audit honesty: a --standard rgaa report produced without a merged sample scan is flagged partial — a CLI warning + a report banner naming the needs-rendering criteria that were not tested. Say the audit is partial rather than implying full coverage.

Golden rules

  • Never invent a non-conformity: every NC must cite a real, resolvable element (check verifies it).
  • Residual is explicit, never silently C: an unproven needs-rendering criterion goes to scan; a judgment criterion the AI agent adjudicates via verify --manual (gated). Any criterion still undecided stays in the "to assess manually" section with a recorded reason.
  • The report's automatic static-check pass rate covers only the machine-decidable subset; full WCAG conformance requires your manual review (it is not a conformance rate).

On this page