Skip to content

LiveSeptember 23, 2026 · one session

Sense Check

Judges whether the alt text, links, headings and labels on a page mean something, and sends the unclear ones to a person.

I built Sense Check for the part of accessibility testing that automated checkers leave to people: whether alt text says what an image shows, whether a link says where it goes, whether a heading describes its section. Rules settle what is certain, Jev judges the rest, and anything Jev is unsure about goes to a person. It is a first pass, not an audit, and it says so.

WCAG success criteria it reads for
8
certain problems settled by rules
13
kinds of typed question Jev answers
6
outcomes: fine, fix, or a person checks
3
Jev requests a page at most, four at a time
11
tests: a fixture page, a fake Jev, a local server
33
a report is kept, so a refresh costs nothing
5 min
records stored
0

Architecture

Five parts, without a database.

My role: Product owner and developer. I researched the gap, set the brief and shipped it to production, with Claude Code as my AI pair programmer.

  • src/lib/extract.ts

    The page read like a screen reader: alt text, accessible names, headings with the prose after them, labels. Hidden parts skipped.

  • src/lib/sense.ts

    The rules, the batched Jev questions, the confidence gate and the report.

  • src/lib/transport.ts

    The fetcher shared with WP Front Door: private addresses refused before the request and inside the socket's DNS lookup.

  • src/lib/injection.ts

    Page text written to steer AI readers is kept away from Jev and flagged for a person.

  • src/app

    next/form, a streamed loading state, a report grouped by what each finding says, and a JSON endpoint.

  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind CSS 4
  • node-html-parser
  • Vitest
  • Vercel
  • Jev (TypeSafe AI)

Why it exists

Checkers find the missing alt text, not the useless one

Deque's coverage report found that automated tools catch 57% of accessibility issues by volume, yet raise issues for only 16 of the 50 WCAG 2.1 AA success criteria. Whether alt text, a link or a heading means something has always been left to a person, and the European Accessibility Act has covered e-commerce in the EU since June 28, 2025.

What it asks

  • Images: would this alt text tell someone what the image shows, or where its link goes? Is it a file name, a generic word, a keyword list, a copy of the caption?
  • Links: can a person tell where it goes from its text and its sentence, and could the text mislead them?
  • Headings: does each one describe the section after it? Form fields: does the label say what to enter?

How it decides

Rules for what is certain, Jev for the judgement calls

A missing alt attribute, a file name as alt text, a link with no name, an empty heading, a field labelled only by its placeholder, a page with no language: rules settle those and never ask Jev. Everything else goes to Jev in batches, each question pointing at its item by path, and the answer's probability decides what happens next.

Confidence gating

  • 70% or more likely fine: counted as fine
  • 30% or less: reported as a fix, with what is wrong
  • In between: marked for a person to check, with Jev's probability shown

Without a key

  • The rules run alone, generic link text is marked for checking, and the report says how many items were left unjudged

Before release

What testing changed before release

Fixed before release

  • The first real run, on a WordPress.org plugin page, reported the core image lightbox's images as missing alt text: they have no src and no alt until the lightbox opens. Hidden parts and images a script fills in are now skipped
  • A linked image that is the whole link was reported twice, as an image and as a nameless link; it is now one finding
  • A dropdown's options leaked into its label; a label now leaves out the control inside it

Readable reports

  • The W3C's deliberately inaccessible demo page gives 38 findings; grouped by what they say, they read as five cards

Built to be run by strangers

A fetcher that cannot be turned on anyone

Addresses

  • Only public addresses on standard ports, checked before the request and again inside the socket's own DNS lookup; redirects followed by hand, each hop checked
  • Ten checks a minute per address and at most twenty checks of one site in ten minutes, whoever asks, on each server instance

The Jev key

  • At most eleven Jev requests a page, under a daily budget, and reports kept five minutes
  • Page text that addresses AI readers is kept away from Jev and flagged for a person

Tests and delivery

A fixture page with one of every problem

The extraction and the rules are tested against a product page built to hold one of each problem; the Jev path against a fake Jev that records every request, so the tests prove no page text ever reaches a question.

Checks before shipping

  • Vitest, TypeScript strict, ESLint and a production build, on every push through GitHub Actions
  • Live checks after deploying: HTTP to HTTPS, the security headers, a WordPress.org plugin page and the W3C demo page, and every refusal: loopback, cloud metadata, a decimal-encoded loopback, a non-standard port, credentials in the address

Hosting

  • Vercel, from a private GitHub repository; no database and no paid service

Growth

Skills I sharpened.

Accessibility
WCAG 1.1.1, 1.3.1, 2.4.2, 2.4.4, 2.4.6, 3.1.1, 3.3.2 and 4.1.2; accessible names computed the way a screen reader reads them.
AI engineering
Jev (TypeSafe AI): fan-out over a page's items, and confidence-gated routing to human review.
Security
SSRF prevention with a guarded socket lookup, prompt-injection screening, per-site and per-address limits, a daily key budget.
Next.js 16
App Router, next/form, a streamed loading state, a grouped server-rendered report, a route handler.
Testing
Vitest with a fixture page, a fake Jev that records requests, and a local server for the transport.