merge: P6, the evidence pipeline (branch P6, checkpoint ce366408)

The last of the paused branches, from its "not for merge" checkpoint:
extraction in ledger-import (text, pages, page images; capped, caught),
journaled as attachment.text_extracted; dedup by hash with
books.find_attachment and books.consolidate_duplicates; annotations and
books.set_entry_settles; the company record categories; the two fuzz
targets; feature attachment_text. Nineteen files conflicted with the
four P4b merges, resolved as plan 8.0.2 says: P6 retakes schema 18 (it
had taken 16, which S4.3 holds; S5 holds 17); the tool table is 129 and
the destructive count 31; both sides' appends kept with their seams
restored; one B-27 paragraph naming every feature; in the old-books
fixture P6's hand-written reimbursement is entry 7 (its ids collided
with S4.3's invoice); the replay fuzzer's list gains S7's
invoice.written_off; S4.3's issued-PDF test expects the extraction
record P6 journals right after a filing.

One integration defect between S7 and P6, found by the arap property
test and fixed here: under P6's dedup, a write-off whose evidence bytes
were filed already (the same collection letter for a second write-off of
the same invoice) was refused only after its entry had been journaled,
at the final link to the invoice ("already linked"). The write-off now
resolves the dedup before anything is journaled and keeps a link the
record already has to the invoice instead of refusing it; an explicit
existing_attachment_id already on an entry is still refused (S7's
one-receipt-once rule). P6's gate never ran before the pause; it runs on
main after this merge, and its ledger-store -> ledger-import dependency
is the open review point (plan 8.0.1).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
swaitsandClaude Fable 5.1 committed 2026-10-28 23:08:59 -06:00
commit 2ad192bbcd
70 files changed
+4618 -384

No files matched your search

+20
View File
@@ -115,6 +115,24 @@ the agent's cannot drift apart. The crate depends inward (`ledger-core`,
`ledger-store`, `ledger-config`, `ledger-import`, `ledger-vault`), never on
`ledger-mcp` or `ledger-gui`.
## The evidence pipeline (`ledger-import`, `ledger-core`, `ledger-store`, P6)
One extractor lives in `ledger-import` (`src/extract.rs`, D-53: in-process,
no new crate): a PDF's text and pages, an XLSX's cells as exact decimal
strings, and plain text; the caps are 25 MiB in, 30 pages and 2 MiB of
text, and a reader panic is caught there. `ledger-store` depends on
`ledger-import` so the writer can read a file as it is filed and journal
`attachment.text_extracted` (content-addressed text blob, extractor,
version, pages, `ok`/`none`/`failed`), one record per attachment, extractor
and version; `Store::verify` checks the text blob's hash and never
re-derives it. The server's filing scan (`tin_files`) and the viewer's PDF
rasterizer read through the same module, so a PDF's text is read one way.
Annotations and settlements are ledger state (`ledger_core::evidence`,
`Ledger::differs_from`), projected into schema 16's `annotations` table;
extractions have a table of their own. The viewer's Documents page groups
by category and filters by subject; Needs attention reads both through
`PackageBooks`.
## The journal format gate (`ledger-store`, P0)
Every journal line passes a gate after its parse, seq and chain checks
@@ -187,6 +205,8 @@ groups are:
- `write_offs` — `books.write_off_invoice`, the bad debt (P4b S7; rules.md
B-41), kept apart from `documents` so S4.4's document tools and this one
land in different files;
- `evidence` — finding a file by its hash, number or text, annotating it,
recording what a payment settles, and consolidating duplicates (P6);
- `settings` — the handbook, `books.settings` and the recorded FX rates
(the module is `settings_tools`, since `crate::settings` is the live
settings);