---
name: velin-a11y-scan-fix
description: Interpret a11y scan findings and diagnostics. Review-only: recommend official --fix / --fix-dry-run only when finding.fixable and scan-policy SAFE gates allow. Candidates ≠ Apply; links/* detect-only; never invent ids/labels/paths.
---
# A11y Scan Fix Guidance

## Purpose
Interpret scanner findings and diagnostics; recommend official SAFE Apply only when gates allow. Candidates ≠ Apply.

## Domain
R · category `accessibility`

## Capabilities
- `review.a11y`

## Permission
`review-only`

## Allowed actions
- READ
- ANALYZE
- RECOMMEND

## Forbidden actions
- WRITE
- APPLY
- ROLLBACK
- ACCEPT
- DEFER
- NOTE
- ACKNOWLEDGE
- CATALOG
- MANIFEST
- CLASSIFY
- invent-target

## Stop conditions
- SR-03
- SR-11

## Agent role / risk
Fixer · risk `med`

## Workflow
1. ANALYZE/VALIDATE only (`permission: review-only`).
2. Apply checklist below.
3. Unclear → STOP (SR-11/SR-03 as listed on skill).
4. Never rewrite-Apply, invent targets, or skip reuse on build handoffs.

## Checklist
- [ ] Triage scan findings
- [ ] Prefer existing a11y patterns
- [ ] Note Detect ≠ Apply: IDREF / nested-interactive / positive-tabindex / empty-link / focus-outline / scrollable-pre / tab-missing-controls / `links/local-href-target` / `links/local-fragment-target` are not auto-fixed
- [ ] Link diagnostics: use structured `diagnostic` field (href, resolved path, reason, candidates) — machine-readable; do not parse `message` alone
- [ ] A11y ID diagnostics: `duplicate-id` / `aria-idref-target` / `aria-controls-target` expose `diagnostic` (occurrences, `idref-not-found` / `idref-empty` / `idref-ambiguous`, similar-id candidates) — Review only; never invent or rename ids
- [ ] Empty-link / positive-tabindex / focus-outline diagnostics: read `diagnostic` flags — never invent accessible names from URLs; never rewrite tabindex; static CSS ≠ runtime focus proof
- [ ] Button / input / nested-interactive diagnostics: `diagnostic` shows checked name/label sources and outer/inner elements — never invent labels/ids; nested interactive needs a developer structure decision (no auto-repair)
- [ ] role-button-contract / heading-order / scrollable-region diagnostics: read `reason` + `runtimeUnverified` / real heading lines — never invent tabindex, key handlers, or heading levels; static CSS/HTML ≠ runtime proof
- [ ] Candidate / ambiguous / related duplicate-id hints are not Apply targets; `fixable` stays false
- [ ] Candidate suggestions are review-only (`confidence: exact` is not an auto-fix); never treat candidates as Apply targets
- [ ] Recommend `--fix` / `--fix-dry-run` only for findings with `fixable: true`; dry-run `autoFix.plans` (current→new) are authoritative for Apply — a finding alone is never Apply permission
- [ ] No finding `action` field and no separate `fixability{}` — use `fixable` + Dry-Run + Apply gates only
- [ ] `a11y/skip-link` auto-fix requires existing `id="main"`; Detect marks fixable only then
- [ ] `velinstyle scan --only links` — Detect only for local href / fragment integrity
- [ ] `a11y/interactive-aria-hidden` applies to the control host, not decorative children with `aria-hidden`
- [ ] Theme override: forcing light while OS prefers dark requires explicit `data-velin-theme="light"` / `data-velin-color-scheme="light"` — not “no theme attribute”
- [ ] Link integrity: do not invent path rewrites or fragment ids from scan findings or diagnostic candidates; generator/site link issues stay in generator/site layer (not HTML bulk-fix)
- [ ] Uneindeutig → STOP SR-03
- [ ] VALIDATE/ANALYZE

## Best practices
- BP-V01, BP-A01 (when a11y), BP-T02 (when theme)

## Anti-patterns
- Silent WRITE/APPLY
- Treating review success as license to auto-map Tailwind residuals

## Inputs / Outputs
- Inputs: html
- Outputs: report, diff
