Skip to content

Matterhorn Protocol — Moving the Machine/Human Line

Purpose

The Matterhorn Protocol 1.1 (PDF Association) is the definitive conformance-testing model for PDF/UA-1 (ISO 14289-1). It decomposes the standard into 31 checkpoints containing 136 failure conditions. Crucially, Matterhorn itself pre-classifies each failure condition by who can test it:

  • 87 failure conditions — determinable by software alone
  • 47 failure conditions — usually require human judgment
  • 2 failure conditions — no test defined (23-001 digital signatures, 27-001 navigation)

That 87/47 split is not a law of nature. It reflects the state of deterministic tooling circa 2013. Matterhorn’s authors drew the line where a rule-based checker (parse the file, inspect the structure) stops and where understanding the content begins — is this alt text actually correct? is this really a heading? does this table’s structure match its visual layout?

The thesis of this document: modern multi-model LLM ensembles can understand content with measurable confidence. That lets us move a large fraction of the 47 “human” conditions into a new machine-assisted tier — automated when models of different architectures agree with high confidence, and flagged for human review only when they disagree or express low confidence. We are not removing the human; we are shrinking the human’s queue from “every document” to “only the genuinely ambiguous cases.”

This document:

  1. Lists all 31 checkpoints and their traditional classification.
  2. Sorts every checkpoint into fully mechanical / partially mechanical / purely human.
  3. Re-classifies with an LLM-ensemble lens: which “human” checks become automatable.
  4. Drafts an automation plan for every fully- or newly-automatable check.

This is a planning document only. No code changes are proposed inline — the roadmap at the end sequences the implementation work.


What we already have (build on, don’t rebuild)

The repo already contains the deterministic half of this problem:

  • tools/pdf-inventory/src/census — a deterministic PDF/UA-1 scanner. Tier-0 (pikepdf structural signals) + Tier-1 (veraPDF PDF/UA-1 profile) with zero AI cost.
  • clause-class-map.json / .md — every machine-checkable veraPDF clause mapped to a fix class: A = structural/automatable (101 clauses), B = needs human-authored text (5 clauses), C = source rebuild. This is the software-checkable 87 conditions, expressed at veraPDF clause granularity (106 clauses).
  • flyer-tagger / api-pdf vision pipeline — Claude vision routed through Bedrock (ZDR) already generates alt text, detects figures, tags equations, infers reading order.

So the automation story is: veraPDF covers the deterministic 87; the LLM ensemble is the new engine that attacks the 47. The clause-class map’s Class B rows are precisely the “machine can detect the absence, but only a human (or now an LLM) can author/verify the content” cases — the natural first targets for ensemble automation.


Classification framework

We use four tiers instead of Matterhorn’s two:

TierSymbolMeaning
Fully mechanical🟩 MDeterministic parse/inspect gives a definitive pass/fail. veraPDF territory. No judgment.
Partially mechanical🟨 PSoftware detects presence/structure but cannot judge correctness/appropriateness. The classic “machine finds the field is empty; human decides if the value is right.”
LLM-automatable🟦 LTraditionally human, but content-understanding by a multi-model ensemble can decide with confidence; low-confidence/disagreement escalates to a human. This is the line we are moving.
Purely human🟥 HRequires real-world context, subjective judgment, or perceptual testing that no model can currently settle (or has no defined test).

A checkpoint can span tiers (e.g. the existence of alt text is 🟩 M; its correctness is 🟦 L). We classify each checkpoint by its dominant unresolved condition.


The 31 checkpoints — full classification

Legend: Trad. = Matterhorn’s original class (Machine / Human / Mixed / None). Today = what our stack (veraPDF + census) already automates. With ensemble = target tier once the multi-LLM layer ships.

#CheckpointTrad.TodayWith ensembleNotes
01Real content is tagged / artifacts markedMixed🟨 P🟦 LveraPDF flags untagged content & Suspects; deciding whether an element is real content vs. decoration is a vision/semantic call.
02Role mappingMixed🟩 M🟩 MCircular/remapped/standard-tag checks are fully deterministic (7.1-5..7).
03Flickering / flashingHuman—🟨 PRendered-page frame analysis can detect flash >3Hz; edge cases stay human.
04Color & contrastHuman—🟦 LRender page → sample text vs background → WCAG ratio. Text/bg separation is the hard part; ensemble + rendering solves most.
05Sound (audio hazard / alternatives)Human—🟦 LAudio is embedded digital data: multi-ASR transcription + transcript-vs-audio match + auto-play/control detection are automatable. Only equivalence/prosody/intent is a soft flag.
06Metadata (title, lang, XMP)Mixed🟩 M🟩 MPresence & schema are deterministic (5-*, 7.1-8/9, 6.2-1). Whether the title is meaningful → 🟦 L.
07Dictionary keysMachine🟩 M🟩 MPure structural.
08OCR validationHuman🟨 P🟦 LDetecting image-only pages is deterministic; verifying OCR fidelity to the image is ensemble OCR cross-check.
09Appropriate tags (semantics match content)Mixed🟨 P🟦 LveraPDF checks tag nesting legality; whether a P should be an H2, or a Table is really tabular, is semantic → ensemble.
10Character mappings (ToUnicode)Machine🟩 M🟩 MDeterministic (7.21.7-*, .notdef).
11Declared natural languageMixed🟨 P🟦 LPresence of Lang is deterministic; whether the declared language matches the actual text is language-ID (ensemble/library).
12Stretchable characters (math delimiters)Human—🟦 LWhether a stretched glyph carries meaning is a vision/semantic judgment.
13Graphics (figures have correct alt)Mixed🟨 P🟦 LFlagship ensemble case. veraPDF finds missing Alt (7.3-1, Class B); ensemble authors & cross-verifies the alt text.
14Headings (hierarchy)Machine*🟨 P🟦 LStructural rules (7.4.4-*) are deterministic; whether the visual headings were tagged as headings, and level correctness, is semantic.
15Tables (structure matches layout)Human🟨 P🟦 LCell/row/header nesting is deterministic (7.2-*, 7.5-*); whether headers/scope match the visual table is vision-semantic.
16Lists (structure matches visual)Human🟨 P🟦 LL/LI/LBody nesting deterministic; “is this visually a list?” is semantic.
17Mathematical expressionsMixed🟨 P🟦 LFormula tag presence deterministic; correct alt/MathML for the expression is ensemble (we already tag equations via vision).
18Page headers / footers (pagination artifacts)Human🟨 P🟦 LWhether running heads are correctly artifacted vs. real content is a repeated-position + semantic call.
19Notes & referencesMachine🟩 M🟩 MNote ID presence/uniqueness deterministic (7.9-*).
20Optional contentMachine🟩 M🟩 MDeterministic (7.10-*).
21Embedded files (Desc)Machine*🟨 P🟦 LPresence of Desc deterministic (7.11-1, Class B); quality of description → ensemble.
22Article threadsHuman🟨 P🟦 LBead/flow order presence deterministic; whether reading order is correct is ensemble reading-order.
23Digital signaturesNone—🟥 HNo test defined (23-001).
24Non-interactive forms (labels)Human🟨 P🟦 LMissing TU/tooltip deterministic (7.18.1-3, Class B); correct human-readable label → ensemble.
25XFAMachine🟩 M🟩 MDynamic-XFA prohibition deterministic (7.15-1).
26Security (encryption doesn’t block AT)Machine🟩 M🟩 MP key check deterministic (7.16-1).
27NavigationNone—🟦 LStandard is under-specified (“should”/“appropriate”), so Matterhorn defined no test — but outline presence, outline↔heading-tree correspondence, and destination validity are deterministic. Only navigation depth/usefulness is subjective.
28AnnotationsMixed🟨 P🟦 LTagging/Contents/Print flag deterministic; link alt text correctness → ensemble (7.18.5-2, Class B).
29Actions (no accessibility traps)Human🟨 P🟥 HAction presence detectable; whether an action harms AT users often needs human context.
30XObjects (no reference XObjects)Machine🟩 M🟩 MDeterministic (7.20-*).
31Fonts (embedding, glyphs, encoding)Machine🟩 M🟩 MDeterministic (7.21.*) — the largest deterministic cluster.

* Matterhorn labels the checkpoint “machine testable” for its structural conditions, but each contains a semantic condition that is really human/ensemble.

Tally

Tier after ensembleCheckpoints
🟩 Fully mechanical (ships today via veraPDF)02, 06(structural), 07, 10, 19, 20, 25, 26, 30, 31 — 10
🟦 LLM-automatable (the line we move)01, 04, 05, 08, 09, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 24, 27, 28 — 18
🟨 Partially mechanical (detect gap, ensemble authors fix)03 — 1 (plus the structural halves of the 🟦 rows)
🟥 No defined test / subjective residue23, 29 — 2

Bottom line: the deterministic tier already handles ~10 checkpoints outright (and the structural half of ~10 more). The ensemble tier targets 18 checkpoints that Matterhorn consigned to humans. Only ~2 checkpoints sit in the residue — and note why: 23 (signatures) has no test defined by the standard and no accessibility semantics to check, and 29 (actions) is a context/intent judgment. Where the standard declined to define a test but the objects are inspectable (like 27 Navigation), we define the operational test ourselves (outline ↔ heading-tree correspondence + destination validity) rather than punting to a human. There is almost no check that is genuinely impossible to automate.


Part A — Fully mechanical checks (automation = ship/verify what exists)

These require no LLM. They are the veraPDF PDF/UA-1 profile, already wired into tools/pdf-inventory/src/census and the clause-class-map. Automation plan is operational, not research:

  1. Run veraPDF PDF/UA-1 profile on the document → machine-readable clause report.
  2. Map each reported clause through clause-class-map.json to a fix class (A/B/C).
  3. Class A auto-fix — structural repairs (role-map normalization, MarkInfo, Lang, metadata title, font embedding, ToUnicode, .notdef removal, Note IDs, XObject incorporation). Our flyer-tagger / pdf-enhance engines already perform most of these.
  4. Emit a per-clause pass/fail into the conformance report (already produced per pass).

Checkpoints fully covered: 02, 07, 10, 19, 20, 25, 26, 30, 31, plus the structural conditions of 06. Nothing new to invent — the work is coverage verification: a golden-corpus test asserting each deterministic clause is exercised, and a gap report for any Matterhorn condition in the 87-set that veraPDF does not implement.

Deliverable: matterhorn-coverage.json — one row per failure condition, columns {condition_id, verapdf_clause, covered: bool, fix_class}. This makes the “87 covered” claim auditable instead of assumed.


Part B — The multi-LLM ensemble engine (the movable line)

This is the core new capability. It converts 18 “human” checkpoints into automated-with-confidence checks.

B.1 Design principles

  • ZDR is a hard constraint. Customer PDFs may only be sent to Zero-Data-Retention / DPA-covered inference. Bedrock is that envelope — and it hosts models from many vendors, not just Anthropic: Amazon (Nova/Titan), Meta (Llama), OpenAI, Mistral, Cohere, AI21. All are covered by Bedrock’s data protection, so we get cross-vendor diversity without leaving ZDR. Gemini remains excluded (not ZDR); any non-Bedrock cloud LLM is excluded for the same reason.
  • Cross-vendor juries are mandatory — never confirm a finding with a same-vendor model. Two Claude models (or two Nova models) share training data, architecture lineage, and therefore blind spots: they tend to be confidently wrong in the same places, which fabricates agreement and defeats the entire point of an ensemble. Every jury must draw its jurors from distinct vendors. Concretely:
    • Juror composition rule: a verdict is only “agreed” if it is corroborated across ≥2 different vendors (e.g. Anthropic Claude + Meta Llama + Amazon Nova, or Claude + OpenAI). Two models from the same vendor count as one vote for consensus purposes.
    • Vision checks (alt text, contrast, tables, math, reading order): pick VLMs from different vendors on Bedrock — Claude (Anthropic) and a Nova/Llama-vision or OpenAI-vision juror.
    • Deterministic jurors (non-LLM): WCAG contrast math, language-ID libraries (fastText/ CLD3), repeated-position detectors. These have rule-based failure modes uncorrelated with any LLM, so they are the strongest independent juror where a deterministic signal exists — always include one when applicable.
    • Tie-breaker is a deterministic juror where one exists, otherwise a third-vendor model — never a second model from a vendor already on the panel.
  • Structured verdicts, not prose. Every juror returns {verdict: pass|fail, confidence: 0..1, rationale, proposed_fix?} via a forced tool/schema.
  • Consensus gate. Automate only when jurors agree above a confidence threshold. Disagreement or low aggregate confidence → flag for human with all rationales attached.
  • Verify, don’t just generate. For content the ensemble authors (alt text, labels), a separate juror is prompted to refute the proposed text against the rendered image — adversarial verification, mirroring the workflow patterns already used in this repo.
  • Cost tracking (non-negotiable). Every juror call logs {op_type, model, tokens, est_cost, timestamp} to the existing cost_tracking mechanism. Ensemble checks are the most expensive path; they must be reportable and budgetable.

B.2 Confidence & escalation model

per juror: v_i ∈ {pass, fail}, c_i ∈ [0,1], vendor_i
agreement: same verdict corroborated across ≥2 DISTINCT vendors
(same-vendor models collapse to a single vote)
aggregate: C = weighted mean of c_i (weight deterministic jurors highest)
decision:
cross-vendor agree AND C ≥ 0.85 → AUTO-PASS / AUTO-FIX (record, no human)
cross-vendor agree AND 0.60 ≤ C < 0.85 → AUTO with SOFT FLAG (batch human spot-check)
disagree OR C < 0.60 OR single-vendor → HARD FLAG → human queue (rationales shown)

Thresholds are per-check-type and tuned against a human-labeled golden set (below). The census tool already has a golden-test harness (131 pytest) — extend it with human-adjudicated labels so we can measure ensemble precision/recall per checkpoint and prove the false-negative rate is acceptable before auto-fixing anything.

B.2a “Human judgment” is not a category — “the best available judge” is

A crucial reframing that governs everything below. Most checks past the deterministic floor require judgment — but judgment is not synonymous with a human. The realistic human alternative for at-scale document remediation is a contracted, often non-expert, sometimes non-native-English reviewer deciding, e.g., “is this TOC deep enough?” or “does this alt text describe the image?” That reviewer:

  • makes mistakes, inconsistently, and at a rate you cannot measure or audit (their judgment is opaque and varies by person, fatigue, and incentive);
  • is slow and expensive per item;
  • has no reproducible reasoning trail.

A cross-vendor LLM ensemble deciding the same question:

  • makes mistakes too — but at a rate we measure against a golden set, per check type, and can drive down with better prompts/jurors;
  • is consistent, fast, and cheap;
  • emits a rationale per juror, so every verdict is inspectable.

So the test for automation is never “does this require judgment?” (almost everything does) — it is “which judge is more reliable, and can we prove it?” For a judgment call where the ensemble matches or beats the contractor baseline on the golden set, the ensemble is the better judge and should decide. Preferring a human there is sentiment, not quality.

This collapses the “human-only” tier further. A human is genuinely required only for reasons unrelated to judgment quality:

  1. Accountability / legal attestation — someone must sign the conformance claim and carry liability. That is one sign-off per document, not a per-check judgment task.
  2. Genuinely contested / no-reliable-judge cases — where neither a human nor a model is dependable (rare, truly ambiguous intent), so a human is placed on record by choice.

Everything else that “needs judgment” routes to the ensemble by default, with the confidence gate deciding when to also show a human — and even then the human is confirming a proposal, not originating one. Where we currently soft-flag to a human “because it’s a judgment call,” that flag should be justified by measured ensemble unreliability on that check, not by the mere presence of judgment.

B.3 Per-checkpoint automation plans (🟦 L)

Each plan states: input signal → jurors → decision → fix.

13 / 21 / 24 / 28 — Alternative text (figures, embedded files, form labels, link text) Clause-class B cases; the highest-value group.

  • Input: rendered figure/region image + surrounding text context; existing Alt/TU/ Contents if any.
  • Jurors (cross-vendor): Claude-VLM (Anthropic/Bedrock) + a different-vendor VLM on Bedrock (Amazon Nova, Llama-vision, or OpenAI-vision) describe independently; a third juror from a third vendor is given both descriptions + the image and asked “do these agree and does either accurately describe the image?” (adversarial). All jurors are ZDR-safe via Bedrock; no two are from the same vendor.
  • Decision: agreement + high confidence → write the alt text (Class B fix). Disagreement → human, with both candidates pre-filled so the human edits rather than authors.
  • Existing assets: flyer-tagger already generates alt text via Bedrock vision — this adds a second architecture + the consensus gate on top.

04 — Color & contrast

  • Input: render page to raster; for each text run, sample glyph pixels vs. local background.
  • Jurors: (1) deterministic WCAG ratio computation (authoritative when text/bg separable); (2) VLM to resolve ambiguous cases (text over gradient/image, anti-aliasing, knockout text).
  • Decision: deterministic pass/fail when contrast is unambiguous; VLM only for the hard overlaps. This is mostly mechanical once rendered — hence 🟨/🟦 boundary.

09 / 14 — Appropriate tags & heading hierarchy (semantic)

  • Input: rendered page + tag tree + text runs with font-size/weight/position features.
  • Jurors: deterministic heading-candidate detector (font-size clustering) + VLM reading the page as a human would (“what are the headings and their levels?”). Compare against the actual tag tree.
  • Decision: mismatch with agreement → propose retag (Class A structural fix, no new text); disagreement → flag.

15 / 16 — Tables & lists (structure matches visual)

  • Input: rendered region + current structure tree.
  • Jurors: VLM reconstructs the logical grid/list from the image; compare to tagged structure (headers, scope, row/col counts — we already compute 7.2-41/42/43).
  • Decision: structural divergence → propose corrected TH/scope/L nesting; ambiguous merged/nested tables → human.

11 — Declared natural language matches text

  • Input: extracted text per structure region.
  • Jurors: deterministic language-ID library (fastText/CLD3) + one LLM for short/mixed passages. Compare detected language to declared Lang.
  • Decision: mismatch with high confidence → propose corrected Lang; short/ambiguous → flag.

08 — OCR fidelity

  • Input: image-only page + its text layer (if any).
  • Jurors: run 2 independent OCR engines + a VLM transcription; cross-compare. High agreement → accept/repair text layer; divergence (tables, handwriting, low-res) → flag.

17 / 12 — Math expressions & stretchable characters

  • Input: rendered formula region.
  • Jurors: VLM → LaTeX/MathML + spoken-math alt; second model verifies round-trip render matches. (We already tag equations as Figures with spoken-math via FLYER_TAGGER_MATH_ALT.)
  • Decision: agreement → emit Formula + MathML/alt; disagreement → flag.

18 — Running headers/footers artifacted

  • Input: text runs repeated at same position across pages.
  • Jurors: deterministic repeated-position detector (strong signal) + VLM confirms it’s chrome not content.
  • Decision: high-confidence repeats → mark Artifact; first/last-page anomalies → flag.

22 — Reading order / article threads

  • Input: geometry of tagged content + rendered page.
  • Jurors: deterministic column/flow detector + VLM natural reading order. Compare to tag order (we already have a reading-order path in flyer-tagger + /inspect).
  • Decision: agreement on reorder → apply; multi-column/complex → flag.

05 — Sound (audio hazards & alternatives) Embedded audio is digitized data we can analyze directly — it is not “real-world” content.

  • Input: the embedded media stream + any author-supplied transcript/caption + the media clip dictionary (auto-play, controls).
  • Deterministic jurors: does audio auto-play without a control? (WCAG 1.4.2, structural); sound-event detection (speech vs. music vs. alarm vs. silence).
  • Cross-vendor ASR jurors: 2–3 independent ZDR ASR engines (e.g. self-hosted Whisper + AWS Transcribe) transcribe; keep the consensus transcript, and treat inter-engine disagreement as the low-confidence region.
  • Verification jurors: (a) transcript-vs-audio match — align the author’s supplied transcript/caption to the ASR consensus; a mismatch is a hard, provable failure. (b) spelling/word-validity + language-ID on the transcript. (c) ensemble semantic-relevance: is the transcript coherent and on-topic for the surrounding document?
  • Decision: missing/mismatched transcript, or auto-play without control → auto-fail with the evidence. Present a draft transcript/caption (the ASR consensus) for the author to confirm. Soft-flag to human only for the residue below.
  • Residue (soft flag, not auto-decided): equivalence adequacy (does the text alternative convey equivalent understanding?), prosody-dependent meaning (sarcasm/emphasis/emotion), and whether meaningful non-speech sound is load-bearing vs. ambient — these are intent calls the ensemble proposes but a human confirms.

27 — Navigation (bookmarks / document outline) The standard (§7.17) is under-specified, so Matterhorn defined no test — we define one.

  • Input: the document outline (bookmark) tree + the tagged heading tree + page count.
  • Deterministic jurors: (a) does an outline exist when the doc exceeds a page threshold we set and has tagged headings? (b) does the outline correspond to the heading tree — same entries, order, and nesting? (c) do all bookmark destinations resolve to valid locations?
  • Ensemble juror: are the bookmark labels meaningful (match/summarize their target heading, not “Untitled”/blank)?
  • Decision: missing outline, or outline that doesn’t mirror the headings, or dead destinations → auto-fail, and auto-draft an outline from the heading tree (mirror to a sensible default depth, e.g. H1–H3) for the author to approve.
  • Residue (soft flag): navigation depth/granularity appropriateness for this document’s purpose — proposed by default, adjustable by a human.

01 — Real content vs. artifact

  • Input: untagged marked-content runs + rendered position.
  • Jurors: VLM decides “is this meaningful content or decoration?” + deterministic heuristics (position, repetition, size).
  • Decision: confident decoration → Artifact; confident content → tag; else flag.

03 — Flicker (partially mechanical)

  • Input: rasterize any animation/OCG toggles or multi-state annotations to frames.
  • Method: frame-diff flash-rate analysis (>3 flashes/sec = fail). Deterministic; VLM only for judging whether a detected flash is a genuine hazard.

Part C — The accountability residue (not a judgment-quality residue)

Per B.2a, this bucket is not “things machines judge worse than humans” — for judgment quality, a measured ensemble generally beats a contracted reviewer. A human remains in the loop here for reasons unrelated to who judges better: legal accountability (someone must sign the conformance claim) and a rare tail of genuinely contested cases where no judge is reliable. Route these to a human checklist and record the verdict (the human_verification append-only table already exists from the audit Phase-0 work). Even here the ensemble assists — it pre-loads context and drafts a proposal; the human confirms and, above all, signs.

  • 23 Digital signatures — no Matterhorn test defined (23-001) and no accessibility semantics to inspect. Nothing to automate.
  • 29 Actions — whether a scripted action harms AT users is context-dependent; the ensemble surfaces risky actions with a plain-language prompt but does not clear them.

Note: Sound (05) and Navigation (27) were previously listed here and have both been moved to the ensemble tier (Part B). Audio is analyzable data (multi-ASR transcription, transcript-vs-audio verification, auto-play detection). Navigation objects are fully inspectable (outline ↔ heading-tree correspondence, destination validity) — the standard merely declined to define a test, so we define one. In both cases only a thin subjective tail (equivalence adequacy; navigation depth) is soft-flagged — the same treatment tables and alt text get, not categorical human-only status.

For this bucket, automation = generating the reviewer’s worklist (which conditions apply, with context and a draft pre-loaded), not deciding the verdict.


Part E — Guided human remediation (make the residue fast)

Automation shrinks the human queue; it never empties it. Three buckets always reach a person: hard-flagged ensemble disagreements, soft-flagged medium-confidence auto-fixes needing a spot-check, and the irreducibly human checkpoints (Part C). The goal here is to make that work as fast and low-skill as possible — the user should confirm or correct, never start from a blank page. This applies to both remediation surfaces:

  • PDF — Gevell PDF (apps/web /tags, /inspect) over the flyer-tagger edit-op engine.
  • HTML — Gevell Web (apps/remediate), the fix step after a Gevell Audit scan.

Both should share one guided-remediation UX and one ensemble backend so a fix authored for a PDF figure and the same fix for an <img> are the same interaction. Build the shared pieces in a package (e.g. packages/guided-remediation) consumed by both apps.

E.1 Universal principles

  • Pre-fill, then confirm. Every flagged item arrives with the ensemble’s best proposal (draft alt text, proposed heading level, reconstructed table grid) and each juror’s rationale. The human accepts, edits, or rejects — one click for the common case.
  • One item at a time, ordered by impact. A single focus queue (“3 of 12 remaining”), sorted by severity × frequency, with keyboard-only flow (next/prev/accept/edit). No hunting through a report.
  • Locate, don’t describe. Selecting an issue scrolls/zooms the rendered page (PDF) or highlights the live DOM node (HTML) so the user sees the element in context.
  • Explain in plain language. Each item states the WCAG/PDF-UA rule, why it matters, and who it affects — not the raw clause ID.
  • Optimistic, reversible edits. Apply to the working copy immediately (optimistic UI per the house standard), with undo; persist in the background.
  • Progress is visible. Live conformance meter that recomputes (veraPDF for PDF, axe/audit for HTML) as items are cleared, so the user sees the score climb.

E.2 Guided tasks

Guided alt text (PDF figures / HTML <img>, 13/21/24/28)

  • Show the image large, the ensemble’s draft alt (cross-vendor), and the surrounding context.
  • User confirms or edits inline; a “describe differently” button re-rolls a fresh draft.
  • Decorative toggle → sets Artifact (PDF) / alt="" aria-hidden (HTML) in one click.
  • Live length/quality hints (not empty, not “image of”, not the filename).

Guided reading order (22)

  • Render the page with a numbered overlay of the current order; drag-to-reorder (PDF tag tree / HTML DOM-order proposal). Ensemble proposes the order; user nudges.

Guided headings & structure (09/14)

  • Overlay detected heading candidates with proposed levels (H1→H6); user promotes/demotes. Flags skipped levels and multiple H1s inline.

Guided tables (15)

  • Side-by-side: rendered table vs. the reconstructed grid. User marks header row/column and scope; ensemble pre-guesses. Fixes TH/scope (PDF) or <th scope>/<caption> (HTML).

Guided lists (16) — confirm “this is a list” and its type; one click wraps the structure.

Guided contrast (04) — show the failing pair, measured ratio, and the nearest AA-passing shade in the same hue; user accepts the suggested color or picks another (live re-check).

Guided language (11) — detected vs. declared language per region; accept to set Lang.

Guided forms & links (24/28) — pre-filled field labels / link purpose text; confirm/edit.

E.3 Built-in screen-reader preview (“hear it before you ship”)

A first-class verification tool, not a checkbox — this is how a sighted user perceives what they built:

  • Accessibility-tree playback. Render the document/page to the same tree an AT consumes (PDF: structure tree → text + roles; HTML: the computed a11y tree/accName), then read it aloud in DOM/reading order with the Web Speech API (client-side; no content leaves the browser → ZDR-safe by construction).
  • Announce roles, not just text — “heading level 2, …”, “figure, alt: …”, “table, 3 columns”, “link, …”, “list, 4 items” — so the user hears exactly what a screen-reader user would, including the alt text they just wrote.
  • Sync highlight. As it reads, highlight the current element in the rendered page/DOM so the user connects sound to visual.
  • Jump-by-element (headings, links, tables, figures) to mirror real AT navigation, and a reading-order lint that flags where spoken order diverges from visual order.
  • Ships in both apps from the shared package; also doubles as the reviewer’s tool for the human-residue checkpoints (e.g. confirming a figure’s alt makes sense in flow).

E.4 What guidance does per Part-C checkpoint

Even the irreducibly-human items get assisted, not just dumped on the user:

  • 05 Sound / 29 Actions — surface every media clip / scripted action with a plain-language prompt (“does this audio convey info not in text?”, “does this action move focus unexpectedly?”) and a record-the-verdict control.
  • 23 Signatures / 27 Navigation — checklist with the relevant objects pre-listed; for navigation, offer an auto-generated bookmark/outline draft from the heading tree for the user to approve.

Deliverable: packages/guided-remediation — shared queue model, item renderer, pre-fill adapters (PDF edit-op engine ↔ HTML DOM patcher), and the screen-reader preview — wired into both apps/web (/tags) and apps/remediate, with every human verdict recorded to human_verification.


Part F — Applicability: how often each test actually applies

“How much is automated?” is the wrong denominator if you count all 136 failure conditions equally. Most checkpoints do not apply to most documents. A checkpoint that governs audio description is irrelevant to a text-only memo; a table-header rule is irrelevant to a document with no tables. The honest metric is:

Over a large sample of real documents, of the applicable test-instances (checkpoint × document, counted only where the test has something to judge), what share is fully automated, partially automated (ensemble-assisted, human fallback), and human-only?

Data source

Estimates below are anchored to our own UT System census (tools/pdf-inventory/ census-results/ut-system-2026-08/): ~1,500 higher-ed PDFs sampled, 1,386 machine-checked with veraPDF, per-clause failure frequencies in clause-frequency.csv. Content-type applicability (does this doc have figures? tables? links? forms?) is inferred from the clause frequencies plus Tier-0 structural probes.

Caveat (stated up front): the census counts failure frequency, not applicability. Untagged documents (35% of the corpus) can’t produce table/list structure failures because they have no structure to fail — so structural applicability for tables/lists is understated in the raw data. Where that biases a number, the estimate is nudged up from the raw floor and flagged. These are corpus-informed engineering estimates, not exact measurements — a per-content-type instrumentation pass (planned) would replace them.

Corpus shape — document size distribution

The same 1,500-PDF census, bucketed by page count. This is the population the pipeline economics ride on: cost and speed per page are dominated by where a document sits on this curve, because the expensive work (image-dense cover/marketing pages, vision passes, fixed per-job overhead) is front-loaded and amortizes over interior pages.

Distribution of PDFs by page count (UT System census, N=1,500) Horizontal bar chart. 1 page: 28.3 percent. 2 to 3 pages: 26.5 percent. 4 to 10 pages: 24.7 percent. 11 to 50 pages: 14.2 percent. 51 to 200 pages: 3.9 percent. 201 to 500 pages: 2.3 percent. Over 500 pages: 0.2 percent. Median 3 pages, mean 18.1, longest 605. Distribution of PDFs by page count (N=1,500) 1 28.3% 2–3 26.5% 4–10 24.7% 11–50 14.2% 51–200 3.9% 201–500 2.3% 500+ 0.2% pages per document → share of corpus · median 3 · mean 18.1 · p95 104 · max 605
PagesShareCumulative
128.3%28.3%
2–326.5%54.8%
4–1024.7%79.5%
11–5014.2%93.7%
51–2003.9%97.6%
201–5002.3%99.8%
500+0.2%100%

What this means for pipeline positioning:

  • The corpus is dominated by short documents — 55% are ≤3 pages, 79.5% are ≤10. A single-page PDF is almost always a cover/flyer/marketing page (image-dense, the most expensive page type), which is why per-page cost is highest at the 1-page end and falls as interior pages dilute it.
  • The long tail is thin but real — only ~6.4% exceed 50 pages and ~2.5% exceed 200. That ~2.5% is the segment where the in-place (preserve) path’s practical ~200-page ceiling bites and the reflow path (which scales to 500+ pages) is the only option. Capacity, not just cost, is a positioning axis: reflow is the default for the long tail.

Per-checkpoint applicability (share of documents the test meaningfully applies to)

Tier = Full (deterministic, no AI, no human) / Partial (ensemble decides, human fallback) / Human (accountability / no defined test). Infer % = this test’s approximate share of the document’s total inference spend — inference only, since compute (rendering, veraPDF, parsing) is a cost you control. Deterministic and human-only tests are therefore 0%; the AI tests sum to ~100%. Absolute anchor (Part G): total inference ≈ $0.07–0.14/doc ≈ ~1¢/page, so a test at “15%” costs roughly 0.15¢/page.

#CheckpointTierApplies ~%Infer %Why (corpus signal / cost basis)
25XFA (prohibition)Full100%0%Deterministic; XFA present in ~0.1% (7.15-1=1).
26Security (prohibition)Full100%0%Deterministic P-key check.
30XObjects (prohibition)Full100%0%Deterministic.
07Dictionary keysFull100%0%Deterministic, universal.
06Metadata (title/lang/XMP)Full100%0%Structural deterministic (meaningful-title is a tiny ensemble add).
02Role mappingFull100%0%Deterministic.
01Real content vs artifactPartial100%~15%Rides the shared page-level VLM sweep.
11Declared languagePartial100%~2%Mostly deterministic lang-ID lib; LLM only on short/mixed text.
04Colour & contrastPartial~100%~5%Mostly deterministic WCAG math on rendered pixels; VLM only for hard overlaps.
09Appropriate tags (semantic)Partial~100%~15%Shared page-level VLM sweep.
31FontsFull~95%0%Deterministic (7.21.*).
10Character mappingsFull~95%0%Deterministic (ToUnicode/.notdef).
22Reading orderPartial~90%~14%Shared page-level VLM sweep + geometry.
14Headings hierarchyPartial~60%~9%Shared page-level VLM sweep.
18Running headers/footersPartial~60%~9%Shared page-level VLM sweep + repeated-position detector.
28Annotations / linksPartial~55%~3%Link-text vision check (tagging itself is deterministic).
27Navigation (bookmarks)Partial~40%~1%Mostly deterministic (outline↔heading); tiny LLM label check.
13Graphics / figures (alt)Partial~37%~15%Dedicated per-figure vision — the main cost concentrator.
16ListsPartial~18%~2%Structure deterministic; VLM confirms “is a list”.
15TablesPartial~15%~4%Dedicated per-table vision (grid reconstruction).
24Non-interactive formsPartial~5%~1%Label-presence deterministic; VLM authors label.
19Notes & referencesFull~5%0%Deterministic ID checks.
08OCR fidelityPartial~5%~2%Rare (5%) but expensive per run (multi-ASR + VLM).
20Optional contentFull~3%0%Deterministic.
21Embedded filesPartial~2%<1%Desc-quality VLM; rare.
23Digital signaturesHuman~2%0%No defined test; no inference.
29ActionsHuman~5%0%Intent judgment; ensemble surfaces but doesn’t decide.
17Math expressionsPartial~1%~1%Dedicated formula VLM; rare.
12Stretchable charactersPartial~1%<1%Subset of math.
03Flicker / flashingPartial<0.5%<1%Frame-diff deterministic; VLM hazard judgment; very rare.
05Sound (audio)Partial<0.5%<1%Multi-ASR + verification; essentially absent in this corpus.

How to read the cost column. Two structural facts dominate:

  1. Shared page sweep is cheap per-checkpoint. Checkpoints 01/04/09/14/18/22 are answered by one page-level vision call that returns all of them at once. They show a meaningful % only because that call is the bulk of per-page cost — but adding one more check to that shared prompt is nearly free. Kill the page sweep on simple text pages (page-gating, Part G) and this whole cluster drops together.
  2. Dedicated per-element vision concentrates cost. 13 (alt text, per figure) and 15 (tables, per table) each spawn their own image call, so their cost scales with how many figures/tables a document has — that’s where spend actually accumulates, even though they apply to only ~15–37% of documents.

Everything marked Full or Human is 0% inference — deterministic checks run on CPU you control, and human-only checks are labor, not tokens. So ~35% of the checkpoints carry the entire inference bill, and within those, alt text + the page sweep are ~80% of it.

The long tail is the story: the checkpoints that Matterhorn calls “human” (subtitles/audio, math, forms, flicker) are exactly the ones that apply to 1–5% of documents or fewer. The checks that apply to almost every document (metadata, fonts, language, structure, contrast, links, real-content) are dominated by deterministic and ensemble-automatable work.

UT corpus evidence — % of documents each test would actually run on

Directly from the census (clause-frequency.csv, ~1,386 machine-checked UT PDFs). “UT evidence” is the count of documents that failed the representative clause(s) for that checkpoint — a hard lower bound on how many documents contain the content the test targets. ”% needing the test” is the applicability estimate (evidence adjusted upward where untagged documents suppress structural failures, as noted). Sorted high → low.

#CheckpointUT evidence (docs w/ representative clause)% of UT docs the test runs on
06Metadata (title/lang/DisplayDocTitle)1,228 lack PDF/UA id; 901 lack DisplayDocTitle; 438 lack title100%
01Real content vs artifact770 (7.1-3) untagged content100%
02Role mapping37 (7.1-5) non-standard tags remapped100%
07Dictionary keysfile-format universal100%
09Appropriate tags (semantic)every tagged doc100%
11Declared language464 (7.2-34) + 38% missing /Lang (Tier-0)100%
04Colour & contrastnot in Tier-1 (needs render); universal~100%
25XFA (prohibition, checked on all)1 (7.15-1) actually has XFA100%
26Security (prohibition)universal100%
30XObjects (prohibition)3 (7.20-2)100%
10Character mappings (ToUnicode)58 (7.21.7-1)~95%
31Fonts (embed/glyph/encoding)521 (7.21.4.2-2) + 467 (7.21.4.1-1)~95%
22Reading ordernot in Tier-1; any multi-element layout~90%
14Headings hierarchy98 (7.4.2-1)~60%
18Running headers/footers70/76 (7.1-1/7.1-2 artifacting)~60%
28Annotations / links690 (7.18.5-2) + 329 (7.18.5-1)~55%
27Navigation (bookmarks)31 (7.2-2 outline lang)~40%
13Graphics / figures (alt)372 (7.3-1) = 27% failing floor~37%
16Lists23 (7.2-20) — understated (untagged)~18%
15Tables149 (7.5-1) + 127 (7.2-42)~15%
08OCR fidelity5% image-only scans (Tier-0)~5%
24Non-interactive forms69 (7.18.4-1) + 49 (7.18.1-3)~5%
19Notes & references8 (7.9-1)~5%
29Actionsrare~5%
20Optional content40 (7.10-1)~3%
21Embedded filesrare~2%
23Digital signaturesrare~2%
17Math expressions1 (7.7-1)~1%
12Stretchable characterssubset of math~1%
03Flicker / flashingnone in corpus<0.5%
05Sound (audio)none in corpus<0.5%

Read this operationally: on a random UT document you run ~10 checkpoints unconditionally (the 100% rows), plus fonts/char-maps/reading-order on nearly all, plus a content-triggered subset — links on ~55%, figures on ~37%, tables on ~15%, and the audio/math/forms/flicker tail on 1–5% or fewer. The expensive LLM work only fires when the triggering content is present, which is the foundation of the cost model in Part G.

Applicability-weighted headline

Weighting each checkpoint by its applicability across the corpus, then splitting each checkpoint’s applicable instances between deterministic (veraPDF), ensemble, and irreducibly- human work:

TierShare of applicable testsWhat it means
🟩 Fully automated (deterministic, no judgment)~74%veraPDF structural + prohibition + file-format checks, plus deterministic navigation (outline ↔ heading correspondence). Ships today / near-term.
🟦 Partially automated (ensemble decides, human fallback on low confidence)~25%Alt text, reading order, table/heading/list semantics, contrast edge cases, form labels, link text, audio transcription, bookmark labels. Mostly auto-resolved; only disagreements/low-confidence reach a human.
🟥 Human-only (no defined test / subjective residue)~1%Digital signatures (no accessibility semantics to test), some action-safety intent judgments, and thin subjective tails (audio equivalence adequacy, navigation depth). Not “machines can’t perceive it.”

So the honest one-liner:

Across a large sample of real higher-ed PDFs, ~74% of applicable accessibility tests are fully automated with no human judgment, ~25% are partially automated (an ensemble makes the call and only escalates the ambiguous cases to a person), and ~1% are irreducibly human.

The human-only tier is now startlingly small because, on inspection, almost nothing is truly untestable — the “human” checkpoints were either under-specified by the standard (navigation), analyzable digital data we hadn’t leveraged (sound), or apply to a vanishing slice of documents (math, flicker). What’s left is essentially digital signatures (which carry no accessibility meaning) and a few intent/equivalence judgments that get proposed by the ensemble and merely confirmed by a person.

Two things sharpen this further:

  1. Deterministic-only (no LLM) already covers ~74%. The ensemble’s job is to attack the ~25% middle band — and it auto-resolves the large majority of that band at high confidence, so the human’s actual queue is far smaller than 25% + 1%. On our confidence gate (auto ≥0.85), the residual hard-flag rate is the fraction of the 25% where vendors disagree — empirically a minority of it.

  2. The per-document view (from the census) agrees. Deterministic-only, 33% of documents need zero human input (Class A + D — the text-only and structurally-simple docs, exactly as expected), ~60% are “near misses” needing only one or two authored items (e.g. a single alt text — the ensemble’s sweet spot), and ~5–7% need a source rebuild (image-only scans) or genuine human judgment. Fold the ensemble in and most of that 60% becomes automated-with-confidence, leaving a single-digit-percent human residue per document.

Document-level summary — what share of files are hands-off

The headline above weights by test. Pricing and staffing care about files: of a random batch of documents, how many come out the far end needing zero human judgment (just a final sign-off), how many need a little human confirmation, and how many hit genuine human judgment? Per your framing, every file still gets a final accountability sign-off — that is not counted as human judgment below (it’s a signature, not a decision).

Document-weighted, folding the ensemble in on top of the census class distribution (33% need zero author input today; ~60% are one or two authored items away; ~5–7% are image-only rebuilds):

Outcome per file~% of filesWhat it means
🟩 Fully automatable~85%Every applicable check resolves deterministically or as a high-confidence ensemble call. No human judgment — only the final sign-off. (The census’s 33% zero-author docs + the large majority of the 60% near-miss docs whose 1–2 authored items the ensemble resolves confidently.)
🟦 Partial~11%Mostly automated, but one or more items get flagged for a human to confirm or correct a pre-filled proposal (an uncertain alt text, an ambiguous table, a low-confidence reading order). Minutes of review, not authoring from scratch.
🟥 Genuine human judgment~4%Contains something that needs a real decision: a complex image-only scan needing a rebuild call, a scripted-action safety judgment, or genuinely contested/ambiguous content.

Why files ≠ tests. The test-level residue is ~1%, but at the file level a small per-item flag rate compounds: a document with ten figures has ten chances to surface one low-confidence alt text. So the “needs a human touch” share is higher per-file (~15% combined) than per-test (~1%) — even though the amount of human work per flagged file is tiny.

Staffing implication: for ~85% of files a person only signs; for ~11% they spend a few minutes confirming pre-filled proposals; only ~4% need real judgment time. The final sign-off is one action per file regardless of tier — bounded, predictable labor you can staff and price directly.

The clean claim for a text-only document

If a document contains only text — no figures, images, charts, tables, forms, math, audio, or video — then every applicable checkpoint is either deterministic or a high-confidence ensemble call (language, headings, reading order, contrast of plain text). Such a document is fully automatable end-to-end, no human step. The census bears this out: the 33% “no author needed” bucket is essentially the text-and-simple-structure population.


Part G — What it costs to run the ensemble (pricing model)

Earlier drafts called the speed/cost advantage “obvious.” It isn’t — it has to be modeled. Here is a bottom-up cost model you can price against. The headline: the LLM cost per document is cents, not dollars, because (a) 74% of checks are deterministic and cost ~$0 in inference, and (b) the expensive vision calls only fire on the fraction of pages/elements that have the triggering content (Part F).

G.1 Where cost comes from

  • Deterministic tier (74% of checks): veraPDF + pikepdf. ~$0 inference — just CPU (fractions of a cent of compute per document). Ignore in pricing.
  • Ensemble tier (25%): vision + text LLM calls. This is essentially all the cost.
  • Human tier (~1%): labor, not inference — priced separately as review time.

Two shapes of ensemble call:

  1. Page-level semantic sweep — one rendered page image answers several checks at once (headings, reading order, contrast flag, artifact/real-content, list/table presence) in a single structured-output call. You pay per (image × juror), not per check — batching checks into one prompt is the single biggest cost lever.
  2. Element-level call — one per figure (alt text), table (structure), equation, or audio clip. Region image + context, per juror.

G.2 Bedrock token prices (per 1M tokens)

Anthropic models on Bedrock are priced per-token the same as first-party (below is from the Claude pricing reference). Cross-vendor Bedrock prices are approximate — verify on the current AWS Bedrock pricing page; the model is parametric, so plug in live numbers.

Juror (Bedrock)VendorInput $/1MOutput $/1MRole
Claude Haiku 4.5Anthropic$1.00$5.00cheap Claude juror
Claude Sonnet 4.6Anthropic$3.00$15.00workhorse juror
Claude Opus 4.8Anthropic$5.00$25.00hard-case escalation only
Amazon Nova LiteAmazon~$0.06~$0.24cheap cross-vendor vote (verify)
Amazon Nova ProAmazon~$0.80~$3.20cross-vendor vision juror (verify)
Meta Llama VisionMeta~$0.70–2.00~$0.70–2.00cross-vendor vision juror (verify)

Image tokens: Claude tokenizes an image at roughly (width × height) / 750. A page rendered at ~1568px long edge ≈ ~1,600 tokens; a figure crop ≈ ~500–900. Opus 4.7+ high-res (up to 2576px) can hit ~4,784 tokens/image (~3× the cost) — render at moderate resolution unless a check needs the detail.

Discounts that apply to bulk remediation:

  • Batch/async inference: ~50% off. A corpus sweep is not latency-sensitive → batchable.
  • Prompt caching: the stable check-instruction/rubric prefix caches at ~0.1× read cost; only the per-page image + varying context pay full price.

G.3 Unit cost per call (cross-vendor 2-juror panel)

Representative panel = Sonnet 4.6 (Anthropic) + Nova Pro (Amazon), with a 3rd-vendor tie-break on the disagreement fraction (~20%). On-demand prices (before batch/cache discounts):

CallInput tokOutput tokSonnet costNova Pro cost2-juror + ~20% tie-break
Page semantic sweep~2,300~500$0.0144$0.0034~$0.021 / page
Alt text / figure~1,200~150$0.0059$0.0014~$0.012 / figure (incl. adversarial verify)
Table structure~1,700~400$0.0111$0.0027~$0.015 / table
Language / link / form (text-only)~600~120$0.0036—~$0.004 / item

With batch (−50%) and prompt caching on the instruction prefix, these drop by roughly half again → page sweep ~$0.010, alt text ~$0.006/figure.

G.4 Per-document rollup (UT averages)

Census averages: ~12 pages/doc (17,611 pages ÷ ~1,486 docs), ~1.5 figures/doc (37% × ~4), ~0.3 tables/doc (15% × ~2).

ComponentVolume/docUnitOn-demandBatched+cached
Page sweeps (gate to complex pages only, ~40%)~5 pages$0.021$0.105$0.050
Alt text1.5 figures$0.012$0.018$0.009
Tables0.3 tables$0.015$0.005$0.002
Language / links / forms~3 items$0.004$0.012$0.006
Total per document~$0.14~$0.07

Page-gating matters most. Sending every page to the ensemble (~12) instead of only content-complex pages (~5) roughly doubles the total. Simple single-column text pages get their reading-order/heading checks confirmed deterministically — don’t pay an LLM for them.

So the LLM cost of goods is roughly 7–14 cents per document, or ~$0.006–0.012 per page — against a human remediation market rate the census cites at $5–8 per page. That is the “obvious” made concrete: ~500–1,000× cheaper per page than manual remediation, before any quality/consistency argument.

G.5 At scale (whole UT System)

UT System discovered ~19,854 PDFs. A full ensemble pass:

ScenarioPer doc19,854 docs
On-demand, sweep every page~$0.28~$5,600
On-demand, page-gated~$0.14~$2,800
Batched + cached + page-gated~$0.07~$1,400

Compare: the census estimates the sample alone (~17,611 pages) at $88k–$141k of manual remediation. Automating the entire discovered corpus costs ~$1.4k–5.6k in inference.

G.6a Per-document cost distribution (whole corpus)

Running the cost model over all 1,500 UT documents individually (using each document’s real pages, tagged, and image_only values; batched+cached unit costs) gives the spread of inference cost per document, expressed in ¢/page:

Statistic¢/page
Max1.57
Mean0.84
Median1.00
Std dev0.31

(For context: min 0.40, p90 1.16, p99 1.55.) The spread is driven almost entirely by three real signals in the data:

  • Tagged docs (965) page-gate well → ~0.55 ¢/page (the low end).
  • Untagged docs (452) need a full-page sweep to infer structure → ~1.15 ¢/page.
  • Image-only scans (83) add OCR on every page → ~1.55 ¢/page (the max).
  • Short documents pull up: page-gating can’t sweep less than one page, so a 1–2 page tagged doc costs like an untagged one — which is why the median (1.0) sits above the mean (0.84).

Caveat — this understates the real tail. The census records content presence, not per-element counts, so figure/table counts are modeled as page-proportional (constant per page). That flattens the figure contribution to ¢/page, so the true corpus std-dev and max are higher than shown — a figure-dense catalog or a data-table-heavy report would sit well above 1.57 ¢/page. Treat these as a conservative floor; the planned per-content-type instrumentation pass (Part F caveat) would replace the modeled counts with measured ones.

G.6b Reality check — modeled vs. actual production cost

The numbers above are a model. Cross-checking against the live cost_ledger (true token cost, estimated_cost_usd, ¢/page from metadata.pageCount/pages) shows the model is optimistic — useful, but a target, not an achieved rate. Actual completed jobs (files carrying page metadata; a recent, small, complexity-skewed slice):

WorkloadFilesmedian ¢/pgmeanmaxblended (Σ$/Σpg)
conversion (full PDF→accessible HTML)880.502.5342.062.44
flyer-tagging (in-place remediation)9610.2141.1340923.70
Matterhorn model (this doc)1,5001.000.841.57~0.8

Conversion’s median matches the model (0.50¢), but its mean is ~3× higher with a fat tail, and flyer-tagging is ~10–30× higher. The gap is explained by five things — not one:

  1. Scope. The model prices checking + targeted fixes. conversion/flyer-tagging do full content extraction, HTML generation, and iterative veraPDF-driven re-tagging — a heavier job.
  2. Model tier. Production runs premium Claude Sonnet/Opus, on-demand; the model assumed a cheap cross-vendor panel (Nova/Haiku) + batch (−50%) + prompt caching — none of which the current pipeline uses. This alone is the ~5× (juror mix) + 2× (batch) swing from §G.6.
  3. Small-doc skew. Metadata-bearing files average ~4 pages (census avg ~12); fixed per-page costs dominate tiny docs — the 42¢/409¢ maxes are 1–3 page complex documents.
  4. Iteration. Conversion logs iterations/batches; flyer-tagging loops until veraPDF-clean. The model assumed ~one pass per check.
  5. Modeled tail is flat. Figure/table counts are page-proportional with no complex-page premium — which is why the model’s max is 1.57 while reality hits 42+.

Takeaway: the ~0.8¢/page figure is achievable only if the ensemble is (a) scoped as check+targeted-fix rather than full re-conversion, and (b) built on the cost levers (cheap cross-vendor jurors, batch, caching, page-gating). Today’s flyer-tagging at ~24¢/page is the status-quo baseline the levers must beat. Data caveat: only 88/2,575 conversion and 96/95 flyer-tagging files carry page metadata (added recently), so this is a small, complexity-heavy slice — a fleet-wide re-baseline is a Phase-0 task.

G.6 The parametric formula (plug in your own numbers)

cost_per_doc =
P_swept × C_page # page-level semantic sweeps
+ N_figures × C_alt # alt text
+ N_tables × C_table # table structure
+ N_items × C_text # language / links / forms / notes
+ escalation_rate × N_hard × C_opus # Opus only on hard/contested cases
where each C_x = Σ_jurors (in_tok×in_price + out_tok×out_price),
× (0.5 if batched) × (cache factor on the prompt prefix)

Sensitivity — the four dials that move the number most:

  1. Page-gating fraction (sweep all pages vs. only complex ones) — ~2× swing.
  2. Juror mix (Haiku/Nova cheap panel vs. Sonnet/Opus) — up to ~5× swing.
  3. Batch vs. real-time — 2× (50% off when batched).
  4. Image resolution — up to ~3× (high-res pages cost triple).

Pricing implication: at a COGS of ~$0.01/page, the ensemble can be priced per-page at a tiny fraction of the $5–8 manual rate and still carry a large margin — or bundled per-document. The dominant variable cost at scale is the human sign-off on the ~1% residue (Part C), not inference. Track inference spend per document in the existing cost_tracking mechanism so the per-doc number is measured, not just modeled — the estimates above are engineering approximations pending a live pilot.


Part D — Roadmap

PhaseScopeOutput
0. Coverage auditMap all 136 conditions ↔ veraPDF clauses ↔ clause-class map.matterhorn-coverage.json; proves the deterministic 87 are covered; lists gaps.
1. Golden label setHuman-adjudicate a corpus (extend census golden harness) with per-condition ground truth.Labeled fixtures → basis for measuring ensemble precision/recall.
2. Ensemble harnessMulti-juror interface — all ZDR (Bedrock), cross-vendor (Anthropic + Amazon + Meta/OpenAI + deterministic), structured verdicts, consensus gate that enforces ≥2-vendor agreement, cost logging.Reusable ensemble.evaluate(check, evidence) service with a vendor-diversity guard.
3. Alt-text pilot (13/21/24/28)Highest-value Class-B checks; adversarial verify; auto-fill + confidence flag.Precision/recall report vs. golden set; go/no-go on auto-fix threshold.
4. Structural-semantic (09/14/15/16/18/22)Retag proposals (no new text) — safest auto-fixes.Retag diffs gated by consensus.
5. Perceptual (04/03/08/17/12)Rendering + OCR + math jurors.Contrast/flicker/OCR/math coverage.
6. Human residueWorklist generator for 05/23/27/29 + soft-flag review queue UI.Human queue shrunk to genuinely ambiguous cases only.
7. Guided remediation (shared)packages/guided-remediation — focus queue, pre-fill adapters (PDF edit-op ↔ HTML DOM patch), locate-in-context, live conformance meter. Wired into apps/web /tags + apps/remediate.One guided UX across PDF & HTML; humans confirm/correct instead of authoring.
8. Built-in screen-reader previewAccessibility-tree playback (Web Speech, client-side/ZDR-safe) with role announcements, sync highlight, jump-by-element, reading-order lint.”Hear it before you ship” verification in both apps.

Success metric

Track the automation rate = (applicable test-instances auto-decided at high confidence) / (applicable test-instances), and the human queue size per document — both weighted by real applicability (Part F), not the flat 136-condition count. Baseline (Part F): ~74% fully automated deterministically, a ~25% ensemble band, ~1% human-only. Target: drive the human queue well below the 25% + 1% ceiling by auto-resolving the ensemble band at high confidence, leaving only genuine vendor-disagreements and the irreducible ~1% for a person — with a measured false-negative rate on the golden set below an agreed threshold (e.g. <2% on alt-text correctness) before any check is allowed to auto-pass without spot-check.


Appendix — Why cross-vendor jurors, not one vendor twice

A single model asked the same question twice tends to be consistently wrong (correlated errors). The same is true of two models from the same vendor: they share training data and architecture lineage, so they share blind spots — they agree confidently on the same mistakes, manufacturing false consensus. Models from different vendors (Anthropic, Amazon, Meta, OpenAI) trained on different data fail in different places, so agreement is genuine evidence and disagreement reliably surfaces the hard cases — exactly the cases that should reach a human.

Because Bedrock hosts all of these vendors under one ZDR/DPA envelope, we get that cross-vendor independence without sending customer content to any non-ZDR provider. That is the mechanism that lets us move Matterhorn’s line without lowering the WCAG/PDF-UA bar: the standard is unchanged; only the cost of checking it drops, and the human is spent only where judgment is genuinely required. The consensus gate enforces this structurally — a finding corroborated only within a single vendor is treated as unconfirmed and routed to a human.

Sources: Matterhorn Protocol 1.1 (PDF Association) · PowerMapper — Matterhorn checkpoint mapping · Silktide — 136 checks still need human eyes · tools/pdf-inventory/src/census/clause-class-map.md (this repo)