From d19fb464b7b000163974b2e00773f53bb664f0a2 Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Tue, 27 Oct 2026 06:34:18 -0600 Subject: [PATCH] docs(plan): S4.3 as built (P4b S4.3) The store now journals the documents_v2 fields, previews without journaling, files the issued copy and locks invoicing.first_number once a number exists. This records the departures: the store's create commands keep their signatures and delegate to _with variants, the issued-copy call takes the create's arguments expanded (the store has no params struct), schema 16 adds the document columns only (the projection has no parties table), the over-the-wire document cut-over entry waits for S4.4, and a refusal leaves the journal unchanged while a storage failure between the invoice's lines and its attachment's is not rolled back. --- plan/served.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plan/served.md b/plan/served.md index 0f6d24c..461a8c9 100644 --- a/plan/served.md +++ b/plan/served.md @@ -1317,7 +1317,13 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1 5. **Files:** owns `crates/ledger-core/src/arap.rs` (S4.1), `crates/ledger-mcp/src/tools/documents.rs` (S4.4), `crates/ledger-import/src/invoice_pdf.rs`, `crates/ledger-import/templates/invoice.typ`, `crates/ledger-package/src/invoice.rs`, `crates/ledger-gui/src/pages/invoices.rs`, `crates/ledger-mcp/handbook/invoices-and-bills.md`, `crates/ledger-cli/tests/documents.rs`; touches the 8.0.3 files. 6. **Tests and proofs:** the tests named in each step; Kani `discount_max_is_bounded`, `line_amount_is_exact`; bridge properties for both; no Lean change (no new `Ledger` command: the document steps are the existing ones with more fields). bookspec (added to `bookspec/examples/` now; the loader in `crates/ledger-core/tests/bookspec.rs` gains `due_date` and `terms` on `InvoiceSpec`/`BillSpec`): `payment-terms-due-date`, `invoice-numbers-run-and-voids-keep-theirs`. 7. **Done when:** (1) every test in steps 6, 9, 10, 11, 17, 19, 20 exists and passes; (2) the S1 tests named in 8.1 (`legacy_documents_replay_with_tags`, `legacy_reversal_now_counts`, `a_payment_journals_its_method_and_reference`, `several_payment_events_on_one_entry_tag_its_lines_in_order`) and the viewer's `the_list_shows_the_ledgers_figures` pass unchanged; (3) `no_new_fields_journals_byte_for_byte` proves an old-shape document is byte-identical; (4) the 8.0.6 checklist is in the PR; (5) `just check` and `just prove` green; (6) the handbook section renders; (7) no figure in any golden changed. -8. **As built:** none yet. +8. **As built:** S4.3 (2026-10-27, `a47af074`), departures only: + - `Store::create_invoice`/`create_bill` keep their signatures and delegate to the new `Store::create_invoice_with`/`create_bill_with`, which take `arap::InvoiceFields`/`BillFields` (the core's own `_with` pattern), rather than the four-argument commands growing a fifth argument. Every existing caller is unchanged. + - Item 11's `(params, pdf_bytes)` is expanded in the signature: `create_invoice_issued(customer_id, date, due_date, lines, fields, pdf_bytes) -> (InvoiceId, EntryId, u64)`, an attachment id being a `u64` as `attach_receipt` already returns. The store has no params struct, and inventing one would be a second carrier beside `InvoiceFields`; `preview_invoice`/`preview_bill` take the same arguments and return `InvoicePreview`/`BillPreview`. + - Schema 16 adds the document columns only (`invoices.number, terms, bill_to, seller, customer_ref, memo`; `bills.vendor_ref, received_on, terms, memo, duplicate_reason`; a line's fields ride `lines_json`). The projection has no parties table for the planned `parties.email` and terms columns, and the party record reaches every reader through replay, so none was invented. `differs_from` needed no new arm: it compares whole invoices, bills and parties, and `documents_v2_waits_for_the_upgrade` fails if replay loses a field. + - Item 13's 8.0.6 item 3 (R-A step 4): the over-the-wire call for a *document* carrying the new fields cannot exist before S4.4's tool arguments do, so `books_p2_served_cut_over_whole` keeps S4.2's `invoicing.default_terms` entry, which refuses before consent and is taken after; the store-level before/after is `documents_v2_waits_for_the_upgrade`. S4.4 adds the document call to the same list. + - `issued_pdf_is_filed_with_the_invoice_or_nothing_is` proves every *refusal* leaves the journal unchanged; `create_invoice_issued` has no transaction over journal appends, so a storage failure between the invoice's lines and the attachment's is not rolled back. The PDF's bytes are stored before the first line, so that window is an I/O failure alone. + - `preview_invoice` takes a number only in books that have declared `documents_v2`, so books that haven't keep the legacy "Invoice {id}" shape and can still file an issued copy before the upgrade (8.3.14 item 5). #### P4b S5: sent tracking (`invoice.sent`)