The index localizes 21/21 ranges exactly
The assertion that makes the coordinate mapping real
| Evidence | Value |
|---|---|
| Persisted index row | Annexure A claims printed pages 58–96 |
| Internal page-number block | Printed 58 occurs on physical PDF page 60 |
| Inferred mapping | PDF = printed + 2 |
| Mapped Annexure A range | PDF pages 60–98 |
The focused test asserts the exact 58 → 60 case. The measurement
command asserts the offset again before printing a result, so a parser that
silently reverts to zero offset cannot produce a green receipt.
What now exists
document_pages_v2.blocks
├─ table.cells (row / col / text) ──► claimed labels and printed ranges
└─ kind="page_number" ─────────────► printed-to-PDF offset
│
▼
cardinality · identity · location
│
├─ anomaly list
└─ missing / surplus reconciliation
src/shared/context/index_manifest.py reads the persisted shape
already produced by Textract projection. It makes no model call, adds no
schema, and needs no cloud capability. Story-3443 is the named production
caller that will feed these three independent inputs to the deterministic
combiner; Story-3442's measurement command is the first caller.
Ambiguity stays visible
| Condition | Output |
|---|---|
| Offset changes mid-bundle | offset_changed; locations remain unmapped |
| Roman-numeral preface | roman_numeral_preface |
| Range gap or overlap | gap / overlap |
| Inserted scan | inserted_scan |
| Amended index | amended_index |
| Duplicate label | duplicate_label |
| No index table | UNAVAILABLE with a reason; never an empty manifest |
The measurement receipt
docs/measurements/story-3442-index-baseline.json contains only
redacted index labels/ranges, observed endpoint page-number pairs, and the
hand-verified boundary ordinals. The script recomputes the score from those
observations; it does not copy a stored aggregate. Pass --pdf
to re-read every endpoint from the source paperbook with pdftotext.
It has 21 annexure rows—A through S, including M1/M2/M3. “21 parsed” is
extraction coverage, not 21 verified correct boundaries.
PYTHONPATH=. python scripts/measure_story_3442_index_baseline.py PYTHONPATH=. python scripts/measure_story_3442_index_baseline.py --pdf /path/to/paperbook.pdf parsed_index_rows: 21 printed_to_pdf_offset: 2 index_range_endpoint_localisation: ranges_checked: 21 matching_endpoints: 42/42 location_accuracy: 1.0 opening_internal_seam_diagnostic: precision: 1.0 recall: 0.5 f1: 0.667
Proofs
| Check | Result |
|---|---|
| Focused unit contract | 9 passed |
| Full unit suite with repo test DB | 4,713 passed |
| Red-first proof | A planted wrong endpoint changes the computed result to 41/42 and 20/21 ranges |
| Ruff | Changed Python files clean and formatted |
| Focused mypy | Clean with imports skipped; repo-wide imported debt remains outside this Story |
| Collision check | No file changed by open PR #970 is touched |