vivekprojectsearshot
← projects
AIAccessibility

Earshot

A pipeline that scans real websites for accessibility barriers, proposes automated fixes, and verifies each one against the literal narration a screen reader would produce.

Tech
TypeScript, Node.js, Playwright, axe-core, Fireworks AI, Zod
Date
Jul 24, 2026
Status
Hackathon Build
Links
Repository

Automated accessibility scanners like axe-core catch roughly a quarter to a third of real barriers, they'll pass alt="image123" without blinking, and can't tell if a page's reading order actually makes sense to a blind user. The rest needs a human with a screen reader, which doesn't scale. Working with a teammate over a hackathon, I built Earshot, a pipeline that scans a real site, proposes automated fixes, and verifies each one by converting the page into the literal narration a screen reader would produce and asking an LLM whether a blind user could actually understand and navigate it, refusing outright to claim a site is "fixed" or "compliant" anywhere in its output.

Architecture

Verification, Not Just Scanning

Every target runs through two graders: axe-core for rule violations, and an LLM comprehension judge that reads a rendered screen-reader transcript, built by walking Playwright's accessibility-tree snapshot and rendering it as literal narration ('heading level 1', 'image, unlabeled'), and scores 1-5 whether the page's purpose and navigation are actually clear from that narration alone. Gaps are never skipped; an unlabeled element renders explicitly as unlabeled, because the gaps are the signal a screen reader user actually experiences.

Patch and Rollback

Fixes come from two tiers: a deterministic tier for mechanical issues (missing lang, skip links, duplicate IDs) with zero model calls, and an LLM tier that proposes attribute-level DOM patches, enforced through a hard-coded allow-list so a hostile page's content can never get a model to inject anything beyond an accessibility attribute. After patching, both graders re-run, and the pipeline diffs the actual set of violations, not just the count, and automatically reverts any patch that introduced a new one.

Technical Challenges

A verifier bug marked every non-throwing patch revert as successful even when the DOM had shifted underneath it and the revert silently no-op'd, caught by asking directly whether reverting actually restored the page and fixed in a follow-up commit. A deterministic 'add a landmark region' fix that looked obviously safe actually made a real government site's violations worse, and the set-diff verification step, not a naive before/after count, is what caught it. Running the tool against its own results dashboard turned up a real accessibility bug in its own UI: zero axe violations but a failing comprehension score, because a value and its label weren't programmatically associated, something no axe rule checks for at all.

Results

Run against five real targets, the pipeline proposed dozens of patches; only a small fraction survived verification and stayed applied, the rest were automatically reverted for introducing a new violation, or the site's violation count held flat. That low keep-rate is the honest, checked-in result, and it's the argument for why verification has to be automatic: a patch that looks correct in isolation regularly isn't once it's actually re-checked against the live page.

Other

  • Every proposed fix ships as a reviewable patch, a diff, an evidence file, and a real pull request against the target, rather than an unverifiable claim of compliance.
  • Built and shipped in under three hours across a 2-person hackathon team.