Skip to content

feat(pdf-extract): scaffold single-source stranske-pdf-extract library (#2711) - #2716

Merged
stranske merged 4 commits into
mainfrom
claude/pdf-extract-scaffold
Jun 30, 2026
Merged

feat(pdf-extract): scaffold single-source stranske-pdf-extract library (#2711)#2716
stranske merged 4 commits into
mainfrom
claude/pdf-extract-scaffold

Conversation

@stranske

@stranske stranske commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

Scaffolds stranske-pdf-extract — the single-source PDF text-extraction library for the stranske/*
fleet — replacing four independent, diverging implementations (Counter_Risk, Pension-Data, Inv-Man-Intake,
Manager-Database) with one installable package. Implements deliverable 5 (scaffold) of the initiative;
design, distribution decision, and migration plan are in
docs/DESIGN.md.

Related to #2711; resolves the build half without closing the source issue.

What's here

Module Role
contract.py the one result + page-level-provenance contract (generalizes Pension-Data's evidence model + Inv-Man-Intake's bbox SourceLocation/Protocols — not a third invented contract)
provider.py ExtractionProvider / MultiModalExtractionProvider Protocols, injectable OCR seam, name registry
orchestration.py run_fallback_chain ladder primitive (lifted from Pension-Data, already generic)
reliability.py greenfield — foot/cross-foot, weights, dates, cross-check, ECE, confidence routing (absent fleet-wide)
providers/docling_provider.py one real extractor behind the Protocol (Docling, MIT, local; optional [docling] extra) — IMI #713 should consume this
providers/text_baseline.py pure-python pdfplumber→pypdf→OCR→raw-decode ladder; runs with no native deps
eval/harness.py golden-set scorer: normalize-then-compare, macro-F1, regression gate

Distribution decision

Installable pip package, not Workflows sync-manifest copy-sync (see docs/DESIGN.md §2): optional native
deps need extras; only 4/13 consumers need it; consumers must pin and migrate independently without breaking
tests. Homed as a subdirectory package; not added to sync-manifest.yml.

Tests

27 deterministic tests, no network, no heavy deps required:

cd packages/stranske_pdf_extract && PYTHONPATH=src python -m pytest -q   # 27 passed

Named conformance gate tests/test_docling_provider.py::test_docling_provider_conforms_to_protocol is proven
falsifiable via the deliberate-break pattern (commenting out DoclingProvider.name → test FAILS → revert →
passes), demonstrated during scaffolding.

Follow-ups (tracked, not in this PR)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added stranske-pdf-extract, a pip-installable PDF text-extraction library with installable extras for baseline parsing, Docling-backed extraction, OCR, and AWS fallback.
    • Introduced a unified extraction contract with page-level provenance and provider output validation.
    • Added fallback-ladder orchestration, reliability checks (business rules, cross-checking, confidence routing), and a golden-set evaluation harness.
    • Published comprehensive documentation and design for the new shared approach.
  • Bug Fixes

    • Improved validation to catch malformed fields, confidence/location mismatches, and strict evidence requirements for high-impact fields.
    • Added Docling provider behavior when the optional dependency is unavailable.
  • Tests

    • Added coverage for contract validation, orchestration behavior, reliability logic, evaluation scoring, and Docling conformance.

Source: Issue #2711

Closes #2711

Automated Status Summary

Scope

PDF text-EXTRACTION is independently reimplemented in four fleet repos with four divergent
result contracts and three OCR strategies (verified by reading source, 2026-06-28, and confirmed by a
fresh clone-grep across all branches — exactly four, none missed):

  • Counter_Risk src/counter_risk/parsers/daily_holdings_pdf.py:81 (_extract_text ladder pdfplumber→pypdf→OCR).
  • Pension-Data src/pension_data/parser/pdf_pipeline.py:455 (parse_pdf_to_funded_input) + src/pension_data/extract/orchestration/fallback.py:53 (run_fallback_chain) + db/models/provenance.py.
  • Inv-Man-Intake src/inv_man_intake/extraction/providers/base.py:204 (ExtractionProvider Protocol; :218 MultiModalExtractionProvider) — current pdf_primary.py extractor is fixture-grade, not real.
  • Manager-Database utils/extract.py:20 (_extract_pdf, pdfplumber→str).

Missing/duplicated behavior: items 1–4 of the shape (text-extraction ladder, OCR fallback, orchestration,
result/provenance contract) are rebuilt per repo; a reliability layer (arithmetic/business-rule validation +
cross-check + calibrated confidence) is absent in all four. This is latent fragility + duplicated effort,
not a current break. Grounding: Code/Audits/2026-06-28-fleet-pdf-extraction-survey.md and …-methodology.md.
A validated scaffold (this design) already exists at packages/stranske_pdf_extract/ with 27 passing
deterministic tests; this issue tracks landing it on main and finishing the optional-dep paths.

Tasks

  • Land packages/stranske_pdf_extract/ on main (the validated scaffold): pyproject.toml (extras
    baseline,docling,ocr,textract,schema,eval), src/stranske_pdf_extract/{contract,provider,orchestration,reliability}.py,
    providers/{docling_provider,text_baseline}.py, eval/harness.py, docs/DESIGN.md, README.md, and tests/.
  • Wire the package's tests/ into Workflows CI (a non-default job, e.g. extend .github/workflows/selftest-ci.yml
    or add a packages-pdf-extract job) running PYTHONPATH=packages/stranske_pdf_extract/src python -m pytest packages/stranske_pdf_extract/tests.
  • Tag the release pdf-extract-v0.1.0 and document the install URL
    git+https://github.com/stranske/Workflows@pdf-extract-v0.1.0#subdirectory=packages/stranske_pdf_extract in README.md.
  • Complete the Docling real path (providers/docling_provider.py:_extract_real) behind the [docling] extra and
    add an opt-in test that runs only when docling_available() is true (skips cleanly otherwise).
  • Perform the deliberate-break verification (see Acceptance Criteria), capture the FAIL output, then revert.

Acceptance criteria

  • Named test gate: packages/stranske_pdf_extract/tests/test_docling_provider.py::test_docling_provider_conforms_to_protocol
    passes in CI (asserts isinstance(DoclingProvider(), MultiModalExtractionProvider)), AND the full package suite
    collects a non-zero count and passes (confirmed-green locally: 27 passed).
  • Deliberate-break gate: temporarily comment out the name = "docling" attribute in
    src/stranske_pdf_extract/providers/docling_provider.py (class DoclingProvider). With this change,
    test_docling_provider.py::test_docling_provider_conforms_to_protocol must FAIL with
    assert isinstance(...) == False. Revert and confirm it passes. (Demonstrated locally during scaffolding.)
  • pip install "git+…#subdirectory=packages/stranske_pdf_extract" imports stranske_pdf_extract with the
    core (no extras) and import of providers does not require docling (only extract_modalities does).

Head SHA: d4fa7d2
Latest Runs: ✅ success — Gate
Required: gate: ✅ success

Workflow / Job Result Logs
Gate ✅ success View run
Health 40 Sweep ✅ success View run
Health 44 Gate Branch Protection ✅ success View run
Health 45 Agents Guard ✅ success View run
Health 50 Security Scan ✅ success View run
Health 52 Semgrep Scan ✅ success View run
Maint 52 Validate Workflows ✅ success View run
PR 11 - Minimal invariant CI ✅ success View run
Selftest CI ✅ success View run

Single-source PDF text-extraction for the fleet, replacing four diverging
implementations (Counter_Risk, Pension-Data, Inv-Man-Intake, Manager-Database).

Ships the generalized result + page-level-provenance contract (generalizes
Pension-Data's evidence model + Inv-Man-Intake's bbox provenance + Protocols),
the lifted fallback-ladder orchestration primitive, a greenfield reliability
layer (arithmetic/business-rule checks + cross-check + calibration/routing,
absent fleet-wide), a real Docling provider behind the Protocol (optional dep),
a pure-python baseline, and a golden-set eval harness. 27 deterministic tests
pass; named conformance gate proven via deliberate-break.

Distribution: pip-installable subdirectory package (not sync-manifest copy-sync)
— see packages/stranske_pdf_extract/docs/DESIGN.md.

Tracking: #2711. Migrations: #2712 #2713 #2714 #2715. Cross-links IMI #713.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds a new stranske_pdf_extract Python package with shared extraction contracts, provider protocols and registry, fallback orchestration, reliability checks, evaluation scoring, two providers, tests, and package/design documentation.

Changes

stranske-pdf-extract library

Layer / File(s) Summary
Package scaffold and exports
packages/stranske_pdf_extract/pyproject.toml, src/stranske_pdf_extract/__init__.py
pyproject.toml defines the package, optional dependency groups, build targets, and pytest settings. __init__.py sets __version__ and re-exports the main public submodules.
Extraction contract and validators
src/stranske_pdf_extract/contract.py
Defines the shared provenance/result dataclasses, evidence identity helpers, provider output models, and validation functions for provider output and extracted results.
Provider protocols and registry
src/stranske_pdf_extract/provider.py
Defines the OCR callable type, extraction provider protocols, and the in-memory provider registry helpers.
Fallback orchestration
src/stranske_pdf_extract/orchestration.py
Adds fallback-stage dataclasses, sequential execution, exhaustion escalation, and best-partial selection.
Reliability checks and routing
src/stranske_pdf_extract/reliability.py
Adds arithmetic checks, cross-checking, calibration error calculation, and confidence routing.
Evaluation harness
src/stranske_pdf_extract/eval/*
Adds normalized value comparison, per-field scoring, regression detection, and public eval exports.
Baseline and Docling providers
src/stranske_pdf_extract/providers/*
Adds the text baseline extractor, the optional Docling-backed extractor, and provider package re-exports.
Contract and provider tests
packages/stranske_pdf_extract/tests/test_contract.py, packages/stranske_pdf_extract/tests/test_docling_provider.py
Covers evidence identity, validator behavior, provider conformance, availability handling, and registry resolution.
Orchestration, eval, and reliability tests
packages/stranske_pdf_extract/tests/test_orchestration.py, packages/stranske_pdf_extract/tests/test_eval.py, packages/stranske_pdf_extract/tests/test_reliability.py
Covers fallback sequencing, scoring and regression detection, and all reliability helpers.
README and design docs
packages/stranske_pdf_extract/README.md, packages/stranske_pdf_extract/docs/DESIGN.md
Documents the package surface, install/test usage, architecture, distribution plan, migration phases, and constraints.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: scaffolding the new single-source stranske-pdf-extract library.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/pdf-extract-scaffold

Comment @coderabbitai help to get the list of available commands.

@stranske
stranske temporarily deployed to agent-standard June 29, 2026 04:53 — with GitHub Actions Inactive
@stranske-keepalive

stranske-keepalive Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Workflow source detected

PR #2716 now has valid workflow source context (origin=github_issue ref=#2711).

A linked GitHub issue is present for this PR.

@stranske-keepalive

stranske-keepalive Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Automated Status Summary

Head SHA: 46b1b3d
Latest Runs: ⏳ pending — Gate
Required contexts: Gate / gate, Health 45 Agents Guard / guard
Required: core tests (3.12): ⏳ pending, core tests (3.13): ⏳ pending, docker smoke: ⏳ pending, gate: ⏳ pending

Workflow / Job Result Logs
(no jobs reported) ⏳ pending

Coverage Overview

  • Coverage history entries: 1

Coverage Trend

Metric Value
Current 75.67%
Baseline 85.00%
Delta -9.33%
Minimum 70.00%
Status ✅ Pass

Top Coverage Hotspots (lowest coverage)

File Coverage Missing
scripts/issue_dedup_smoke.py 0.0% 4
scripts/runner_lib/__main__.py 0.0% 3
scripts/validate_template_sync.py 0.0% 77
scripts/langchain/topic_splitter.py 19.1% 57
tools/codex_log_analyzer.py 19.6% 140
scripts/repo_review_round2_runner.py 25.1% 344
scripts/prune_agent_stubs.py 39.7% 26
scripts/repo_review_round1_runner.py 40.7% 133
tools/ensure_workflow_timeout_variables.py 42.1% 74
scripts/sync_label_docs.py 42.9% 64
tools/ci_failure_triage.py 44.2% 123
scripts/repo_review_backlog_scan.py 45.3% 116
scripts/repo_review_body_writer.py 46.5% 86
tools/codex_session_analyzer.py 47.9% 59
scripts/create_verifier_labels.py 48.3% 58

Low Coverage Files (<50.0%)

File Coverage Missing
scripts/issue_dedup_smoke.py 0.0% 4
scripts/runner_lib/__main__.py 0.0% 3
scripts/validate_template_sync.py 0.0% 77
scripts/langchain/topic_splitter.py 19.1% 57
tools/codex_log_analyzer.py 19.6% 140
scripts/repo_review_round2_runner.py 25.1% 344
scripts/prune_agent_stubs.py 39.7% 26
scripts/repo_review_round1_runner.py 40.7% 133
tools/ensure_workflow_timeout_variables.py 42.1% 74
scripts/sync_label_docs.py 42.9% 64
tools/ci_failure_triage.py 44.2% 123
scripts/repo_review_backlog_scan.py 45.3% 116
scripts/repo_review_body_writer.py 46.5% 86
tools/codex_session_analyzer.py 47.9% 59
scripts/create_verifier_labels.py 48.3% 58

Updated automatically; will refresh on subsequent CI/Docker completions.


Keepalive checklist

Scope

PDF text-EXTRACTION is independently reimplemented in four fleet repos with four divergent
result contracts and three OCR strategies (verified by reading source, 2026-06-28, and confirmed by a
fresh clone-grep across all branches — exactly four, none missed):

  • Counter_Risk src/counter_risk/parsers/daily_holdings_pdf.py:81 (_extract_text ladder pdfplumber→pypdf→OCR).
  • Pension-Data src/pension_data/parser/pdf_pipeline.py:455 (parse_pdf_to_funded_input) + src/pension_data/extract/orchestration/fallback.py:53 (run_fallback_chain) + db/models/provenance.py.
  • Inv-Man-Intake src/inv_man_intake/extraction/providers/base.py:204 (ExtractionProvider Protocol; :218 MultiModalExtractionProvider) — current pdf_primary.py extractor is fixture-grade, not real.
  • Manager-Database utils/extract.py:20 (_extract_pdf, pdfplumber→str).

Missing/duplicated behavior: items 1–4 of the shape (text-extraction ladder, OCR fallback, orchestration,
result/provenance contract) are rebuilt per repo; a reliability layer (arithmetic/business-rule validation +
cross-check + calibrated confidence) is absent in all four. This is latent fragility + duplicated effort,
not a current break. Grounding: Code/Audits/2026-06-28-fleet-pdf-extraction-survey.md and …-methodology.md.
A validated scaffold (this design) already exists at packages/stranske_pdf_extract/ with 27 passing
deterministic tests; this issue tracks landing it on main and finishing the optional-dep paths.

Tasks

  • Land packages/stranske_pdf_extract/ on main (the validated scaffold): pyproject.toml (extras
    baseline,docling,ocr,textract,schema,eval), src/stranske_pdf_extract/{contract,provider,orchestration,reliability}.py,
    providers/{docling_provider,text_baseline}.py, eval/harness.py, docs/DESIGN.md, README.md, and tests/.
  • Wire the package's tests/ into Workflows CI (a non-default job, e.g. extend .github/workflows/selftest-ci.yml
    or add a packages-pdf-extract job) running PYTHONPATH=packages/stranske_pdf_extract/src python -m pytest packages/stranske_pdf_extract/tests.
  • Tag the release pdf-extract-v0.1.0 and document the install URL
    git+https://github.com/stranske/Workflows@pdf-extract-v0.1.0#subdirectory=packages/stranske_pdf_extract in README.md.
  • Complete the Docling real path (providers/docling_provider.py:_extract_real) behind the [docling] extra and
    add an opt-in test that runs only when docling_available() is true (skips cleanly otherwise).
  • Perform the deliberate-break verification (see Acceptance Criteria), capture the FAIL output, then revert.

Acceptance criteria

  • Named test gate: packages/stranske_pdf_extract/tests/test_docling_provider.py::test_docling_provider_conforms_to_protocol
    passes in CI (asserts isinstance(DoclingProvider(), MultiModalExtractionProvider)), AND the full package suite
    collects a non-zero count and passes (confirmed-green locally: 27 passed).
  • Deliberate-break gate: temporarily comment out the name = "docling" attribute in
    src/stranske_pdf_extract/providers/docling_provider.py (class DoclingProvider). With this change,
    test_docling_provider.py::test_docling_provider_conforms_to_protocol must FAIL with
    assert isinstance(...) == False. Revert and confirm it passes. (Demonstrated locally during scaffolding.)
  • pip install "git+…#subdirectory=packages/stranske_pdf_extract" imports stranske_pdf_extract with the
    core (no extras) and import of providers does not require docling (only extract_modalities does).

@stranske

stranske commented Jun 29, 2026

Copy link
Copy Markdown
Owner Author

Runner dispatch state for autofix on PR #2716. Do not edit.

@github-actions github-actions Bot added the autofix Opt-in automated formatting & lint remediation label Jun 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/stranske_pdf_extract/docs/DESIGN.md`:
- Around line 41-52: The package-tree fence in the DESIGN.md snippet is missing
a language tag, which keeps markdownlint failing. Update the fenced block for
the `stranske_pdf_extract/` tree to use a plain-text language label such as
`text` or `plaintext`, keeping the content unchanged. Locate the fenced package
tree near the `contract.py` / `provider.py` / `orchestration.py` listing and
apply the language tag there.
- Around line 108-111: Update the calibration + confidence routing section in
DESIGN.md to match the shipped reliability.py API: describe only
expected_calibration_error() and route_by_confidence(), remove the mention of a
ConfidenceCalibrator seam, and align the routing thresholds with the current
defaults of accept_at=0.95 and reject_below=0.50 instead of ~85%. Keep the
wording focused on the available functions and current router behavior so the
documentation matches the implemented symbols.

In `@packages/stranske_pdf_extract/README.md`:
- Around line 51-52: The README wording for Docling is inaccurate: the provider
test in test_docling_provider.py::test_docling_provider_conforms_to_protocol
does not “pass with or without” the extra, and the extraction path in the
Docling provider raises DoclingUnavailableError when [docling] is missing.
Reword the Docling section to say the test is skipped when Docling is already
installed and that the provider surfaces DoclingUnavailableError if the extra is
absent, so readers understand it does not silently skip.

In `@packages/stranske_pdf_extract/src/stranske_pdf_extract/contract.py`:
- Line 20: The contract module has an unused import of field alongside
dataclass, which causes lint failure. Remove the field import from the import
statement in the contract.py module and keep only the symbols that are actually
used, such as dataclass.
- Around line 287-295: The strict_evidence check in the ExtractedField
validation only verifies that f.evidence exists, so mismatched EvidenceRef
values can still pass. Update the validation path around the current
strict_evidence/f.evidence logic to also inspect the EvidenceRef contents,
adding a dedicated validator for EvidenceRef and enforcing that source_doc_id
matches the current document plus basic page-number sanity before allowing
high-impact fields. Reuse the existing validation pattern in
validate_provider_output() and keep the new checks close to the current
ExtractedField / HIGH_IMPACT_PREFIXES enforcement.

In `@packages/stranske_pdf_extract/src/stranske_pdf_extract/eval/harness.py`:
- Around line 27-36: The numeric normalization in normalize_value() is using
float(), which can merge distinct exact values into the same canonical form.
Update the numeric parsing in normalize_value() to preserve exact decimal
precision using a decimal-based representation instead of float(), while keeping
the existing handling for negatives and cleaned currency/percent strings. Make
sure the returned canonical string is stable and exact so score_against_golden()
and reliability.cross_check() do not treat unequal values as equal.

In `@packages/stranske_pdf_extract/src/stranske_pdf_extract/orchestration.py`:
- Around line 48-70: The ladder in orchestration.py is only treating
stage.parse() exceptions as recoverable, but an is_complete(parsed) exception
still aborts the flow. Update the failure handling around the parse result in
the parse loop so that the is_complete check is also wrapped in the same
stage-failure path, recording a ParserAttempt with the stage_name and
parser_name and then continuing to later parsers. Use the existing
ParserAttempt, stage.parse(), and is_complete(parsed) flow as the place to catch
and classify this error.

In `@packages/stranske_pdf_extract/src/stranske_pdf_extract/provider.py`:
- Around line 1-91: Run Black on the provider.py module to normalize formatting
so CI passes; update the spacing and line wrapping in the affected definitions
such as register_provider, build_provider, and the module docstring/exports to
match Black’s output without changing behavior.

In
`@packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/docling_provider.py`:
- Around line 45-48: The Docling OCR toggle is exposed on
DoclingProvider.__init__, but _extract_real() ignores self._do_ocr and always
creates DocumentConverter() with default behavior. Update
DoclingProvider._extract_real() to pass the stored OCR setting into the Docling
converter so callers can control OCR, or remove the unused do_ocr parameter
entirely if it should not be supported. Use the DoclingProvider and
_extract_real symbols to keep the change localized.

In
`@packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/text_baseline.py`:
- Around line 35-40: The fallback chain in the text extraction flow stops on
non-empty page lists even when they contain only blank strings, so OCR is
skipped for image-only PDFs. Update the page selection logic in the baseline
extractor method that builds pages to treat “all blank” results from
_with_pdfplumber() and _with_pypdf() as unusable, then continue to _with_ocr()
before falling back to _raw_decode(). Keep the existing helper order, but add a
blank-content check on the returned pages so OCR runs whenever the earlier
parsers produce only empty text.

In `@packages/stranske_pdf_extract/src/stranske_pdf_extract/reliability.py`:
- Around line 161-174: Validate inputs in expected_calibration_error before
creating bins: reject n_bins values less than 1 and ensure each confidence in
the pairs passed to the function is within the expected [0.0, 1.0] range instead
of silently bucketing invalid values. Update the input handling around the
expected_calibration_error loop so bad arguments fail fast with a clear
exception, and keep the binning logic unchanged for valid confidences.

In `@packages/stranske_pdf_extract/tests/test_contract.py`:
- Around line 5-23: The test module is still failing Ruff/Black due to import
ordering and helper formatting in test_contract.py. Normalize the import block
around validate_extracted_document_result, validate_provider_output, and the
contract dataclasses to satisfy I001, and simplify the _field helper’s dict
initialization to the preferred literal style to address C408. Also remove the
unused mismatched assignment in the affected test case so F841 is cleared.

In `@packages/stranske_pdf_extract/tests/test_reliability.py`:
- Around line 3-17: The import block in test_reliability.py needs to be
reformatted to satisfy Ruff and Black before merge. Update the imports around
check_date_in_period, check_foots, check_sign, check_weights_sum_to_one,
cross_check, expected_calibration_error, route_by_confidence, and the
pytest/date imports so the file matches the formatter output and passes
lint/format checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 40a74eb5-bed4-485e-bc9e-db7df905cace

📥 Commits

Reviewing files that changed from the base of the PR and between a39db6e and 3cb38ab.

📒 Files selected for processing (18)
  • packages/stranske_pdf_extract/README.md
  • packages/stranske_pdf_extract/docs/DESIGN.md
  • packages/stranske_pdf_extract/pyproject.toml
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/__init__.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/contract.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/eval/__init__.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/eval/harness.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/orchestration.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/provider.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/__init__.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/docling_provider.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/text_baseline.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/reliability.py
  • packages/stranske_pdf_extract/tests/test_contract.py
  • packages/stranske_pdf_extract/tests/test_docling_provider.py
  • packages/stranske_pdf_extract/tests/test_eval.py
  • packages/stranske_pdf_extract/tests/test_orchestration.py
  • packages/stranske_pdf_extract/tests/test_reliability.py

Comment thread packages/stranske_pdf_extract/docs/DESIGN.md Outdated
Comment thread packages/stranske_pdf_extract/docs/DESIGN.md Outdated
Comment thread packages/stranske_pdf_extract/README.md Outdated
Comment thread packages/stranske_pdf_extract/src/stranske_pdf_extract/contract.py Outdated
Comment thread packages/stranske_pdf_extract/src/stranske_pdf_extract/contract.py
Comment thread packages/stranske_pdf_extract/src/stranske_pdf_extract/reliability.py Outdated
Comment thread packages/stranske_pdf_extract/tests/test_contract.py
Comment thread packages/stranske_pdf_extract/tests/test_reliability.py
@github-actions

Copy link
Copy Markdown
Contributor

Autofix updated these files:

  • packages/stranske_pdf_extract/src/stranske_pdf_extract/contract.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/eval/harness.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/provider.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/docling_provider.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/text_baseline.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/reliability.py
  • packages/stranske_pdf_extract/tests/test_contract.py
  • packages/stranske_pdf_extract/tests/test_reliability.py

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Runner dispatch state for codex on PR #2716. Do not edit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/stranske_pdf_extract/src/stranske_pdf_extract/reliability.py`:
- Around line 105-112: The sign-check logic in the reliability rule evaluator
currently falls through to None for unknown expected modes, which silently
disables validation. Update the function that handles the expected sign check in
reliability.py to explicitly reject any unsupported expected value by raising
ValueError before the non_negative/non_positive comparisons. Keep the existing
RuleViolation behavior for the supported modes and use the same rule/expected
branch so the fix is localized and easy to locate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: fc2d74b7-2b3d-4bb1-9608-1e8e6245d7fd

📥 Commits

Reviewing files that changed from the base of the PR and between 3cb38ab and 8633112.

📒 Files selected for processing (8)
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/contract.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/eval/harness.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/provider.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/docling_provider.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/providers/text_baseline.py
  • packages/stranske_pdf_extract/src/stranske_pdf_extract/reliability.py
  • packages/stranske_pdf_extract/tests/test_contract.py
  • packages/stranske_pdf_extract/tests/test_reliability.py

The autofix bot handled format + the 7 auto-fixable findings; this clears
the 3 remaining hidden fixes (F841 dead var, C408 dict()->literal, C416)
so `ruff check` is green. No behavior change; 27 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@stranske
stranske temporarily deployed to agent-standard June 30, 2026 00:54 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard June 30, 2026 09:26 — with GitHub Actions Inactive
@stranske

Copy link
Copy Markdown
Owner Author

Closer review-fix pass pushed commit d4fa7d2.

Addressed the unresolved CodeRabbit threads for:

  • docs/readme drift around the package tree fence, confidence routing, and Docling behavior
  • EvidenceRef source/page validation under strict evidence
  • exact Decimal normalization in the eval harness
  • fallback-chain handling when is_complete raises
  • Docling do_ocr converter wiring
  • blank native-text pages falling through to OCR
  • reliability fail-fast checks for sign modes and ECE inputs
  • package test formatting/lint issues

Local validation:

  • PYTHONPATH=src python -m pytest -q -> 32 passed
  • python -m ruff check packages/stranske_pdf_extract/src/stranske_pdf_extract packages/stranske_pdf_extract/tests -> passed
  • python -m black --check --target-version py312 packages/stranske_pdf_extract/src/stranske_pdf_extract packages/stranske_pdf_extract/tests -> passed
  • git diff --check -> passed

All addressed review threads were resolved via GraphQL. Fresh GitHub checks and CodeRabbit are running on d4fa7d2; no automation sleep/poll was used.

@stranske
stranske merged commit 46b1b3d into main Jun 30, 2026
50 checks passed
@stranske
stranske deleted the claude/pdf-extract-scaffold branch June 30, 2026 10:22
@stranske stranske added the verify:compare Compare multiple LLM evaluations label Jun 30, 2026
@stranske
stranske temporarily deployed to agent-standard June 30, 2026 10:23 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-high-privilege June 30, 2026 10:23 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard June 30, 2026 10:23 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

Provider Comparison Report

Provider Summary

Provider Model Verdict Confidence Summary
openai gpt-5.4 CONCERNS 89% The merged PR appears to land the new stranske_pdf_extract package scaffold successfully, with substantial implementation coverage across contract, provider protocols, orchestration, reliability, D...
anthropic claude-sonnet-4-6 CONCERNS 72% The scaffold itself (package structure, contracts, providers, orchestration, reliability, tests) appears well-implemented with 6 test files covering the 27-test suite. The core code quality is good...
📋 Full Provider Details (click to expand)

openai

  • Model: gpt-5.4
  • Verdict: CONCERNS
  • Confidence: 89%
  • Scores:
    • Correctness: 8.0/10
    • Completeness: 6.0/10
    • Quality: 8.0/10
    • Testing: 7.0/10
    • Risks: 7.0/10
  • Summary: The merged PR appears to land the new stranske_pdf_extract package scaffold successfully, with substantial implementation coverage across contract, provider protocols, orchestration, reliability, Docling/text-baseline providers, docs, README, and a non-trivial test suite. Code quality looks solid from the structure and scope of files added. However, the acceptance criteria are not fully satisfied based on the diff provided: the required explicit CI wiring for the package test command is not evident, the release tag requirement is not verifiable from code, and the deliberate-break verification is not demonstrated in the merged changes. Because the core implementation is present but several acceptance items are unproven or apparently incomplete, the appropriate verdict is CONCERNS rather than PASS.
  • Concerns:
    • The package scaffold itself appears substantially implemented: pyproject, core modules, providers, docs, README, and tests were added under packages/stranske_pdf_extract as requested.
    • A dedicated package test suite was added, including packages/stranske_pdf_extract/tests/test_docling_provider.py with the named protocol-conformance test, but the PR summary does not show any change to .github/workflows/selftest-ci.yml or another workflow that explicitly wires PYTHONPATH=packages/stranske_pdf_extract/src python -m pytest packages/stranske_pdf_extract/tests as required.
    • The acceptance criterion requiring release tag pdf-extract-v0.1.0 cannot be verified from code changes alone; README may document the install URL, but the actual tag creation is not evidenced in the merged code.
    • The deliberate-break verification requirement is not demonstrable from the code diff. The presence of the conformance test suggests the failure mode exists, but the PR does not capture evidence in code that the temporary removal of name = "docling" was performed and reverted.
    • The README was added and likely documents installation, but without the file contents it is not possible to confirm it includes the exact git+https://github.com/stranske/Workflows@pdf-extract-v0.1.0#subdirectory=packages/stranske_pdf_extract URL required by acceptance.
    • The CI guidance in the prompt says in-progress workflows are irrelevant post-merge, but it also states a failure on the merge commit would disqualify PASS. No failing workflows are shown, so this does not block, but the lack of explicit workflow wiring for the package tests remains a completeness concern.

anthropic

  • Model: claude-sonnet-4-6
  • Verdict: CONCERNS
  • Confidence: 72%
  • Scores:
    • Correctness: 7.0/10
    • Completeness: 6.0/10
    • Quality: 8.0/10
    • Testing: 7.0/10
    • Risks: 8.0/10
  • Summary: The scaffold itself (package structure, contracts, providers, orchestration, reliability, tests) appears well-implemented with 6 test files covering the 27-test suite. The core code quality is good. However, two task requirements show gaps: (1) CI wiring of the PDF extract test suite into selftest-ci.yml or a dedicated job is not evidenced in the changed files — this is required for the named test gate AC to be satisfied in CI rather than just locally; (2) the release tag pdf-extract-v0.1.0 cannot be confirmed from the diff. The deliberate-break gate is a process step claimed as locally demonstrated but not formally captured. These gaps prevent a clean PASS verdict.
  • Concerns:
    • CI wiring gap: selftest-ci.yml (or equivalent) does not appear in the changed files list, meaning the task requirement to wire packages/stranske_pdf_extract/tests/ into Workflows CI as a non-default job may not be fulfilled. The named test gate AC requires the test to pass in CI, not just locally.
    • Tag pdf-extract-v0.1.0 is a git operation not visible in the diff; cannot confirm it was created as required by the tasks.
    • Deliberate-break gate (AC2) is a process verification step documented as 'demonstrated locally during scaffolding' — no evidence in the diff that this was formally captured or that the revert was confirmed.
    • The install URL documentation in README.md cannot be fully verified from the diff summary alone (file added at +53 lines, content not shown).
    • No explicit opt-in test gated on docling_available() is confirmed visible in the diff summary for test_docling_provider.py, though the file exists — the skip-when-unavailable pattern needs verification.

Agreement

  • Verdict: CONCERNS (all providers)
  • Correctness: scores within 1 point (avg 7.5/10, range 7.0-8.0)
  • Completeness: scores within 1 point (avg 6.0/10, range 6.0-6.0)
  • Quality: scores within 1 point (avg 8.0/10, range 8.0-8.0)
  • Testing: scores within 1 point (avg 7.0/10, range 7.0-7.0)
  • Risks: scores within 1 point (avg 7.5/10, range 7.0-8.0)

Disagreement

No major disagreements detected.

Unique Insights

  • openai: The package scaffold itself appears substantially implemented: pyproject, core modules, providers, docs, README, and tests were added under packages/stranske_pdf_extract as requested.; A dedicated package test suite was added, including packages/stranske_pdf_extract/tests/test_docling_provider.py with the named protocol-conformance test, but the PR summary does not show any change to .github/workflows/selftest-ci.yml or another workflow that explicitly wires PYTHONPATH=packages/stranske_pdf_extract/src python -m pytest packages/stranske_pdf_extract/tests as required.; The acceptance criterion requiring release tag pdf-extract-v0.1.0 cannot be verified from code changes alone; README may document the install URL, but the actual tag creation is not evidenced in the merged code.; The deliberate-break verification requirement is not demonstrable from the code diff. The presence of the conformance test suggests the failure mode exists, but the PR does not capture evidence in code that the temporary removal of name = "docling" was performed and reverted.; The README was added and likely documents installation, but without the file contents it is not possible to confirm it includes the exact git+https://github.com/stranske/Workflows@pdf-extract-v0.1.0#subdirectory=packages/stranske_pdf_extract URL required by acceptance.; The CI guidance in the prompt says in-progress workflows are irrelevant post-merge, but it also states a failure on the merge commit would disqualify PASS. No failing workflows are shown, so this does not block, but the lack of explicit workflow wiring for the package tests remains a completeness concern.
  • anthropic: CI wiring gap: selftest-ci.yml (or equivalent) does not appear in the changed files list, meaning the task requirement to wire packages/stranske_pdf_extract/tests/ into Workflows CI as a non-default job may not be fulfilled. The named test gate AC requires the test to pass in CI, not just locally.; Tag pdf-extract-v0.1.0 is a git operation not visible in the diff; cannot confirm it was created as required by the tasks.; Deliberate-break gate (AC2) is a process verification step documented as 'demonstrated locally during scaffolding' — no evidence in the diff that this was formally captured or that the revert was confirmed.; The install URL documentation in README.md cannot be fully verified from the diff summary alone (file added at +53 lines, content not shown).; No explicit opt-in test gated on docling_available() is confirmed visible in the diff summary for test_docling_provider.py, though the file exists — the skip-when-unavailable pattern needs verification.

🔍 LangSmith Traces

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autofix:escalated autofix Opt-in automated formatting & lint remediation verify:compare Compare multiple LLM evaluations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build stranske-pdf-extract: single-source PDF-extraction library (contract + Protocols + fallback + reliability + Docling) in packages/

2 participants