docs: document policy OCR capture, the feature no spec proposed
Policy OCR shipped 2026-08-01 (5e9cb12) and was documented nowhere. It is
not in INSURANCE_FEATURES_SPEC.md because it did not come from that
meeting — it came out of building the utility statement OCR pipeline in
RECEIPT_CAPTURE_SPEC.md §2 and noticing the same shape fits carrier
policy PDFs. A reader had no way to find that lineage.
New docs/POLICY_OCR.md covers it end to end, with weight on the three
things that are not obvious from the statement side:
- **One PDF = one policy.** Statements arrive bundled one customer per
page, so there a page is a document. A GMX certificate is one policy
across two pages, so the pages are concatenated and the parser runs
once per file — which is why `pageNumber` is a file ordinal and
`storageKey` is the source PDF, not a page image.
- **The GMX certificate carries no premium at all** — it lives on a
separate recibo PDF. Hence the null-preserving confirm and the
double-gated ledger write.
- **OcrModule was extracted out of StatementsModule to make this
possible**, and that was blocking rather than cosmetic.
Cross-referenced from RECEIPT_CAPTURE_SPEC.md §2 (where it came from),
INSURANCE_FEATURES_SPEC.md (which never proposed it, and whose §4 carrier
API it partly overlaps), PLAN.md step 11, README and RESUME.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -151,6 +151,21 @@ single-movement form.
|
||||
> blobs. `GET /statements/status` reports `ocrAvailable` and `storageAvailable`,
|
||||
> and the upload card hides itself unless both hold.
|
||||
>
|
||||
> **This pipeline turned out to generalise, and a second feature came out of
|
||||
> it.** Once render → OCR → parse → match → review existed for utility
|
||||
> receipts, the same shape obviously fit the *other* stack of paper this
|
||||
> office keys in by hand — carrier policy PDFs. That is
|
||||
> [`POLICY_OCR.md`](POLICY_OCR.md), built 2026-08-01, and it is **not in any
|
||||
> spec**; it was a revelation from doing this one. The `OcrProvider` seam was
|
||||
> lifted out of `StatementsModule` into its own `OcrModule` so the policy
|
||||
> module could inject it without taking on the statement pipeline —
|
||||
> `StatementsModule` imports it now and binds nothing itself. The engine
|
||||
> choice stays a one-line change in one file, for both features.
|
||||
>
|
||||
> One assumption does **not** carry over: statements arrive bundled *one
|
||||
> customer per page*, so here a page is a document. A policy PDF is one
|
||||
> document across several pages. See that doc's "One PDF = one policy".
|
||||
>
|
||||
> **Measured, not assumed.** Ten real scans (46 pages of CFE, CESPT and Telnor
|
||||
> bills) drove every decision below. Against them the shipped parser identifies
|
||||
> the provider on **46/46**, reads an account reference on **43/46**, an amount
|
||||
|
||||
Reference in New Issue
Block a user