Skip to content

fix(robustness): graceful per-page detection + clearer errors (agent-team review) - #3

Merged
san64777 merged 1 commit into
mainfrom
fix/robustness-graceful-detection
Jun 8, 2026
Merged

fix(robustness): graceful per-page detection + clearer errors (agent-team review)#3
san64777 merged 1 commit into
mainfrom
fix/robustness-graceful-detection

Conversation

@san64777

@san64777 san64777 commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Context

You asked: "if there's an image in a PDF it doesn't warn and skip it, it crashes - at least it should complete the next pages," and to re-review the code with the agent-team. This is the result of a real-world QA pass plus a 3-lens agent-team review (QA / PDF-engine / independent code review).

The reported bug (fixed)

detect() / make_fillable() raised ScannedPDFError on the first image-only page, discarding every other page. A mostly-vector form with one scanned/image page (a cover page, an exhibit) got zero fields. This violated the best-effort detection contract (best-effort detection must degrade gracefully).

Fix: detect_manifest now skips a scanned or error-throwing page with warnings.warn and processes the rest. ScannedPDFError is raised only when every page is image-only (so a genuinely scanned single-page doc still refuses - Gate C preserved). Verified: a vector/image/vector PDF now detects fields on the two vector pages and warns about the image page.

Other issues the review found (fixed)

  • fill() with a list value on a non-multi-select field crashed with a cryptic pypdf AttributeError (a real bug in the guaranteed core, from the multi-select work) -> now a clear ValueError.
  • _inherited could infinite-loop on a circular /Parent chain (malformed PDFs contain these) -> cycle guard added.
  • read_fields aborted the whole read on one malformed widget -> now skips it with a warning, recovers the rest.
  • flatten on a fieldless PDF raised a raw pypdf error -> now a no-op returning the input.

Deferred (tracked in D020, out of scope per rule 5)

Typed PDF-open error family (corrupt/encrypted input), rotated-page placement (needs golden-harness), build() duplicate-name collision, XFA-dropped warning, text/checkbox sub-pixel guard.

Validation

  • 7 new regression tests (per-page skip, all-scanned refusal, fill misuse, cycle guard, malformed-widget skip, flatten no-op).
  • Re-ran a hands-on QA probe: the mixed image/vector doc now completes; single-page image-only still refuses gracefully; fixtures unaffected.
  • CI: ruff, mypy, 111 tests, license-gate, no-dashes all pass. Bumps to 0.3.2 (rolls up the held 0.3.1 list-box fix).

…/flatten/read errors

From an agent-team robustness review + real-world QA. detect/make_fillable no longer refuse a whole document on the first image-only page: a scanned or error-throwing page is skipped with a warning and the rest is processed; ScannedPDFError is raised only when every page is image-only (Gate C preserved). Also: fill() rejects a list value on a non-multi-select field with a clear error (was a cryptic pypdf AttributeError); _inherited guards against a circular /Parent (was an infinite loop); read_fields skips a single malformed widget instead of aborting; flatten no-ops on a fieldless PDF. Bumps to 0.3.2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@san64777
san64777 merged commit 5827d1b into main Jun 8, 2026
4 checks passed
@san64777
san64777 deleted the fix/robustness-graceful-detection branch June 8, 2026 18:26
san64777 added a commit that referenced this pull request Jun 9, 2026
…/flatten/read errors (#3)

From an agent-team robustness review + real-world QA. detect/make_fillable no longer refuse a whole document on the first image-only page: a scanned or error-throwing page is skipped with a warning and the rest is processed; ScannedPDFError is raised only when every page is image-only (Gate C preserved). Also: fill() rejects a list value on a non-multi-select field with a clear error (was a cryptic pypdf AttributeError); _inherited guards against a circular /Parent (was an infinite loop); read_fields skips a single malformed widget instead of aborting; flatten no-ops on a fieldless PDF. Bumps to 0.3.2.
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