You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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):
Inv-Man-Intake src/inv_man_intake/extraction/providers/base.py:204 (ExtractionProvider Protocol; :218MultiModalExtractionProvider) — current pdf_primary.py extractor is fixture-grade, not real.
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.
Scope
Land the single-source library stranske-pdf-extract as a pip-installable subdirectory package in
Workflows at packages/stranske_pdf_extract/ (distribution decision: package, NOT sync-manifest copy-sync —
see packages/stranske_pdf_extract/docs/DESIGN.md §2). The package owns: the generalized result + page-level
provenance contract (contract.py, generalizing Pension-Data + Inv-Man-Intake), the provider Protocols + OCR
seam + registry (provider.py), the fallback-ladder primitive (orchestration.py, lifted from Pension-Data),
the greenfield reliability layer (reliability.py), one REAL extractor behind the Protocol
(providers/docling_provider.py, Docling/MIT/local, optional [docling] extra), a pure-python baseline
(providers/text_baseline.py), and the golden-set eval harness (eval/harness.py). Tag pdf-extract-v0.1.0.
Non-Goals
Do NOT add the package to .github/sync-manifest.yml — distribution is pip, not copy-sync. The only
sync/doc touch is a note that the package exists and is pip-installed (so a future audit does not "fix" its absence).
Do NOT run Docling or OCR in any stlite/Pyodide browser path; keep them optional extras never imported there.
Do NOT migrate any consumer in this issue — migrations are separate, dependency-ordered tracking issues.
Do NOT learn any consumer's domain schema; domain field-parsing stays in each consumer.
Scaffold-only completion does NOT count: landing the tree with the named conformance gate collecting 0
tests, or the deliberate-break below not demonstrated, is a failure of this issue.
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_protocolmust 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).
Implementation Notes
Confirmed-green local reproduction: cd packages/stranske_pdf_extract && PYTHONPATH=src python -m pytest -q → 27 passed.
Core has zero runtime deps by design; native deps (Docling/Tesseract) are extras so confidentiality-sensitive
consumers install only what they need.
Contract merge rule and migration order are in packages/stranske_pdf_extract/docs/DESIGN.md.
Why
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):
src/counter_risk/parsers/daily_holdings_pdf.py:81(_extract_textladder pdfplumber→pypdf→OCR).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.src/inv_man_intake/extraction/providers/base.py:204(ExtractionProviderProtocol;:218MultiModalExtractionProvider) — currentpdf_primary.pyextractor is fixture-grade, not real.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.mdand…-methodology.md.A validated scaffold (this design) already exists at
packages/stranske_pdf_extract/with 27 passingdeterministic tests; this issue tracks landing it on
mainand finishing the optional-dep paths.Scope
Land the single-source library
stranske-pdf-extractas a pip-installable subdirectory package inWorkflows at
packages/stranske_pdf_extract/(distribution decision: package, NOT sync-manifest copy-sync —see
packages/stranske_pdf_extract/docs/DESIGN.md§2). The package owns: the generalized result + page-levelprovenance contract (
contract.py, generalizing Pension-Data + Inv-Man-Intake), the provider Protocols + OCRseam + registry (
provider.py), the fallback-ladder primitive (orchestration.py, lifted from Pension-Data),the greenfield reliability layer (
reliability.py), one REAL extractor behind the Protocol(
providers/docling_provider.py, Docling/MIT/local, optional[docling]extra), a pure-python baseline(
providers/text_baseline.py), and the golden-set eval harness (eval/harness.py). Tagpdf-extract-v0.1.0.Non-Goals
.github/sync-manifest.yml— distribution ispip, not copy-sync. The onlysync/doc touch is a note that the package exists and is pip-installed (so a future audit does not "fix" its absence).
tests, or the deliberate-break below not demonstrated, is a failure of this issue.
Tasks
packages/stranske_pdf_extract/onmain(the validated scaffold):pyproject.toml(extrasbaseline,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, andtests/.tests/into Workflows CI (a non-default job, e.g. extend.github/workflows/selftest-ci.ymlor add a
packages-pdf-extractjob) runningPYTHONPATH=packages/stranske_pdf_extract/src python -m pytest packages/stranske_pdf_extract/tests.pdf-extract-v0.1.0and document the install URLgit+https://github.com/stranske/Workflows@pdf-extract-v0.1.0#subdirectory=packages/stranske_pdf_extractinREADME.md.providers/docling_provider.py:_extract_real) behind the[docling]extra andadd an opt-in test that runs only when
docling_available()is true (skips cleanly otherwise).Acceptance Criteria
packages/stranske_pdf_extract/tests/test_docling_provider.py::test_docling_provider_conforms_to_protocolpasses in CI (asserts
isinstance(DoclingProvider(), MultiModalExtractionProvider)), AND the full package suitecollects a non-zero count and passes (confirmed-green locally: 27 passed).
name = "docling"attribute insrc/stranske_pdf_extract/providers/docling_provider.py(classDoclingProvider). With this change,test_docling_provider.py::test_docling_provider_conforms_to_protocolmust FAIL withassert isinstance(...) == False. Revert and confirm it passes. (Demonstrated locally during scaffolding.)pip install "git+…#subdirectory=packages/stranske_pdf_extract"importsstranske_pdf_extractwith thecore (no extras) and
importofprovidersdoes not requiredocling(onlyextract_modalitiesdoes).Implementation Notes
cd packages/stranske_pdf_extract && PYTHONPATH=src python -m pytest -q→27 passed.consumers install only what they need.
packages/stranske_pdf_extract/docs/DESIGN.md.