# Audit And Fix

> Closes the audit→edit→verify loop. Runs an accessibility audit, applies fixes to source code, and re-audits to confirm. Prefers live-DOM auditing via a browser MCP when available; falls back to static HTML audit when not.

- Skill: `langgenius/audit-and-fix` (Agent Skill)
- Install (CLI): `npx skillmds@latest add langgenius/audit-and-fix`
- Raw SKILL.md: https://api.skillmd.com/api/skills/langgenius/audit-and-fix/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: langgenius (https://skillmd.com/u/langgenius)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/langgenius/audit-and-fix

---


You close the accessibility loop. The user points you at something with a11y issues; you find them, fix the source, and verify the fixes resolved without introducing new violations.

You have **two flows**, and which one you use depends on whether a browser MCP is connected:

- **Live DOM (preferred)** — fires when a browser MCP (chrome-devtools-mcp, playwright-mcp, puppeteer-mcp) is available. The audit runs against the rendered page, catching SPA content, web-font contrast, and post-mount ARIA state.
- **Static fallback** — fires when no browser MCP is connected. The audit runs against HTML files or strings only.

Pick by checking which `mcp__*` tools are available to you in this session. If you see chrome-devtools / playwright / puppeteer tools, use the live flow. If not, use the static fallback. Don't ask the user to install a browser MCP — fall back silently and note in the report that some categories of issue (rendered-only) won't be caught.

## When to invoke

The user says any of: "fix the a11y issues in X", "audit and fix", "make this accessible", "verify the contrast fix landed", or hands you a violation report and asks you to apply it.

## Live-DOM flow

1. Invoke the `audit-live-page` prompt from the AccessLint MCP with `mode: "fix"` and the target URL. The prompt owns: navigate → inject IIFE via `audit_browser_script` → run via the browser MCP's evaluate → collect via `audit_browser_collect` → map violations to source components → apply edits.
2. Before the prompt applies edits, confirm scope with the user (which components are in-bounds, what files are off-limits).
3. After the prompt finishes, run `audit_diff(audit_name: <same name>)` to re-collect a fresh audit and verify the diff shows fixed violations and zero new ones. Re-inject is unnecessary on the same browser session — pass `inject: false` to `audit_browser_script` for the verification call.

### Mapping violations to source files (live-DOM only)

Live-DOM violations may include a `Source: <file>:<line>[:<col>] (Symbol)` line — this is the JSX literal location read from React DevTools fibers. Use that as the **first** signal when picking which file to edit:

1. **`Source:` line present** → open that file at that line. If multiple locations are listed (separated by `←`), the first is the JSX literal; the rest are enclosing components. Use the `Symbol` to disambiguate when the same line renders multiple similar elements.
2. **No `Source:` line** → fall back to the existing heuristics: stable hooks (`data-testid`, `id`, `aria-label`), visible text, then tree position via grep.

Source mapping requires a React dev build with the JSX `__source` transform (default in CRA, Next dev, Vite + React). For non-React pages, production builds, or any case where the field is absent, the fallback heuristics still apply — don't bail.

## Static fallback flow

Steps:
1. **Baseline**: `audit_diff({ path: "<target>", format: "compact" })`. The first call establishes a baseline and returns the full audit. Note the violations marked `Fixability: mechanical` — those have authoritative `Fix:` directives.
2. **Plan the edits**: confirm scope with the user. For each violation, identify the source location:
   - Selector and HTML snippet point at the rendered output.
   - Grep the codebase for stable hooks (`data-testid`, `id`, `aria-label`, visible text) to find the source file.
   - `Source:` lines are **not** available in static audits — they only ride out of the live-DOM flow.
   - For `Fixability: contextual` or `visual`, do **not** invent content — leave a `TODO` comment with the rule ID and a one-line ask for the developer.
3. **Apply**: edit source files with the standard `Edit` tool. Use the `Fix:` directive verbatim for mechanical fixes. Group edits in the same file into one operation.
4. **Verify**: `audit_diff({ path: "<target>", format: "compact" })` again. Same key, same baseline; the diff shows what landed. Confirm:
   - All targeted violations appear in the `-fixed` bucket.
   - The `+new` bucket is empty (or your edits introduced something new — investigate).
   - Use `quick_check` for a final pass/fail summary if the user wants the one-line answer.

## Fixability rules

The engine tags every rule with one of:

- **mechanical** — the `Fix:` directive (e.g. `add-attribute alt=""`) is authoritative. Apply verbatim.
- **contextual** — content needs human input (e.g. an actual `alt` description). Do **not** invent. Leave a `TODO` with the rule ID and the question the developer needs to answer.
- **visual** — needs visual judgment (e.g. compliant color choices). For contrast, suggest a hex change that preserves hue and verify with a re-audit; for layout/spacing, leave a `TODO` for the developer.

When in doubt about a rule, call `explain_rule({ id: "<rule-id>" })` for full guidance and `browserHint` (which tells you whether a screenshot or inspect would help disambiguate).

## When to bail

Don't apply fixes if:
- The user hasn't confirmed scope and the change touches files outside the obvious target.
- More than ~10 mechanical fixes are pending — the user should review the plan before mass-edits.
- A single violation has no `Fix:` directive — that means it needs human judgment; leave a `TODO`, don't guess.

## Output

Per cycle, briefly report:
- What was audited and what flow was used (live vs static).
- Number of violations found, by impact.
- What was applied (file + rule + directive) and what was deferred (`TODO`s left, with reasons).
- The final `audit_diff` result.

If anything failed verification, name it and stop. Do not iterate silently.

