# Five synthetic PDFs, six observed outcomes

These are small, deliberately regular examples, executed on 2026-10-14 with **pdfplumber 0.11.9 as the only extractor**. They are a characterization of these exact files and settings, not representative business documents, a tool comparison, or an accuracy estimate.

The human-readable evidence page is at `/tool-match/evidence/`. The matcher demo at `/tool-match/demo/` is separate: it runs documentation-based selection rules, not these extraction experiments.

## What was observed

- **Single-page ruled table, lines/lines:** the raw 4 × 3 grid exactly matched all 12 expected cells, including the header
- **Two-page ruled table, lines/lines:** both raw 4 × 3 grids matched. Separate example post-processing joined them into a 7 × 3 grid and removed an exactly repeated header. It assumes the tables belong together; pdfplumber did not infer continuation
- **Borderless table, lines/lines:** no table detected in this fixture
- **Same borderless table, text/text:** one table detected, but the header `Unit price` became `Unit`. Stripping cell-edge whitespace and removing wholly empty rows did not repair the missing word
- **90-degree page rotation, lines/lines:** a table was detected, but its 3 × 4 output was transposed/reversed relative to the expected 4 × 3 logical grid. The header also contained a line break. No correction was applied
- **Image-only copy, lines/lines:** zero characters and tables. This is the expected negative control without OCR, not an OCR test

The two configurations of the borderless file are separate observations of one fixture. Do not pool these results into a marketing percentage or infer that the same outcomes apply to every file or configuration.

## Reproduce locally

After downloading and extracting the evidence ZIP, open the `proof-of-use-evidence` folder. Python 3.12.14, Linux x86_64 and the pinned package versions were used for the recorded run.

First check the downloaded record and fixture hashes. This needs only Python's standard library:

```sh
python3 verify.py
```

To rerun extraction, use an isolated environment. Installing packages accesses the Python package registry; the experiments themselves use only local invented files:

```sh
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python run.py
.venv/bin/python verify.py
```

On Windows, use `.venv\Scripts\python.exe` instead of `.venv/bin/python`. Direct and key transitive dependencies are pinned, not a full platform-specific lockfile. Platform or dependency changes may change results or file hashes.

`run.py` regenerates the five PDFs, writes raw/normalized extraction results to `artifacts/results.json`, and renders PNGs into `previews/`. It replaces the downloaded result and fixtures in this extracted folder. Preserve a copy first if you want to compare with the recorded run. The execution timestamp changes on rerun.

`verify.py` checks the recorded hashes and known positive and negative observations. A passing verification means this characterization is consistent; it does not mean every extraction succeeded. The verifier alone does not execute pdfplumber. Inspect changed outcomes before changing the expectations.

## Inspect the evidence

- `artifacts/results.json`: exact raw output, expected grids, normalized output, settings, environment and SHA-256 fixture hashes
- `artifacts/*.pdf`: all five inputs
- `run.py`: fixture generation, extraction, generic normalization and explicit page-stitching code
- `verify.py`: characterization assertions, including the observed failures
- `requirements.txt`: package versions used for the run

The source and recorded artifacts were copied from the completed experiment without changing the measured outputs. The final recorded limit saying no public artifact was changed describes the original experiment; these copies are now published as separate evidence. The matcher dataset, ranking and compatibility labels remain unchanged.

## Provenance and limits

All fixture text and numbers are invented. ReportLab generated the PDFs; PDFium rendered the image-only copy and previews. No customer documents, borrowed PDFs, personal data, credentials, logs, network calls during extraction, model weights, or OCR pipeline were used. The generator uses built-in Helvetica text and no outside image assets. Dependency licenses remain their own; this bundle makes no claim to license third-party software or models.

Only pdfplumber was executed as an extractor. Camelot, Tabula, Docling and PaddleOCR were not run. There were no speed, memory, security, production robustness or comparative-ranking measurements. The fixtures use regular English text and simple numbers, with one small example per layout; they do not establish broad compatibility.

The two settings are exactly `vertical_strategy/horizontal_strategy = lines/lines` and `text/text`. There is no page crop, fixture-specific extraction coordinate, expected-cell substitution or corrective row/column reordering. Normalization only strips cell-edge whitespace and removes wholly blank rows. Raw output remains alongside normalized output. Explicit page joining assumes a known continuation and cannot handle unrelated tables or split/missing rows.
