Skip to content

Make compare_pdfs coverage fail closed - #184

Merged
silverstein merged 5 commits into
masterfrom
codex/compare-coverage-v013-reconcile-20260904
Sep 4, 2026
Merged

Make compare_pdfs coverage fail closed#184
silverstein merged 5 commits into
masterfrom
codex/compare-coverage-v013-reconcile-20260904

Conversation

@silverstein

@silverstein silverstein commented Sep 4, 2026

Copy link
Copy Markdown
Member

Summary

  • make compare_pdfs degrade semantic, text, and structure coverage when extraction failed, was partial, or page matching is ambiguous
  • prevent no_reported_changes from presenting an all-clear result when material content was not actually compared
  • retain explicit checkbox appearance coverage and document the separately tracked radio appearance-state limitation
  • reconcile the comparison evaluator and frozen oracle identities with current v0.13 source

Why this matters

A comparison can only claim “no changes” for content it truly examined. This change turns skipped, failed, partial, and ambiguous comparisons into visible coverage limitations instead of a false green result.

Verification

Exact head: c743659aea1f792c80c7070fcef1ce58cae54409

  • focused/adjoining VM bank: 8 files, 104/104 passed
  • Mac npm run test:all under Node 22.23.2: 2,813 Vitest passed, 109 declared skips; 62 native passed, 9 platform skips
  • Mac encrypted-PDF/qpdf adjacency: 11/11 passed
  • reproducible share contract: 51 tools, 14 prompts, 122 licensed SBOM components
  • source/share runtime bytes match
  • oracle regeneration is byte-identical
  • git diff --check passes

Scope

No release artifact, benchmark claim, or provider execution is included. The radio-button per-widget appearance-state enhancement remains separately tracked as a lower-priority follow-up.

silverstein and others added 5 commits September 4, 2026 03:46
….0/1.1

The shipped v0.11.0 compare_pdfs engine could report `supported` coverage
and zero changes on pages and fields it never actually compared. Three
truthfulness fixes, all in the engine so every consumer is safe:

Bug 1 — derivePdfComparisonCoverage now inspects each compared page's
Extraction IR status, not just text truncation. A page whose text layer
or extraction failed drops the semantic and text channels to
`unavailable`; a partial one drops them to `partial` (typed
`<SIDE>_TEXT_LAYER_FAILED` / `_EXTRACTION_FAILED` / `_TEXT_LAYER_PARTIAL`
/ `_EXTRACTION_PARTIAL`). A scanned or image-only page is never scored as
fully text-covered again. Truncation degradation is retained.

Bug 2 — any `repeated_ambiguous` alignment (a repeated/template page the
aligner refuses to pair, whose content is therefore never compared) now
degrades semantic, text, and structure to `partial` with a typed
`REPEATED_PAGE_AMBIGUITY` reason. Coverage derivation takes the
alignments; buildPdfComparison computes them first. A document of
identical repeated pages is no longer trivially green.

Bug 3 — resolved by documented exclusion. `appearance_state` (the widget
/AS) is captured on the observation but provably redundant with `value`:
the pinned pdfjs 5.4.624 resolves a button widget's fieldValue from its
/AS, so `value` already reflects the displayed state (measured for
checkboxes and radios in the new test). Comparing it would only
double-report every checkbox/radio value change, so it stays out of the
compared properties with a comment explaining why.

Because coverage output is wire-visible, the comparison engine/schema
version is bumped 0.1.0 -> 0.2.0 and 1.0 -> 1.1, in server and share
output schemas; the mcp-contract tool-contract hash is updated with a
changelog note. validatePdfComparisonSemantics now asserts the new
invariant: a repeated_ambiguous alignment implies its affected channels
are not `supported` and carry the reason.

equivalence_claim stays false; no_reported_changes stays fail-closed and
now also trips when a channel is degraded.

New deterministic fixtures + test/compare-pdfs-coverage.test.js prove the
failed/partial-page, repeated-page, and appearance-state cases. Existing
compare-pdfs assertions that accepted over-optimistic `supported`
coverage (mixed-content fixtures draw a rectangle -> extraction_status
partial) were updated intentionally with in-test comments. Server
changes mirrored into pdf-toolkit-mcp-share/. Docs reconciled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codex diff review found the documented-exclusion over-claimed: pdfjs folds
/AS into fieldValue for checkboxes, but for radio groups fieldValue is the
shared /V and per-widget appearanceState is not exposed, so a per-widget /AS
change with unchanged group /V is NOT detected. Corrected the comment,
MCP_CONTRACT wording, and test to name it as a known coverage gap rather than
claim full form-appearance coverage. Detecting it needs an observation-layer
change, tracked separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@silverstein
silverstein merged commit 431f10c into master Sep 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant