|
| 1 | +--- |
| 2 | +name: ibm-a11y-pr-remediation |
| 3 | +description: Scan every frontend surface touched by the current PR/branch for IBM Equal Access Level 1 accessibility issues and fix all in-scope violations by default. Discovers changed files, maps them to routes/components/states, runs both axe and IBM engines, remediates until both are green (or only documented baselines remain), and reports back. Use when the user asks to check, scan, or clean up accessibility for "this PR", "my branch", or "my changes" and wants fixes applied, not just a report. For a single scoped audit report without a default fix pass, use ibm-a11y-level1-audit; for a route batch scan only, use ibm-a11y-route-scan. |
| 4 | +disable-model-invocation: true |
| 5 | +--- |
| 6 | + |
| 7 | +# IBM Level 1 PR Accessibility Remediation |
| 8 | + |
| 9 | +Scope is **IBM Equal Access Level 1 only**. **Default mode is fix, not report-only.** Scan every frontend surface touched by the PR/branch and remediate all in-scope issues until both engines are green (or only documented baselines remain). |
| 10 | + |
| 11 | +This skill is a PR-scoped orchestrator. It does not duplicate detailed engine/pattern guidance — read the linked skills for that: |
| 12 | + |
| 13 | +- [ibm-a11y-testing-guide](../ibm-a11y-testing-guide/SKILL.md) — which engine/test layer to use, POUR checklist, axe-vs-IBM gaps, Radix/AG-Grid gotchas, baselines. |
| 14 | +- [ibm-a11y-route-scan](../ibm-a11y-route-scan/SKILL.md) — Python scanner options for ad-hoc route batches. |
| 15 | +- [ibm-a11y-level1-audit](../ibm-a11y-level1-audit/SKILL.md) — Level 1 criteria references and report template, useful when the user wants a formal audit report for the PR instead of (or in addition to) fixes. |
| 16 | +- [frontend-i18n](../frontend-i18n/SKILL.md) — accessible names / UI strings must go through i18n. |
| 17 | + |
| 18 | +## Mandate |
| 19 | + |
| 20 | +1. Diff the PR (or current branch vs its merge base) for `src/frontend/**` changes. |
| 21 | +2. Map changed files → UI surfaces → routes / components / states to scan. |
| 22 | +3. Run **both** axe (Jest where applicable) and IBM Equal Access (Playwright `page.runA11yScan` and/or `scripts/a11y/a11y_scan.py` — see `ibm-a11y-testing-guide` / `ibm-a11y-route-scan`). |
| 23 | +4. **Fix every in-scope Level 1 violation** in the changed surfaces. Do not stop at a findings list unless the user says **report only** (in that case, hand off to `ibm-a11y-level1-audit`). |
| 24 | +5. Re-scan until assert mode passes. Add/update a11y specs when coverage is missing. |
| 25 | +6. Report what changed, commands run, and any baselined/deferred debt. |
| 26 | + |
| 27 | +Do **not** invent new tag names, silently disable scans, or expand into IBM Level 2/3 unless asked. |
| 28 | + |
| 29 | +## Progress checklist |
| 30 | + |
| 31 | +``` |
| 32 | +IBM L1 PR A11y: |
| 33 | +- [ ] 1. Collect changed frontend files |
| 34 | +- [ ] 2. Map files → surfaces / routes / states |
| 35 | +- [ ] 3. Scan (IBM + axe) |
| 36 | +- [ ] 4. Fix all in-scope violations |
| 37 | +- [ ] 5. Add/update tests if needed |
| 38 | +- [ ] 6. Re-scan assert-green |
| 39 | +- [ ] 7. Report back |
| 40 | +``` |
| 41 | + |
| 42 | +## 1. Collect changed frontend files |
| 43 | + |
| 44 | +Prefer the PR merge base when a PR exists; otherwise the branch merge base vs `main`/`master`. |
| 45 | + |
| 46 | +```bash |
| 47 | +# PR number known |
| 48 | +gh pr diff <n> --name-only | grep -E '^src/frontend/' || true |
| 49 | + |
| 50 | +# Current branch vs upstream default |
| 51 | +BASE=$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD origin/master) |
| 52 | +git diff --name-only "$BASE"...HEAD -- 'src/frontend/**' |
| 53 | + |
| 54 | +# Include uncommitted work when the user is mid-change |
| 55 | +git diff --name-only HEAD -- 'src/frontend/**' |
| 56 | +git diff --name-only --cached -- 'src/frontend/**' |
| 57 | +git ls-files --others --exclude-standard 'src/frontend/**' |
| 58 | +``` |
| 59 | + |
| 60 | +Include: |
| 61 | +- `src/frontend/src/**/*.{tsx,ts,jsx,js,css}` (UI) |
| 62 | +- `src/frontend/tests/a11y/**` (existing coverage) |
| 63 | +- Locale files only when they change accessible names / labels |
| 64 | + |
| 65 | +Skip pure non-UI churn unless it affects a11y (e.g. test helpers that change focus / ARIA). If **no** frontend files changed, say so and stop. |
| 66 | + |
| 67 | +## 2. Map files → surfaces |
| 68 | + |
| 69 | +For each changed file, identify: |
| 70 | + |
| 71 | +| Change type | Scan target | |
| 72 | +|-------------|-------------| |
| 73 | +| Page / route | That route + meaningful states (empty/populated/modal/mobile) | |
| 74 | +| Shared component (`TableComponent`, dialogs, menus) | **Every** consumer page that uses it — not only the file you touched | |
| 75 | +| Primitive | Jest axe on the primitive + any Playwright surface that embeds it | |
| 76 | +| Spec / baseline only | Re-run that spec; no product fix unless it fails | |
| 77 | +| `a11y_routes.json` | Update static coverage; run static or route scan | |
| 78 | + |
| 79 | +List interactive controls and states (default, empty, populated, open modal / menu, selected row, error, mobile). Prefer existing specs under `src/frontend/tests/a11y/`. |
| 80 | + |
| 81 | +## 3. Scan (both engines must pass) |
| 82 | + |
| 83 | +Automated a11y is not one tool — see `ibm-a11y-testing-guide` for the full engine comparison and gotchas. Summary: |
| 84 | + |
| 85 | +- **axe-core** — Jest `axe()` (`@/utils/a11y-test`), jsdom-only. |
| 86 | +- **IBM Equal Access** — stricter on ARIA structure and keyboard semantics. Playwright `page.runA11yScan(label)` for stateful surfaces (modals/menus/selected/editing); `scripts/a11y/a11y_scan.py` for default-loaded page only. |
| 87 | + |
| 88 | +```bash |
| 89 | +cd src/frontend |
| 90 | +RUN_A11Y=true RUN_A11Y_ASSERT=true npx playwright test tests/a11y/<feature>.a11y.spec.ts --project=chromium --workers=5 |
| 91 | + |
| 92 | +# Python scanner playwright deps are NOT in default uv sync. |
| 93 | +# One-time: uv run --with playwright playwright install chromium |
| 94 | +uv run --with playwright python scripts/a11y/a11y_scan.py \ |
| 95 | + --url http://localhost:3000 \ |
| 96 | + --routes /settings/<route> \ |
| 97 | + --out /tmp/a11y.json --markdown /tmp/a11y.md --timeout-ms 45000 |
| 98 | +``` |
| 99 | + |
| 100 | +`RUN_A11Y=true` runs the scan; `RUN_A11Y_ASSERT=true` fails on new violations. After changing a shared component, re-scan every page that uses it. |
| 101 | + |
| 102 | +For component-only changes: |
| 103 | + |
| 104 | +```bash |
| 105 | +cd src/frontend |
| 106 | +npx jest path/to/<name>.a11y.test.tsx --runInBand |
| 107 | +``` |
| 108 | + |
| 109 | +Do not invent findings — prefer scanner output plus manual Level 1 spot checks scanners miss (keyboard trap both ways, focus restore, 320px reflow, color-not-only). |
| 110 | + |
| 111 | +## 4. Fix all in-scope Level 1 violations |
| 112 | + |
| 113 | +Default: **fix**. Only list proposed fixes without editing if the user asked **report only** — then hand off to `ibm-a11y-level1-audit` for the formal report format. |
| 114 | + |
| 115 | +Rules: |
| 116 | +- Prefer semantic HTML over ARIA. |
| 117 | +- Follow the Langflow patterns in `ibm-a11y-testing-guide` (AG Grid, Radix `asChild`, focus restore, icon-only `aria-label`). |
| 118 | +- Route new UI strings / `aria-label`s through i18n (`t(...)`, all locale files) per `frontend-i18n`. |
| 119 | +- Keep fixes minimal; do not refactor unrelated UI. |
| 120 | +- Do **not** silently disable scans. Use IBM baselines under `src/frontend/tests/a11y/baselines/` only for documented framework debt. |
| 121 | +- Map each issue to a Level 1 WCAG/IBM id; defer anything listed as Level 2/3 in the criteria guide (`ibm-a11y-level1-audit/references/ibm-level1-criteria.md`) unless the user expands scope. |
| 122 | + |
| 123 | +### Manual Level 1 spot checks (when relevant) |
| 124 | + |
| 125 | +- **2.1.1 / 2.1.2:** Tab and Shift+Tab; Escape closes overlays; no trap. |
| 126 | +- **2.4.3 / 2.4.7:** Focus order matches visual order; focus ring visible. |
| 127 | +- **1.4.10:** 320px / ~400% zoom — no essential horizontal scroll. |
| 128 | +- **1.4.1:** Status/errors not color-only. |
| 129 | +- **3.3.1 / 3.3.2:** Errors in text and tied to fields; inputs labeled. |
| 130 | + |
| 131 | +## 5. Tests / coverage |
| 132 | + |
| 133 | +| Surface | Spec | |
| 134 | +|---------|------| |
| 135 | +| Static routes | `static-routes.a11y.spec.ts` (+ `scripts/a11y/a11y_routes.json`) | |
| 136 | +| Auth | `auth-pages.a11y.spec.ts` | |
| 137 | +| Core pages | `core-pages.a11y.spec.ts` | |
| 138 | +| Data-rich | `files.a11y.spec.ts`, `api-keys.a11y.spec.ts`, `global-variables.a11y.spec.ts` | |
| 139 | +| Other data-rich | `data-rich-routes.a11y.spec.ts` | |
| 140 | + |
| 141 | +If you fixed a state with no scan, add one (and keyboard tests for custom keyboard behavior) following `files.a11y.spec.ts` / `api-keys.a11y.spec.ts` patterns. |
| 142 | + |
| 143 | +Tag every Playwright a11y test `@release` plus a domain tag (`@workspace` / `@api` / `@database` / `@components` / `@starter-projects`). Import `test`/`expect` from `../fixtures`. |
| 144 | + |
| 145 | +## 6. Re-scan and report |
| 146 | + |
| 147 | +Re-run the same scans with `RUN_A11Y_ASSERT=true`. Each finding → `fixed` | `baselined` | `open`. |
| 148 | + |
| 149 | +When done, state: |
| 150 | +- Changed frontend files considered |
| 151 | +- Surfaces / states scanned |
| 152 | +- Fixes applied (files + what) |
| 153 | +- Commands run — whether **both** axe and IBM ran and both reported zero |
| 154 | +- Specs / baselines added or updated |
| 155 | +- States skipped and why |
| 156 | +- Remaining risk or accepted limitation |
0 commit comments