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

+35 -1
View File
@@ -5,7 +5,7 @@
//! is the current version.
/// Current schema version.
pub const SCHEMA_VERSION: u32 = 17;
pub const SCHEMA_VERSION: u32 = 18;
/// Migrations, in order. `MIGRATIONS[i]` migrates from version `i` to `i+1`.
pub const MIGRATIONS: &[&str] = &[
@@ -434,5 +434,39 @@ CREATE TABLE IF NOT EXISTS invoice_sends(
reference TEXT NULL,
note TEXT NULL
);
"#,
r#"
-- v18: evidence (plan P6, feature attachment_text): what was read out of
-- a file (`attachment.text_extracted`), the facts a human annotated it
-- with (`attachment.annotated`), and the duplicate an attachment was
-- withdrawn as. Extraction is its own record per (attachment, extractor,
-- version): an extractor upgrade adds one, never replaces one. A text
-- hash is the extraction's blob; the text itself is content-addressed in
-- the blob store. Amounts stay TEXT (exact decimal), never REAL.
CREATE TABLE IF NOT EXISTS extractions(
attachment_id INTEGER NOT NULL,
extractor TEXT NOT NULL,
version TEXT NOT NULL,
text_sha256 TEXT NULL,
pages INTEGER NOT NULL,
status TEXT NOT NULL,
seq INTEGER NOT NULL,
PRIMARY KEY(attachment_id, extractor, version)
);
CREATE INDEX IF NOT EXISTS idx_extractions_text ON extractions(text_sha256);
CREATE TABLE IF NOT EXISTS annotations(
attachment_id INTEGER PRIMARY KEY,
receipt_number INTEGER NULL,
payee TEXT NULL,
amount TEXT NULL,
date TEXT NULL,
instrument TEXT NULL,
category TEXT NULL,
source TEXT NULL,
reimbursable_to TEXT NULL,
note TEXT NULL,
seq INTEGER NOT NULL
);
ALTER TABLE attachments ADD COLUMN duplicate_of INTEGER NULL;
"#,
];