release: v1.7.5 — PDF/A-2 ~92% (non-page content streams, XMP extension schema, 2 FP fixes) - #135
Merged
Conversation
The catalog listed §6.7.3.3-1 as Deferred citing a structure-tree walker, but the clause's veraPDF predicate is just containsStructTreeRoot == true — a document-catalog presence check that LogicalStructureRule (PDF/A-2a-gated, so FP-safe for 2b/2u) already enforces. Flip it to Implemented and record the clause-level confirmation: veraPDF fires clause 6.7.3.3 testNumber 1 as the SOLE failed check on the pdfa2a-no-structure oracle fixture. Only 6.1.6-2 remains Deferred for PDF/A. Gate: REQUIRE_VERAPDF=1 → 994 passed; dotnet format clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
…t streams Add a reusable GetReachableContentStreams collector to ContentStreamUsage (drawn Form XObjects — recursive, cycle-guarded; all CharProcs of Tf-selected Type 3 fonts; every annotation /AP /N appearance stream incl. keyed sub-dicts) and extend ContentStreamOperatorRule (§6.2.2-1) to scan them. §6.2.2-1 moves Partial -> Implemented. Reachability policy empirically pinned against veraPDF 1.30.2: Form XObjects validated only when drawn (undrawn excluded); Type 3 CharProcs validated for every Tf-selected font regardless of which glyph is shown (the unshown-CharProc case fires in veraPDF too — scope matches, no false positive); appearance streams validated regardless of annotation visibility. Appearance /N detection probes ResolveStream first so an indirect keyed sub-dictionary (Widget checkbox/radio) is walked, not dropped. Cross-validated fixtures (drawn/undrawn/nested/cyclic forms, inline-image-in- form, direct + keyed annotation appearances). Gate REQUIRE_VERAPDF=1 -> 1012 passed; dotnet format clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
…tent streams Extend InlineImageFilterRule to scan inline images in drawn Form XObjects, Tf-selected Type 3 CharProcs, and annotation /AP /N appearance streams via the shared GetReachableContentStreams collector (same refactor shape as the §6.2.2-1 extension: per-blob ScanBytes run over page content and every reachable stream). §6.1.10-1 moves Partial -> Implemented. Cross-validated fixtures for forbidden (/F /LZWDecode) and permitted (/F /AHx) filters in drawn/nested forms and annotation appearances, plus the adversarial case where ID..EI binary sample data contains the literal bytes /F /LZWDecode (confirms SkipInlineImageData prevents the dict parser from misreading samples). Gate independently re-run REQUIRE_VERAPDF=1 -> 1026 passed; dotnet format clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
…streams Run the overprint/OPM graphics-state interpreter over drawn Form XObjects, Tf-selected Type 3 CharProcs, and annotation /AP /N appearance streams (via the shared GetReachableContentStreams collector), each scanned in isolation against its own /Resources. Extracts InterpretStream from EvaluatePage; null-/Resources streams are skipped (names unresolvable -> under-detection, FP-safe). Stays Partial by design: veraPDF threads graphics state across Do boundaries (probe N3-B: page sets op/OPM/ICCBased-CMYK, form merely fills -> veraPDF fires; isolated per-stream scanning under-detects this). Isolated scanning is a strict subset of veraPDF's view -> can only under-detect, never over-detect. Catalog note updated to record the residual inherited-state gap. Cross-validated fixtures (self-contained form violation, OPM-0 guard, no- /Resources guard) + 4 in-process FP-sweep facts; 8-case adversarial sweep found zero false positives. Gate REQUIRE_VERAPDF=1 -> 1036 passed; format clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
…streams Feed Separations used in drawn Form XObjects, Tf-selected Type 3 CharProcs, and annotation /AP /N appearance streams into the document-wide Separation consistency comparison (via the shared GetReachableContentStreams collector). Extracts ProcessResourceScope from the page loop and adds a small defensive cs/CS scanner (ScanSelectedColorSpaces) for non-page stream bytes; per-stream names resolve against that stream's own /Resources, null-/Resources skipped, seenCsObjects dedups Separations shared across page and forms. Stays Partial: image /ColorSpace and nested alternate spaces remain unwalked. FP-safe by pool growth — adding non-page used-Separations only grows the comparison pool toward what veraPDF already compares (our set stays a subset), so any inconsistency we detect veraPDF also detects. Probes N4-A/B/C confirm veraPDF compares page-vs-drawn-form Separations and ignores undrawn ones. Cross-validated fixtures (page/form inconsistent -> fail; identical -> pass) + 3 FP-sweep facts; sweep found zero false positives. Gate independently re-run REQUIRE_VERAPDF=1 -> 1043 passed; format clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
…ed-name FP Extend the inherited-resource check (§6.2.2-2) to non-page content streams: a resource-less drawn Form XObject / Type 3 CharProc / annotation appearance that uses a named resource defined in the page's resource scope is flagged (it relies on inherited resources, which §6.2.2 forbids). Scoped precisely to veraPDF's inheritedResourceNames model — empirically pinned (probes N5/A1/B1/B2): veraPDF fires ONLY when the used name IS defined in the ancestor scope; an undefined name does not fire. That same finding exposed a pre-existing FALSE POSITIVE in the page-level path: EvaluatePage reported EVERY used name when a page lacked its own /Resources, without checking the inherited scope — so a page using a name undefined in the whole inheritance chain was over-rejected (veraPDF accepts it, probe A1). Fixed to resolve the inherited /Resources and report only names actually defined there. Nested-form case (inner resource-less form, name in page) confirmed NOT an FP (veraPDF fires too, probe B1); outer-defined-only stays silent in both (B2). §6.2.2-2 stays Partial (Pattern scn/SCN + Properties BDC/DP names still out of scope). New fixtures + facts for every probed case; gate independently re-run REQUIRE_VERAPDF=1 -> 1061 passed; format clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
…+ per-type matching OutputIntentRule's device-colour check fired whenever any device colour was used without a PDF/A output intent, ignoring /Default* colour spaces entirely — a FALSE POSITIVE: veraPDF accepts DeviceRGB/CMYK/Gray used with a matching /DefaultRGB|CMYK|Gray colour space and no output intent (probed, 2026-06-23). Rework to veraPDF's per-type semantics: DeviceRGB satisfied by /DefaultRGB OR an RGB-profile output intent; DeviceCMYK by /DefaultCMYK OR a CMYK intent; DeviceGray by /DefaultGray OR ANY intent. Intent colour space read from the DestOutputProfile ICC header data-colour-space field (offset 16). Per-type device-colour detection added additively to ContentStreamUsage (UsesDeviceRgb/Cmyk/Gray; UsesDeviceColour unchanged for existing consumers) + PreflightContext.DocumentDeviceColourTypes(). FP-safe by construction: fires only on a POSITIVELY-determined mismatch (intent present but its colour space read and not the needed one); any uncertainty (unreadable/non-standard ICC colour space, malformed profile) stays silent. Document-wide Default*/usage aggregation under-detects the cross-page case (FP-safe) — 6.2.4.3-2/-3/-4 stay Partial (image/pattern/XObject device colour still undetected). 8 cross-validated fixtures (FP regression guards + true positives + correct-match) + sweep; gate independently re-run REQUIRE_VERAPDF=1 -> 1077 passed; format clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
…prefixes Extend ExtensionSchemaRule to validate the RDF container TYPE (rdf:Bag vs rdf:Seq) and namespace prefixes of the pdfaExtension schema, flipping four clauses to Implemented: - 6.6.2.3.3-1: pdfaExtension:schemas must be rdf:Bag + 'pdfaExtension' prefix - 6.6.2.3.3-5: pdfaSchema:property must be rdf:Seq + null|'pdfaSchema' prefix - 6.6.2.3.3-6: pdfaSchema:valueType must be rdf:Seq + null|'pdfaSchema' prefix - 6.6.2.3.3-15: pdfaType:field must be rdf:Seq + null|'pdfaType' prefix 6.6.2.3.3-8 and -17 (scalar valueType field prefix) get the prefix check too but STAY Partial — veraPDF also requires the value type be a defined Text type (isValueTypeDefined), which needs the value-type registry not yet built; firing only on wrong prefix is a strict subset of veraPDF's condition (FP-safe). Key veraPDF nuance probed and honored (2026-06-23): the container elements (-5/-6/-15) accept a NULL prefix (default namespace) as well as the canonical one, while -1/-8/-17 require the literal named prefix. Each check fires only on a subset of veraPDF's firing conditions; only documents that declare an extension schema are affected. 10 cross-validated fixtures + 6 facts + sweep; gate independently re-run REQUIRE_VERAPDF=1 -> 1103 passed; format clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
…on schema, 2 FP fixes) VersionPrefix 1.7.4 -> 1.7.5; CHANGELOG 1.7.5 entry; README conformance parity ~90% -> ~92% for PDF/A-2b/2u/2a (UA-1 ~90% unchanged). Reader/Conformance kept at Preview maturity (packages themselves ship stable, non-prerelease). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RghjbtTZ9hn9P8A1JEgXVq
This was referenced Jun 24, 2026
This was referenced Jul 1, 2026
This was referenced Jul 15, 2026
This was referenced Aug 19, 2026
This was referenced Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v1.7.5 — PDF/A-2 conformance deepened + two false-positive fixes
Build-verified veraPDF parity: PDF/A-2b 90.3 → 92.36%, 2u 90.4 → 92.47%, 2a 89.9 → 92.48% (UA-1 ~90% unchanged). Every batch cross-validated against veraPDF 1.30.2 in CI with adversarial false-positive sweeps.
Added — PDF/A-2 across non-page content streams
Tf-selected fonts, annotation/AP /Nappearances (incl. keyed sub-dicts); reachability pinned empirically to veraPDF.Fixed — two false positives (a rule must never reject what veraPDF accepts)
/DefaultRGB|CMYK|Graycolour space was present. Now per-type per veraPDF semantics./Resourceswas flagged for every used name, including names undefined in the inheritance chain (which veraPDF accepts). Now flags only inherited-defined names.Reader & Conformance remain at Preview maturity (packages ship as stable, non-prerelease
1.x).Gate:
REQUIRE_VERAPDF=1→ 1103 passed;dotnet formatclean.