Skip to content

Architecture

Wholisphere has two independent surfaces: the scan-and-report pipeline (which finds WCAG issues and renders an honest VPAT from what it found), and the assistive agent — an opt-in tool that adapts a page for the individual end user. It never remediates the site itself and never injects fixes into a visitor’s browser for compliance; it serves the reader who chose to turn it on. Two layers:

┌──────────────────────────────────────────────────────────┐
│ ASSISTIVE RUNTIME CLIENT (end-user tool) │
│ • Browser extension OR embed script (one engine) │
│ • Floating Shadow-DOM landmark widget (AAA) │
│ • Local TTS / STT (Web Speech) — sub-50ms, no network │
│ • Calls the backend only for vision / LLM reasoning │
└──────────────────────────────────────────────────────────┘
│ on demand
┌──────────────────────────────────────────────────────────┐
│ BACKEND API (Cloudflare Workers) │
│ • /v1/describe, /v1/read-page, /v1/intent, … │
│ • Content-addressed response cache (KV): identical │
│ requests (same image + context) skip the paid call │
│ • Multi-model LLM router (Gemini + Claude + Mock) │
└──────────────────────────────────────────────────────────┘

Why the response cache

A naive deploy would call the LLM on every user interaction — slow and expensive at scale. Because an image’s description is identical for everyone, the backend caches each result by a content hash of the image plus its context: the first request for a given image pays for the vision call, and every request after it is served from cache in milliseconds.

PropertyNaive (LLM on every call)Wholisphere (content-addressed cache)
Repeat-image latency800–2500 mscache hit, milliseconds
Vision costone paid call per viewone paid call per distinct image

Multi-model LLM routing

Same prompt, multiple providers. Today: Gemini Flash + Claude Sonnet + Mock. Routing strategy:

  • fast / balanced → Gemini Flash (~30× cheaper per image; fine for 80% of calls)
  • accurate / vision → Claude Sonnet (better small-element + low-contrast OCR)

The router falls through providers on retryable errors (5xx, 429, 529). Adding OpenAI is a one-file change.

Coexistence with native AT

The widget is role="complementary" with aria-label="Accessibility tools". JAWS / NVDA / VoiceOver users find it via the standard landmark navigation key (D in NVDA, VO+U in VoiceOver). They can:

  • Ignore it entirely and continue using their native AT
  • Engage one specific tool (“describe this image please”)
  • Delegate the whole page to the agent

We never override or fake screen-reader output. We’re additive, not replacement.

Audit trail

Every agent action is logged: timestamp, URL, capability invoked, outcome, duration. Logs live in D1 (12 months hot) and R2 (5 years cold). Customers can export as JSON or stream via webhooks. Court-defensible.