audit (EXPERIMENTAL)

auditAccessibility(agent.describe({ styles: true })) turns the affordance map into findings. It is the lint the map made obvious: every element with handlers should have a name, a role, and enough contrast and size to use — and because the map is the framework's own record of its wiring, a finding here is a real defect, not a scraper's guess.

import { enableAgentInterface, auditAccessibility } from 'tosijs'

const agent = enableAgentInterface()
const report = auditAccessibility(agent.describe({ styles: true }))
report.failed   // 0 when clean
report.findings // [{ rule, severity, message, record, index }]

Pure over the description — no DOM, so it runs on a map that arrived over a wire, in a test, or in CI. Pass styles: true to describe() or the contrast rule has nothing to measure and skips itself (it says so).

The rules

rule what it catches why
anonymous-affordance a wired element with no accessible name, text, or value a screen reader announces "button"; an agent sees <div>
unnameable-action a handler that is an anonymous function (ƒ) nothing can invoke or describe it but a click
missing-role a non-semantic tag (div/span) wired to act assistive tech has no idea it is a control
contrast text/background below the WCAG AA ratio measured with tosijs's own Color; needs styles: true
target-size interactive element below 24×24 (WCAG 2.5.8) too small to hit reliably; toggles exempt
label-hidden-by-placeholder a control whose only name is its placeholder the name vanishes the moment the user types

Findings carry the record and its index, so a caller can jump straight to the element — or hand the pair to schematicSVG's flags to draw them.

Known divergence (tosijs-floorplan#4). target-size and "is this interactive" are currently implemented twice — here, and in the vendored renderer that draws the same map — and the two have drifted: this module counts href as interactive and exempts a link named by aria-label; the renderer does neither. So an icon-only <a href onClick aria-label="Buy"> at 20×20 audits clean while the drawing flags it, and a nameless 16×16 <a href> does the reverse. Reconciliation has to happen upstream (src/schematic.ts is machine-vendored) — see tosijs-floorplan#4. Until it lands, trust this module's verdict for target-size: it has the accessible name, which the renderer does not.

EXPERIMENTAL. Ships with the agent surface; rules and shapes may change.