truecopy1.0.0

Why refusing matters

Two readers written for different documents, sharing no line of code, arrived at the same five rules. When two teams converge without speaking, that is not a preference - it is the shape of the problem.

The worst defect a document reader can have is not missing something. It is returning a table that looks right out of a document it misread — because a table that looks right is never checked.

That is the whole argument, and everything in this library follows from it.

The five laws

Two readers, written for different documents — one for bank statements, one for career records — sharing no line of code, arrived at these five separately. When two teams converge without speaking, it is no longer a preference.

1. The document checks itself

A statement carries opening + Σ = closing. A career record announces its own total of quarters. An invoice announces its total. Setting your reading against what the document declares is the only check that depends on no layout at all — it works on an issuer you have never seen, in a language you do not read.

Measured: eighteen per-year point values on a real career record summed to 4112,03, and the document announced 4112,03. Eighteen decimals landing to the cent do not land by accident. When they do, the table was read entirely and exactly — no line skipped, no value misread, nothing counted twice.

That is selfCheck, and it is the first thing to write.

2. Refusing beats returning a plausible table

Fed a document it could not parse, one of these readers produced twenty-two findings, none of which meant anything — the document carried neither of the two figures the tool knows how to check. It did not fail. It answered confidently, about nothing.

A refusal is an answer. It takes the place of the result, and it carries the next move — because a refusal with no way out is a dead end.

3. Counting is not measuring

A tempting shortcut: run two readings and keep the one that finds more rows. It always picks the worse one. A reader that cuts badly finds more, because it turns footnotes and page furniture into data.

So read returns no score. The document decides, not the count.

4. The reader proposes, the person confirms

The correction screen is part of the product, not the recovery path. Which means every row a person is asked to confirm must carry where it came from — a value nobody can point at is a value nobody can check. Handed a list of figures, a person hunts through the document again; handed a place, they jump to it.

That is rowsToReview, and placesOf.

5. Every quantifier is bounded

These patterns run over a whole document, line by line. An unbounded quantifier there is not slow — it is a page that never comes back. This one is not in the kit, because a naive scan of source produces false positives; it is held by eslint-plugin-regexp and its no-super-linear-backtracking rule, in your own gate.

The name research gives it

The machine-learning world arrived at the same place from the other side, and named it: calibrated abstention. A 2026 architecture for enterprise document AI describes “the system declines rather than guesses when grounding is insufficient”, paired with “evidence-based confidence that verifies extractions against the source document”.

Word for word: refuse and selfCheck.

Models trained to say “I don’t know” cut false-confident answers by a factor of two to five. The same literature names why it stays rare: benchmarks penalise abstention, and training amplifies the bias, so the whole machine is tuned to guess with confidence.

A deterministic parser has no excuse to inherit that.

What the library does not promise

It does not promise to read an unknown layout correctly.

Measured on a real bank statement whose header labels were hidden: the page-wide spread of x proposed twelve columns where the table had five — it counts the letterhead, the address block and the footer as evidence of where a column starts. Cutting on the rows that share the table’s shape brought it to seven, and named three of the roles from content alone. The reading still came back wrong.

The only reason that was visible is that the rows did not add up to the balances the document declares.

It does not promise to read an unknown layout correctly. It promises to tell you when it did not.

That is a smaller claim than the one every extractor makes, and it is the only one worth making about somebody’s money.