docs: the 2026-10-28 drift review; the plan, status and docs brought to date
check / check (push) Canceled after 0s
two-user / two-user (push) Canceled after 0s

The planning session read plan/served.md, every design document and the
five branches the owner paused on 2026-10-27 against main (44ee4083),
with dry-run merges touching no branch. plan/2026-10-28_DRIFT_REPORT.md
lists every divergence and judges every recorded departure (all kept;
three owed back; one needs a decision: P6 made ledger-store depend on
ledger-import).

The plan: section 0 "What changed on 2026-10-28"; 8.0.1 and the unit
Status lines name S4.4, S5, S6, S7 and P6 as built but unmerged; 8.0.2
records the destination (D-56: the installed app, P11a starts now) and
the resume order with the known conflicts (the shared documents.rs
test file, the types.rs appends, P6 retaking schema 18, the law numbers
34 to 37); 8.0.3 lists the names the EM approved during the wave; P11a
gains step 0 (the macOS and Windows keyring stores, the Windows data
root and pipes, a cross-platform CI build: today the agent path runs on
Linux alone); Q-5 is due and Q-8 asks whether D-47 to D-54 stand; the
Landlock sentences in section 2 and server.toml are struck.

STATUS.md and HANDOFF.md say where things stand and how to resume;
roadmap.md and gui.md are rewritten to today. The docs lose their
stale facts: 122 tools, 2,700 tests, the parity floor at 21 with the
P4b notes the slices never wrote, the ten crates and their dependency
graph (jiff added to the core's allowed list), the cutover of
2026-10-20 recorded in capability-parity.md and parallel-run.md, the
P4b S1 law and its two Kani harnesses added to verification.md (law
34), the proof counts (51 and 9), and README, the site and install.sh
honest about macOS (the viewer runs; connecting an agent waits for
P11a's keyring store, and the installer now says so instead of failing).

just check on main at 44ee4083: exit 0 (167 suites, 2,871 passed, 0
failed, 7 ignored, the server-only build clean). No code changed.

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 18:26:23 -06:00
1 parent 44ee408312
commit af553a3706
21 files changed
+662 -220

No files matched your search

+11 -3
View File
@@ -149,8 +149,10 @@ clone, with status. Rules:
`post_entry`, `reverse_entry`, `add_account`). Struct fields stay private;
no other mutation path may exist.
- `ledger-core` depends only on `rust_decimal`, `thiserror`, `chrono`,
`serde`, `serde_json`. New dependencies need justification in the commit
message. No I/O, no networking, no time-source in the core.
`serde`, `serde_json`, and `jiff` (the bundled time-zone database for
`company.timezone`: "today" is computed by the caller and passed in;
the core still reads no clock). New dependencies need justification in
the commit message. No I/O, no networking, no time-source in the core.
- Future crates (`ledger-store`, `ledger-import`, `ledger-oracle`, `books-app`)
depend inward toward the core, never the reverse. See `docs/architecture.md`.
@@ -174,6 +176,8 @@ clone, with status. Rules:
| Read this | When you need |
|---|---|
| `plan/served.md` | The plan every remaining unit is built from: section 8.0 (status, order, recipes), 8.2 (the units), 10 (decisions) |
| `plan/HANDOFF.md` | The prompt for the implementing team, and how to resume the paused worktrees |
| `docs/requirements.md` | What the engine must do (R-1…), what is future work |
| `docs/architecture.md` | Crate layout, command pattern, dependency rules |
| `docs/oracle.md` | How we check correctness: golden files, property tests, fuzzing, cross-checks against other implementations (and who is right) |
@@ -183,9 +187,13 @@ clone, with status. Rules:
| `docs/capability-parity.md` | Parity vs the GSheet+GDrive system + the cutover rule |
| `docs/mcp-interface.md` | The MCP tool surface: the primary interface spec |
| `docs/receipt-store.md` | Blob store + `ledger-store` SQLite persistence spec |
| `docs/testing.md` | Every test layer, each unit's test record, and what P12 must mutate |
| `docs/parties-and-attachments.md` | The party directory, roles, the TIN vault, attachments to any subject |
| `bookspec/README.md` | The formal accounting specification's examples, checker and runner (P13) |
| `deploy/README.md` | Running the books on a machine of your own (P9a) |
| `docs/glossary.md` | Debit/credit and friends, for agents new to accounting |
| `plan/STATUS.md` | Where the project stands right now |
| `plan/roadmap.md` | Phase plan: semantics → oracle harness → egui app → workflow parity |
| `plan/roadmap.md` | Where the project has been and is going: the installed app, then the hosted service |
## License
+29 -12
View File
@@ -16,7 +16,7 @@ through MCP. Self-hosted, no rent.
append-only, hash-chained JSONL journal; SQLite is a disposable
projection rebuilt from it; receipts live in a content-addressed blob
store. Drafts are durable, corrupt projections self-heal.
- **`ledger-mcp`** — the AI-first interface. 118 MCP tools, served by the
- **`ledger-mcp`** — the AI-first interface. 122 MCP tools (2026-10-28), served by the
books server (`wanderbooks server`) on the data root's local sockets and
reached through the agents' bridge (`wanderbooks mcp --book ID`): draft →
preview → post workflow, server-side receipt
@@ -39,7 +39,7 @@ through MCP. Self-hosted, no rent.
This is the storytold way applied to accounting: agents verify against
oracles, never ship what they haven't demonstrated.
- 190+ workspace tests: invariant tests encoding accounting law, golden-file
- About 2,700 tests across the two workspaces (2026-10-28): invariant tests encoding accounting law, golden-file
report snapshots, property tests (proptest), end-to-end MCP tests through
a real books server.
- **Formal proofs of the accounting laws** (`just prove`,
@@ -51,8 +51,9 @@ oracles, never ship what they haven't demonstrated.
pass found three engine bugs that every test, fuzzer, and mutant had
missed: negative amounts accepted, and two crashes on oversized
amounts. It also caught a soundness bug in the model checker itself.
- Mutation testing via cargo-mutants; fuzzing via cargo-fuzz (11.5M+
executions, zero crashes).
- Mutation testing via cargo-mutants (paused for development until the
P12 max-testing pass, D-33; CI's weekly shards still run); fuzzing via
cargo-fuzz (11.5M+ executions, zero crashes).
- GnuCash is *a* behavioral cross-check, never the authority and never
a code source (clean room, MIT OR Apache-2.0). Accounting principles,
proved, are the spec. Where any other program disagrees, we work out
@@ -60,10 +61,16 @@ oracles, never ship what they haven't demonstrated.
## Status
Parity is 12 of 12 against the spreadsheet workflow it replaces
(`docs/capability-parity.md`). The parallel-run plan
(`docs/parallel-run.md`) is written; the Google Sheet stays the system of
record until a clean month and explicit cutover approval.
Parity is 12 of 12 against the spreadsheet workflow it replaced
(`docs/capability-parity.md`); the books cut over on 2026-10-20 and the
Sheet is frozen as of 2026-10-11. The remaining work, its order and its
hand-off are `plan/served.md` section 8.0; the destination is one
installed app for Mac, Windows and Linux (P11), then the hosted service
the plan describes and does not build. Today the agent path runs on
Linux: tokens live in the OS keyring and only the Linux Secret Service
store exists, so on macOS the viewer and server run but `wanderbooks
connect` and the agent bridge wait for P11's keyring stores; Windows is
WSL2 only.
See [`plan/STATUS.md`](plan/STATUS.md) for where things stand and
[`plan/roadmap.md`](plan/roadmap.md) for where it's going.
@@ -82,6 +89,10 @@ them; nothing needs sudo):
curl -fsSL https://wanderbooks.ai/install.sh | sh -s -- acme
```
(Linux today. On macOS the same line installs and sets up, and the
viewer runs, but connecting an agent waits for P11's keyring store; on
Windows run it inside WSL2.)
Already installed, three commands: `wanderbooks setup`, `wanderbooks books
create acme`, `wanderbooks connect claude --book acme` (or `connect codex`).
Then talk to the agent; `wanderbooks gui acme` shows the books, and its
@@ -102,15 +113,21 @@ just # lists the recipes: check, build, prove, demo, ...
```
crates/ledger-core/ # engine: money, accounts, journal, ledger, reports
crates/ledger-store/ # journal + SQLite projection + blob store
crates/ledger-mcp/ # MCP server: 118 tools, resources, handbook, receipt policy
crates/ledger-mcp/ # MCP server: 122 tools, resources, handbook, receipt policy
crates/ledger-import/ # QBO CSV import, IIF/XLSX export
crates/ledger-config/ # wanderbooks.toml company settings
crates/ledger-cli/ # `wanderbooks`: the one executable (every mode)
crates/ledger-host/ # the host, the agents' bridge, the owner's commands
crates/ledger-package/ # The CPA package and the 1099 worksheet (server and viewer)
crates/ledger-package/ # the shared read-only view: the CPA package, the invoice PDF, Needs attention
crates/ledger-vault/ # the TIN vault (XChaCha20-Poly1305 under the book's key)
crates/ledger-gui/ # the viewer: read-only, live (egui)
docs/ # requirements, architecture, oracle, parity, glossary
plan/ # STATUS.md, roadmap.md
verify/lean/ # the accounting laws as Lean theorems (`just prove`)
bookspec/ # the formal accounting specification: checker, runner, examples (P13)
fuzz/, oracle/ # fuzz targets; the GnuCash differential (`just oracle`)
deploy/ # the self-host recipe and system unit (P9a)
site/ # wanderbooks.ai and install.sh
docs/ # requirements, architecture, oracle, parity, testing, verification, spec, glossary
plan/ # served.md (the plan), STATUS.md, roadmap.md, HANDOFF.md, gui.md
AGENTS.md # operating manual for agents working here
```
+48 -28
View File
@@ -21,21 +21,51 @@ are free functions: pure, total, and deterministic. Same ledger in, same
report out, every time, on every platform. That determinism is the entire
basis of `docs/oracle.md`.
## Current crate layout
## The crates (2026-10-28)
```
crates/ledger-core/
src/
lib.rs # crate docs, re-exports, design rules
money.rs # Currency + Money (Decimal, checked arithmetic)
account.rs # AccountType, Side, Account, ChartOfAccounts
journal.rs # JournalLine, JournalEntry, validate()
ledger.rs # Ledger: the command surface, append-only log
reports.rs # trial_balance, unclosed_earnings, balance_sheet, snapshot
tests/
invariants.rs # accounting-law tests + randomized property test
golden/ # hand-verified expected report snapshots
```
Two Cargo workspaces: the engine and its application in `crates/`, and
the specification in `bookspec/` (which never depends on the engine).
| Crate | Role | Depends on (ours) |
|---|---|---|
| `ledger-core` | the semantics engine: money, chart, journal, `Ledger` commands, reports, periods, assets, schedules, parties, A/R and A/P, payroll, projects, settings and conventions, the kernel and its Kani harnesses | nothing |
| `ledger-vault` | the TIN vault: XChaCha20-Poly1305 records under the book's key | nothing |
| `ledger-config` | the `wanderbooks.toml` codec (adoption in, `books.export_settings` out) and the receipt policy until P4 moves it into the core | `ledger-core` |
| `ledger-store` | the source of truth: the hash-chained JSONL journal, its format gate, the SQLite projection (schema 16; a file per schema), the blob store, backups, the access log, `Snapshot` for readers | `ledger-core` |
| `ledger-import` | formats: QuickBooks CSV in; IIF, XLSX, Typst PDFs (statements, the invoice, labels) out | `ledger-core` |
| `ledger-package` | the shared read-only view over `Store` or `Snapshot` (`PackageBooks`): the CPA package, the 1099 worksheet, the invoice document, Needs attention | `ledger-core`, `ledger-store`, `ledger-config`, `ledger-import`, `ledger-vault` |
| `ledger-mcp` | the books server: the MCP tools (122), resources, the handbook, scopes, the door and the access log, backups' scheduling | all of the above |
| `ledger-host` | the host and its leases, the agent bridge (`wanderbooks mcp`), tokens in the OS keyring, the owner's commands, uploads and downloads | `ledger-store`, `ledger-mcp`, `ledger-config` |
| `ledger-gui` | the viewer: read-only, live, egui; the Books menu hands work to the server | `ledger-core`, `ledger-store`, `ledger-config`, `ledger-import`, `ledger-package`, `ledger-vault`, `ledger-host` |
| `ledger-cli` | `wanderbooks`, the one executable: every mode (`serve`, `server`, `host`, `mcp`, `gui`, `setup`, `books`, `token`, `connect`, `doctor`, …) and the over-the-wire test suites | everything |
| `bookspec/checker`, `bookspec/runner` | the example schema and parser, the rule catalogue, the `Engine` trait; the per-rule runner | nothing of ours (the adapter in `ledger-core`'s tests depends on them) |
Dependency direction is always inward toward `ledger-core`; nothing in
the core depends on another crate of ours. UI concerns (formatting,
locale, widgets) never leak into the core; the core speaks `Decimal` and
ISO codes. A crate that was planned and never created is not missing:
`ledger-export` became part of `ledger-import`; `ledger-oracle` is the
test `crates/ledger-core/tests/oracle_gnucash.rs` with `oracle/gnucash/`
(`just oracle`); `ledger-view` and `ledger-extract` were closed by D-53
(`PackageBooks` is the shared view; extraction is in-process in
`ledger-import`, P6).
Pending (the P6 branch, 2026-10-27, unmerged): P6 made `ledger-store`
depend on `ledger-import` so the writer can extract a file's text at
attach time and on the backfill command. That keeps the direction inward
but pulls Typst, the fonts and hayro into the store's dependency closure;
whether it stands, or extraction moves to the server before the store
call, is decided at P6's review.
`ledger-core` itself (`crates/ledger-core/src/`): `money`, `account`,
`journal`, `ledger` (the command surface and replay), `kernel` (every
money arithmetic, generic over `Amount`) and `proofs` (its Kani
harnesses), `reports`, `cashflow`, `analysis`, `periods`, `assets`,
`schedules`, `recurring`, `payouts`, `payroll`, `form1099`, `tax`,
`classes`, `parties`, `arap`, `settings`, `conventions`, `calendar`,
`shares`, `tax_capital`, `rules`, `error`; its tests in `tests/`
(`invariants.rs`, `properties.rs`, `spec_*.rs`, `kernel_bridge.rs`,
`model.rs`, `bookspec.rs`, `golden/`).
## Dependency rules
@@ -45,24 +75,14 @@ crates/ledger-core/
- `thiserror` — the error type
- `chrono` — dates (`NaiveDate`; no wall-clock reads in the core)
- `serde` / `serde_json` — the oracle interchange format
- `jiff` — the bundled time-zone database behind `company.timezone`
("today" is computed by the caller and passed in; the core reads no
clock)
New dependencies need justification in the commit message. In particular:
no I/O, no networking, no async runtime, no logging framework in the core.
The core is a pure domain library and stays that way.
## Future crates (do not create until the roadmap says so)
| Crate | Purpose | Depends on |
|---|---|---|
| `ledger-store` | Journal (hash-chained JSONL) + SQLite projection, blob store | `ledger-core` |
| `ledger-import` | QuickBooks CSV read-only import (bank transactions, chart of accounts) | `ledger-core` |
| `ledger-export` | Format renderers: CSV, XLSX, IIF journal entries (QuickBooks Desktop) | `ledger-core` |
| `ledger-oracle` | Cross-check harness: our engine vs other implementations (GnuCash first) on fixture books; diffs are adjudicated, not obeyed | `ledger-core`, `ledger-import` |
Dependency direction is always inward toward `ledger-core`. Nothing in the
core may depend on a future crate. UI concerns (formatting, locale, widgets)
never leak into the core; the core speaks `Decimal` and ISO codes.
## Why Rust
Exact decimal semantics, exhaustive pattern matching on the five account
@@ -127,7 +147,7 @@ engine keeps them beside the ledger (`ledger_core::settings::Settings`,
`ledger_core::conventions::Conventions`, fields of `Ledger`), so the store,
its replay and the viewer's `Snapshot` share one reading; `Ledger::
differs_from` and `verify` compare them, and the projection has a table
for each (schema v12). `ledger-config` is the codec between them and a
for each (schema 16 on 2026-10-28; a file per schema). `ledger-config` is the codec between them and a
`wanderbooks.toml` (`codec::import`, `codec::export`): adoption (`wanderbooks
books adopt`) moves an older books dir's file in through it, once, and
`books.export_settings` writes the books' settings out as one. The books
+10 -1
View File
@@ -43,7 +43,16 @@ Statuses: `covered` (built and tested), `partial` (built, known gaps listed),
- Row 12 is deliberately excluded. Email filing is a mail problem, not a
books problem; it stays where it is.
## Cutover rule
## Cutover: done 2026-10-20
The three conditions below were met and the owner said so: the books were
adopted into the server's data root as the first company's live books on
2026-10-20 (P2 slice 9), the Sheet is frozen as of 2026-10-11 with the
final `verify-sheet` run filed as a workpaper, and the old copies moved
into the data root's `legacy/` (Q-3, D-2). The rule is kept for the record
and for the next company.
## Cutover rule (as it was)
The sheet does not retire on a date. It retires when **all three** hold:
+7 -3
View File
@@ -8,12 +8,16 @@ exposes both over the Model Context Protocol — the open standard, so the
books are drivable by any MCP client (Muse, Claude Code, IDE agents), not
locked to one assistant.
## Crates in this phase
## Crates
| Crate | Role | Spec |
|---|---|---|
| `ledger-store` | SQLite persistence, blob metadata, event log | `docs/receipt-store.md` |
| `ledger-mcp` | MCP server wrapping store + core | this document |
| `ledger-store` | the hash-chained journal (the source of truth), the SQLite projection, the blob store | `docs/receipt-store.md` |
| `ledger-mcp` | the books server: the tools, resources and handbook over store + core | this document |
| `ledger-host` | the agent bridge (`wanderbooks mcp`), the host and its leases, tokens | `plan/served.md` 3.3, 3.9 |
(The overview sections of this document date from the first MCP phase; P5
rewrites them. The per-tool sections are held to the code by a test.)
Rust, `rmcp` SDK (the Rust MCP SDK). The MCP crate holds no accounting
logic: it translates tool calls into `Ledger` commands and formats results.
+10 -9
View File
@@ -53,7 +53,7 @@ case: partial first/final months in different-length calendar months don't
complement, so the lifetime total drifted by cents (fixed with the
final-month true-up in `depreciation_schedule`).
**Layer 3 — Mutation testing (live now).** `cargo mutants -p ledger-core`
**Layer 3 — Mutation testing (paused for development until P12, D-33, 2026-10-20; CI's weekly shards still run).** `cargo mutants -p ledger-core`
(228 mutants as of 2026-10-10: 159 caught, 28 unviable, 2 timeouts from
induced infinite loops, 39 missed). Every *missed* mutant is triaged:
real gaps get new tests (this pass added parent-account validation,
@@ -94,12 +94,11 @@ built through wanderbooks (entries, foreign lines, reversals, closes),
every account's balance at month ends and random dates, and each month's
P&L, compared exactly (15,800 comparisons). Its first run found one real
difference, adjudicated from principles: wanderbooks kept sub-cent
amounts on foreign lines; it now books in cents (rules.md B-3). The
original plan follows. A
`ledger-oracle` crate will run fixture books through our engine and through
other implementations (GnuCash headless first), then diff `snapshot()`
output automatically: `cargo xtask oracle`. This is the direct analog of
storytold's `cargo xtask corpus` / `oracle_diff`, with one difference: a
amounts on foreign lines; it now books in cents (rules.md B-3). What the
original plan still owes (roadmap phase 3): fixture books, not only random
ones, diffed as `snapshot()` output automatically, inside the harness as
it is (no `ledger-oracle` crate is planned: D-53). This is the direct analog
of storytold's `cargo xtask corpus` / `oracle_diff`, with one difference: a
diff does not mean we are wrong. Each one is adjudicated from principles
(see "Who is right"). Note also: GnuCash is *a* behavioral cross-check, not
a file-format target
@@ -113,8 +112,10 @@ evidence. It never overrides them.
## What the oracle does NOT cover (yet)
- **Workflows**, only semantics: that an invoice *posts the right lines* is
oracle-covered; that the invoice *screen* is usable is a UI concern for the
egui phase, where storytold's screenshot-in-the-loop comes back.
oracle-covered; that the invoice *screen* is usable is the viewer's
concern (since 2026-10-12: `crates/ledger-gui/tests/*.rs` render every
page with `shot(..)` and `tests/view_model.rs` holds every figure shown
to the engine's).
- **Tax law.** The engine computes what you tell it; it does not know the
tax code. Tax-adjacent logic gets its own fixtures and its own goldens
when it arrives, sourced from IRS publications — never from memory.
+6
View File
@@ -1,5 +1,11 @@
# Parallel-run readiness
> **Historical (2026-10-28).** The run happened; the books cut over on
> 2026-10-20 (P2 slice 9, `plan/STATUS.md`): the Google Sheet is frozen
> as of 2026-10-11, its final comparison (`verify-sheet`) is a filed
> workpaper, and the books are the system of record. Kept as the record
> of how cutover was decided. The counts below are of 2026-10-11.
The Google Sheet stays the system of record until the parallel run passes
and the owner explicitly approves cutover. This doc is the plan; the run
itself needs the owner's go-ahead.
+19 -4
View File
@@ -8,7 +8,7 @@ Statuses: `done` = implemented + invariant-tested + golden-covered.
`partial` = implemented but missing tests or goldens. `todo` = not started.
No other statuses.
**Floor: 10 done** (2026-10-10; fixed-asset register added).
**Floor: 21 done** (2026-10-28; it was 10 on 2026-10-10, when the fixed-asset register was added, and the sections below record each rise).
| Area | GnuCash counterpart (a cross-check, not the spec) | Status | Notes |
|---|---|---|---|
@@ -34,8 +34,8 @@ No other statuses.
| Bank reconciliation (cleared flags + report) | Reconcile | done | — |
| QuickBooks CSV import (bank txns, chart of accounts) | Banking → Upload | done | R-FUTURE-4 |
| QuickBooks IIF + XLSX export | Export / reports | done | R-FUTURE-4 |
| A/R invoices + payments + aging | Business → Invoices | done | R-FUTURE-5 |
| A/P bills + payments + aging | Business → Bills | done | R-FUTURE-5 |
| A/R invoices + payments + aging | Business → Invoices | done | R-FUTURE-5; since P4b S1 (D-45) a document's paid, outstanding and status are read from its tagged ledger lines, hand lines on the receivables account are refused, `books.void_document` and `books.control_check` tie the subledger to the control account (rules.md B-38); S2 `books.documents`/`books.document` and the viewer pages; S3 the invoice PDF; S4.1-S4.3 terms, numbers, line accounts, the issued PDF filed at issue (behind `documents_v2`, the owner's next upgrade) |
| A/P bills + payments + aging | Business → Bills | done | R-FUTURE-5; the same S1 derivation and control guard on the payables account; S4.1-S4.3 the vendor's invoice number, terms, every line on its own account (behind `documents_v2`) |
| Payroll runs (accounting only, no tax tables) + tax remittance | Payroll | done | — |
| Tracking classes (divisional P&L) | Class tracking | done | invoice and bill lines take a class too (projects, rules.md B-37 item 8; QBO/Xero class or tracking per line) |
| CPA handoff package (TB + GL xlsx, P&L + BS pdf, zip) | Reports → export | done | — |
@@ -44,7 +44,7 @@ No other statuses.
| Payout gross-up (deposit → revenue, fees, adjustments) | Bank deposit with fee lines; Xero/QBO Stripe & Shopify integrations | partial | hand-verified fixture incl. classes and a negative payout; no statement parsers yet |
| 1099 vendor tracking + year-end worksheet | Vendors → Track payments for 1099; 1099 report | partial | hand-verified fixture (bill payments, card exclusion, reversal, year boundary); no golden file yet |
| Prepaid expense + deferred revenue amortization | Amortization schedules (Xero/QBO add-ons) | partial | hand-verified fixture, to the cent; no golden file yet |
| Automated cross-implementation diff harness (GnuCash first) | — (our `xtask oracle`) | todo | roadmap phase 3 |
| Automated cross-implementation diff harness (GnuCash first) | — (`just oracle`) | partial | live: `tests/oracle_gnucash.rs` runs 200 random books through GnuCash 5.10 in a pinned container, 15,800 exact comparisons, weekly in CI (docs/oracle.md Layer 5); open: fixture books diffed as `snapshot()` output, and the machine-readable catalog with CI enforcing this floor |
Workflow/UI parity (QuickBooks/Xero reference) gets its own catalog when the
egui phase starts; semantics come first.
@@ -63,6 +63,21 @@ D-46); no file with a full TIN is filed into the books (B-26); the agent is
told the rules in force in a short connect text and a handbook, and no
agent text points at the books' files, git or the repo.
## P4b: receivables and payables, first class (D-45; 2026-10-23 to 2026-10-27)
The two A/R and A/P rows above were `done` before P4b and stay `done`;
what moved is their notes, so the floor stands at 21. S1 changed what the
figures *are* (derived from tagged standing lines, so a reversed payment
no longer counts and a void is exact; proven by Lean `control_agrees`
and Kani `bounds_kept_is_the_definition_on_books_in_bounds`), S2 and S3
added the read tools, the viewer pages and the PDF, and S4.1 to S4.3
added terms, numbers, line accounts, the parties' snapshots and the
issued copy, journaled only when set so an old-shape document is byte
for byte the same. The rest of P4b (S4.4 and S4.5, S5 sent tracking, S6
paying on terms, S7 bad debts) is built on paused branches or open as
`plan/served.md` 8.0.1 says; each adds a note to these rows when it
lands. No golden moved.
## U0b: one attention engine (D-53, 2026-10-26)
No semantic feature changed, so no status moved and the floor stands (10
+4 -1
View File
@@ -2,7 +2,10 @@
Design for two features built together (the owner, 2026-10-15): a directory
of the parties the company deals with, and attachments that link to any
subject. Status: design; built after asset tax basis.
subject. Status: built (2026-10-15 to 2026-10-17: parties with roles, the
TIN vault, attachments linked to any subject; the party's contact block,
D-55, is built on branch S4.4 as of 2026-10-28). The design is kept as
written; departures are in `plan/served.md` and `docs/spec/rules.md` B-26.
## Why together
+8 -7
View File
@@ -184,11 +184,12 @@ Suspected corruption is fixed by rebuild, never by forensics.
projection from the journal and comparing reports before/after. A newer
schema version than the binary understands is a hard error, not a guess.
## Migration from Google Drive
## Migration from Google Drive (done)
Backfill walks the Drive `the first company` folders and files each
document via the equivalent of `books.file_document` with its category.
The Drive folders stay exactly as they are until the capability-parity
cutover rule (see `docs/capability-parity.md`) is satisfied. Migration is an
implementation task, not part of this spec — but the spec is written so the
migration is a straightforward script, not a redesign.
The company's records were filed into the books at the P1 cutover
(2026-10-17, D-20: formation papers, notices, plans and history, through
`books.file_document` with their categories) and the books cut over on
2026-10-20. The Drive manifest and comparison tools once planned for P6
were struck (`plan/served.md` 8.4): the Drive folder is frozen history.
P6 (on its branch) adds the categories `notices`, `correspondence`,
`plans`, `history` and text extraction for every filed document.
+23 -9
View File
@@ -97,11 +97,14 @@ requirement conflict, the requirement wins.
receipts and documents are withdrawn with a reason. Unlinking may never
leave an entry the policy (R-13) requires a receipt for with none. Every
step is a journal event; no blob is deleted.
- **R-13 — Receipt enforcement.** The MCP layer (not the engine — the engine
stays policy-free) enforces a configurable receipt policy: postings at or
above a threshold (`require_receipts_above`, default `"25.00"` in base
currency) must have at least one attached receipt, with per-account
overrides. `post_entry` with `confirmed: true` refuses with a typed
- **R-13 — Receipt enforcement.** The server (not the engine — the engine
stays policy-free) enforces the books' evidence policy: postings at or
above a threshold (the journaled setting `policy.evidence.threshold`,
with required and exempt accounts; P1, rules.md B-29) must have at least
one attached receipt. Evaluated by `ledger-config`'s `ReceiptPolicy`
today; P4 moves the evaluation into `ledger_core::evidence` so the
store, the server and the viewer call one function (plan I-5, D-47:
reversals, closes, schedule and depreciation runs are exempt by origin). `post_entry` with `confirmed: true` refuses with a typed
`receipt_required` error otherwise. The draft preview always includes the
receipt checklist (`attached: [...]`, `required_but_missing: bool`), so the
human sees it before confirming. Full spec: `docs/mcp-interface.md`.
@@ -162,7 +165,14 @@ requirement conflict, the requirement wins.
overridable threshold. Schema v7.
- **R-? — A/R and A/P workflows.** Was R-FUTURE-5.
`ledger-core::arap`: customers, vendors, invoices, bills, payments,
AR/AP aging. MCP tools for the full workflow.
AR/AP aging. MCP tools for the full workflow. Since P4b S1 (D-45,
rules.md B-38): a document's figures are the signed sum of its tagged
ledger lines dated on or before the day asked about, so reversals,
voids and write-offs are right by construction; a hand line on a
control account is refused; `books.control_check` ties the subledger to
the control account. S4 to S7 add terms, numbers, line accounts, the
issued PDF, sends, settlements with discounts and the processor's fee,
and bad debts, behind the `documents_v2` journal feature.
- **R-? — Bank reconciliation.** Cleared flags on posted lines,
`reconciliation_report` with uncleared-line detail.
- **R-? — Payroll (accounting only).** `ledger-core::payroll`:
@@ -173,9 +183,13 @@ requirement conflict, the requirement wins.
`JournalLine.class_id`, `add_class`, `set_line_class` (drafts only),
`profit_and_loss_filtered`, `profit_and_loss_by_class`. Shared costs are
split explicitly across lines at entry time.
- **R-? — CPA handoff package.** `books.export_cpa_package`: zip with
trial-balance XLSX, general-ledger XLSX (every posted line), P&L and
balance-sheet PDFs (printpdf, MIT).
- **R-? — CPA handoff package.** `books.export_cpa_package` (and the
viewer's Export menu, D-29): a zip, built by `ledger-package` for both,
as of a day (B-33), with the trial balance and general ledger as XLSX,
the statements as Typst PDFs, the journal as IIF (B-34), every receipt
behind the period's entries with an index, the company's documents, the
1099 worksheet, the members' equity and K-1 worksheets (book and tax
basis, B-36), and a README; handed over as a download (D-46).
## Non-goals (all phases of the engine)
+2 -2
View File
@@ -23,7 +23,7 @@ promise.
| Model-based stateful | the Lean state machine, transcribed (3) | `tests/model.rs` | `just check` | ~3s | every change |
| Differential: Decimal vs i64 | the kernel at two types (3) | `kernel_bridge.rs` | `just check` | <1s | every change |
| Differential: GnuCash | another implementation, adjudicated (3) | `tests/oracle_gnucash.rs`, `oracle/gnucash/` | `just oracle` | ~2 min | weekly |
| Formal proofs | Kani (bounded) and Lean (unbounded) | `src/proofs.rs`, `verify/lean/` | `just prove` (48 harnesses and Lean), `just prove-slow` (the 8 in the justfile's `kani_slow`, each under its own 30-minute cap) | prove ~5 min and prove-slow ~8 min at four jobs on a quiet laptop (each ~25 min under heavy load; docs/verification.md, "Running it") | weekly (CI runs both) |
| Formal proofs | Kani (bounded) and Lean (unbounded) | `src/proofs.rs`, `verify/lean/` | `just prove` (51 harnesses and Lean), `just prove-slow` (the 9 in the justfile's `kani_slow`, each under its own 30-minute cap); 60 harnesses in all with the checker canary (2026-10-28) | prove ~5 min and prove-slow ~8 min at four jobs on a quiet laptop (each ~25 min under heavy load; docs/verification.md, "Running it") | weekly (CI runs both) |
| Fuzzing | crash, hang, broken books (4); for `fuzz_store_replay` (validly chained journals with fuzz-chosen events): books that open must verify, and the viewer must accept exactly what the writer does | `fuzz/fuzz_targets/`, corpora in `fuzz/corpus/` | `just fuzz <target> <secs>` | 10 min each | weekly |
| Miri | undefined behavior in our use of dependencies (4) | the core's unit, bridge, invariant tests (the exhaustive calendar walk aside) | `just miri` | ~4 min | on demand |
| Golden | `tests/golden/fixture_company.json` (5) | `invariants.rs` | `just check` | <1s | every change |
@@ -37,7 +37,7 @@ promise.
| Mutation (GUI) | can the tests fail? | `ledger-gui` view model and formatting (2026-10-14: 140 caught of 176 viable on the full run, then 92 of 99 on a targeted rerun of the money paths after new tests; of its 7 survivors, one then killed by a test (burn over exactly one month, confirmed by a rerun of `compute_kpis`'s 48 mutants), two dead arms removed (`parties`' bill arms: the ledger tags bill entries with their vendor, which wins), four equivalent: an entry's debits vs its credits (they balance), the three-month burn boundary (both paths give 3), burn over zero covered months (only when the first entry is after the window, which then holds no loss), and `compact`'s sign test at zero (zero prints "$0" unsigned either way)) | retired 2026-10-18 (owner: it crushed the machine; for the viewer, test its two musts directly: it never writes the books, `tests/read_only.rs`, and every figure it shows is the engine's, `tests/view_model.rs`) | | never |
CI: `.github/workflows/check.yml` runs `just check` on every push;
`scheduled.yml` runs proofs, the oracle, fuzzing, and mutation weekly. Mutation is split into shards, one job each (`just mutants-mcp 3/16` runs the fourth of sixteen), because GitHub stops a job at six hours and a whole crate takes longer on its runners (2026-10-19, the first scheduled run: the core and MCP runs were stopped at the limit). Test timeouts are three times each run's own baseline, never under the recipe's floor, so a slower runner doesn't report false timeouts. The viewer has no mutation job.
`scheduled.yml` runs proofs, the oracle, fuzzing, and mutation weekly. Mutation is split into shards, one job each (`just mutants-mcp 3/16` runs the fourth of sixteen), because GitHub stops a job at six hours and a whole crate takes longer on its runners (2026-10-19, the first scheduled run: the core and MCP runs were stopped at the limit). Test timeouts are three times each run's own baseline, never under the recipe's floor, so a slower runner doesn't report false timeouts. The viewer has no mutation job. Development mutation runs are paused until the P12 max-testing pass (D-33, 2026-10-20): each unit records its targets in a **For P12** paragraph instead; the weekly shards keep running in CI.
Seeds and failure databases: proptest's `*.proptest-regressions` files
are checked in and replay on every run. The GnuCash oracle's books come
+42 -2
View File
@@ -479,6 +479,44 @@ one kernel function, `kernel::unrecovered_cost`:
`unrecovered_cost_only_for_on_spec_and_never_negative`. No Lean model:
the function is one subtraction and a `max`.
### Documents and their control accounts (P4b S1, D-45)
**Law 34. A control account is its documents.** For a receivables or
payables account A and any day D, the account's balance on D equals the
sum over documents of `outstanding(d, D)` (the signed sum of the lines
tagged with d and dated on or before D, whatever their entries' standing:
a reversal's mirror carries the same tag and cancels) plus the legacy
untagged lines that still stand. A document never owes less than nothing
or more than its total on any day a payment path or a reversal touches
it. Rule: `docs/spec/rules.md` B-38.
- Kernel: `kernel::running_bounds(total, deltas)` and
`kernel::bounds_kept(total, before, after)` decide, at every date in
date order, whether 0 ≤ outstanding ≤ total holds; `Ledger::
check_item_bounds` runs them on the documents a step touches. Kani:
`bounds_check_matches_definition` (the check equals the definition on a
symbolic sequence of deltas) and
`bounds_kept_is_the_definition_on_books_in_bounds` (on books already
within bounds, `bounds_kept` is exactly the definition over the new
deltas), both with covers reaching a refused and an accepted sequence.
Bridge: `crates/ledger-store/tests/bounds.rs` and the properties in
`crates/ledger-store/tests/arap_props.rs` (`subledger_equals_control`
after every operation, at every date; `status_is_a_function_of_journal
_and_date`; `reversal_twice_restores_state`).
- Lean, `verify/lean/Wanderbooks/Documents.lean`: `control_agrees` and
`control_agrees_through` (the identity, for every account and through
every day), `Step.document_unattached` (an untagged legacy line only
grows `unattached`, never a document), `Step.reverse_moves` and
`reverse_twice` (a reversal moves exactly the opposite of its tagged
lines from its date; reversing it restores them),
`Reachable.control_is_documents` (the identity on every reachable
book). Listed in `Audit.lean`; standard axioms only.
- Laws 35 to 37 are taken, in the order the paused branches merge, by
S5 (`Step.markSent`: a send changes no figure), S6
(`settle_is_exact`: a settlement's cash, discounts and fee are exact)
and S7 (`writeOff_within_bounds`); the branches wrote 34 and are
renumbered at merge (`plan/served.md` 8.0.2).
### Payment terms and document lines (P4b S4.1)
Payment terms (rules.md B-39) give a due date and a discount date by
@@ -660,8 +698,8 @@ Lean carrying any weights.
```sh
mise install # once: Kani, Lean, and the rest, pinned in mise.toml
just prove # 48 Kani harnesses and Lean
just prove-slow # the other 8: the justfile's kani_slow
just prove # 51 Kani harnesses and Lean
just prove-slow # the other 9: the justfile's kani_slow
just prove-all # both
```
@@ -766,4 +804,6 @@ each harness's whole run, its compile of about 50 s included):
| `unrecovered_cost_laws` | 32 | prove | 0 |
| `discount_max_is_bounded` | 33 | prove-slow | 163 |
| `line_amount_is_exact` | 33 | prove | 6 |
| `bounds_check_matches_definition` | 34 | prove | (not in the 2026-10-22 run; P4b S1, 2026-10-24) |
| `bounds_kept_is_the_definition_on_books_in_bounds` | 34 | prove | (as above) |
| `kani_symbolic_copy_canary` | (the checker: "Trusting the checker") | prove | 3 |
+8 -3
View File
@@ -3,8 +3,11 @@
#
# curl -fsSL https://wanderbooks.ai/install.sh | sh -s -- acme
#
# Linux and macOS. On Windows, run it inside WSL2 (Ubuntu): the viewer opens
# as a normal window on Windows 11.
# Linux, and macOS with one gap: agents' tokens live in the OS keyring and
# only the Linux store exists until the macOS app (plan P11a), so on macOS
# this installs, sets up and starts the books but cannot connect an agent
# yet (it says so instead of failing). On Windows, run it inside WSL2
# (Ubuntu): the viewer opens as a normal window on Windows 11.
#
# Installs Rust if needed, then the one `wanderbooks` program (into
# ~/.cargo/bin), then makes the books' private folder (`wanderbooks setup`).
@@ -76,7 +79,9 @@ if [ $# -gt 0 ]; then
if ! "$wb" books list | cut -d' ' -f1 | grep -qx "$1"; then
"$wb" books create "$1"
fi
if command -v claude >/dev/null 2>&1; then
if [ "$os" = macos ]; then
say "Done. Your books \"$1\" exist and 'wanderbooks gui $1' shows them. Connecting Claude Code waits for the macOS keyring store (the app, plan P11a); until then agents connect from Linux."
elif command -v claude >/dev/null 2>&1; then
"$wb" connect claude --book "$1"
say "Done. Start Claude Code and say hello: your books \"$1\" are ready."
else
+175
View File
@@ -0,0 +1,175 @@
# Drift report, 2026-10-28: the plan, the code, and the documents
Written by the planning session on 2026-10-28, after the implementing
team (an engineering-manager agent with worker agents in git worktrees,
2026-10-26 to 2026-10-27) was paused. Method: every plan and design
document in `plan/` and `docs/` was read whole and compared with `main`
(`44ee4083`), the five paused branches (`S4.4`, `S5`, `S6`, `S7`, `P6`),
their worktrees, dry-run merges (`git merge-tree`, touching no branch),
and the code. Only divergences are listed; what matches is not.
## Where we are, in one paragraph
Of the plan's remaining units, nine landed on `main` in two days (U0a,
U0b, U0c, P7, P9a, P13 steps 1-3, P4b S4.1, S4.2, S4.3) and five more are
built to their "Done when" lists on unmerged branches (S4.4, S5, S6, S7;
P6 is feature-complete with its gate interrupted). Not started: S4.5, P4,
P5, P8, P10, P11a, P11b, P12, P13 steps 4-6. The owner's destination,
stated 2026-10-28, is one installed app for Mac, Windows and Linux (P11a,
then P11b), then the hosted service of section 11; today the executable
is Linux-first (the keyring store exists for Linux only, so on macOS an
agent cannot connect), nothing of P11a exists, and no macOS or Windows
build runs in CI.
## plan/served.md
- **8.0.1 and the unit Status lines are stale.** The S4 row says "S4.4-S4.5 open"; S4.4 is built on branch `S4.4` (`002fb9f8`, 2 commits, 29 files) with its As-built block written. S5 (`ad649be3`, 10 commits, 44 files), S6 (`6c4480cd`, 4 commits, 45 files) and S7 (`4b4fecb9`, 12 commits, 49 files) say "not started" and are built, each with its As-built block, `just check` reported green by its worker on the branch rebased on `ed637f0e`. P6 says "not started" and is built to every step on branch `P6`, checkpointed as `ce366408` ("wip: pause checkpoint, P6 feature complete, gate interrupted (not for merge)"): its `just check` never finished.
- **The merge hazards of the pause are not recorded anywhere.** Dry-run merges onto `main` in plan order: S4.4 clean; then S5 conflicts in `crates/ledger-cli/tests/documents.rs` (add/add) and `crates/ledger-mcp/src/types.rs`; S6 in `documents.rs` (add/add) and `docs/mcp-interface.md`; S7 in `documents.rs` (add/add), `types.rs`, `crates/ledger-store/src/lib.rs`; P6 in `types.rs`, `store/src/lib.rs`, `store/src/schema.rs`, `store/tests/store.rs`, `docs/parity.md`, `docs/receipt-store.md`, `docs/spec/rules.md`, `docs/testing.md`. Each branch alone merges onto `main` cleanly except P6. Causes: 8.0.3 allocated one over-the-wire test file (`crates/ledger-cli/tests/documents.rs`) to four units, and each created it; the "append at the end" rule for `types.rs` collides whenever two units append; P6 branched before S4.3 and took schema 16, which S4.3 holds on `main` (S5 took 17), so P6 must retake 18 at its rebase. S5 and S6 both numbered their new law 34 in `docs/verification.md` (S5 `Step.markSent`, S6 `settle_is_exact`); S1's documents law, which was never written up, is 34 on `main` as of this report, so S5 becomes 35, S6 36 and S7's write-off 37 at merge.
- **8.0.3's allocated names drifted, with the EM's approval, and the table was not updated:** two new MCP groups, `tools/sent.rs` (S5) and `tools/settlements.rs` (S6, which also moved `books.receive_payment`, `books.pay_bill`, `books.ar_aging`, `books.ap_aging` out of `documents.rs`); `books.mark_sent`'s recipients parameter is `recipients`, not `to` (the `no_tool_takes_a_path` lint refuses `to`); P6 built `books.set_entry_settles`, named in its Build step but absent from the new-tools row (P6 flagged it).
- **S6 departed from its Build in ways the owner should see:** `confirmed` (preview then confirm) was not added to `books.receive_payment` and `books.pay_bill` (deferred to P4's one sweep); the processor's vendor on a fee is named in the entry's description, not tagged (tags are entry-wide); no schema change (18 not taken); the three bookspec examples were not written (two wait for journaled terms); the over-the-wire discount tests wait for S4.3's journaled terms, which have since landed.
- **P6 departed in a way that changes the crate graph:** `ledger-store` now depends on `ledger-import` (Typst, the fonts, hayro enter the store's dependency closure) so the writer can extract at attach time. `docs/architecture.md`'s dependency rules neither allow nor forbid it; it needs a decision at P6's review (the alternative is extraction in the server before the store call, with the backfill command doing the same).
- **S4.4 changes the live contract A-1 planned:** existing callers of `books.create_invoice` and `books.create_bill` now need `confirmed: true`; the connect text and handbook on `main` still say "Invoice, bill, payment and payroll tools post at once, unchecked", so that sentence is stale the moment S4.4 merges (S4.5 owns the handbook; the connect text is `handbook.rs`).
- **Q-5 is due and unasked.** Its trigger is "when S4 lands"; S4.1-S4.3 are on `main` and S4.4 is built. A-14 is still reserved for the answer.
- **D-47 to D-54 are the review's recommendations, never explicitly confirmed by the owner** ("the owner may revisit"); S5, S6, S7 and P6 were built on them (D-47, D-49, D-52, D-53). Confirming them is now a one-line question (Q-8 below).
- **P11a's Build omits the groundwork the design assigns to P11 elsewhere:** the macOS and Windows keyring stores (3.3 as built; D-19; `crates/ledger-host/src/tokens.rs` returns "kept in the keyring on Linux only, until the macOS and Windows apps (P11)" on every other OS, so `wanderbooks connect` and the bridge fail there), the Windows data root under `%LOCALAPPDATA%` with an owner-only DACL (3.4), named pipes with a SID check (3.9), and a CI build on macOS and Windows runners (none exists: all three workflows run `ubuntu-24.04`). None is a step in 8.2 P11a.
- **8.0.2's priority statement is stale against the owner's destination.** It names P10 as "the owner's goal" and leaves P11a as "any time"; the owner's statement of 2026-10-28 makes the installed app the destination, with P11a to start now beside the P4b finish (recorded as D-56).
- **Section 2 carries superseded sentences without the strike-through rule of section 0:** I-1 "Landlock and seccomp confine the server itself where available", I-2 "Landlock harness `no_tool_touches_outside_tenant`", I-8 "`gui_works_under_read_only_landlock`" (all → D-32).
- **`server.toml` (3.2, 3.4) was never built**; the deployment flags are `wanderbooks serve --http` and `--isolation` (P9a). The references read as if it exists.
- **4.9's "The tool count is 118 (2026-10-26)"** is 122 on `main` (U0a's As-built says so) and becomes 130 once the five branches merge (S5 +1, S6 +1, S7 +1, P6 +4, S4.4 +0).
- **8.0.6 item 2 fixtures**: S4.3 wrote `p4_s43_documents`, S5 `p4_s5_before`, S7 `p4_s7_before`, P6 `p6_evidence`; S4.4 and S6 wrote none of their own (S6 reuses `p4-arap-before`, which predates S1). Acceptable under the item's intent (no figure moves), recorded here so the EM does not look for them.
## plan/STATUS.md
- The title and the "Now" section are dated 2026-10-26 and say "P4b S4 next"; since then U0a, U0b, P9a, S4.1-S4.3 landed and S4.4, S5, S6, S7, P6 were built on branches. The pause paragraph (2026-10-27) is the last entry but the head of the file was not revised, so a reader is told the wrong next step.
## plan/HANDOFF.md
- "What is true today (2026-10-26)" says nothing after S3 is built. Nine units landed and five are on paused branches.
- No procedure for resuming paused worktrees: the merge order of the five branches, the known conflicts (above), the schema renumbering P6 needs, and that every branch's `just check` must be re-run after the rebase (the pause killed the gates).
- It does not say that P11a is to be staffed now (D-56).
## plan/roadmap.md
- Phase 2 says "27 tools" (122). Phase 3 (oracle harness) reads as not started; `just oracle` runs 200 random books through GnuCash 5.10 with 15,800 exact comparisons (docs/oracle.md Layer 5); the machine-readable parity catalog and CI floor are the part still open.
- Phase 5 lists A/R and A/P, bank reconciliation and period close as future; all three exist (reconciliation and close since 2026-10-11, A/R and A/P first-class since P4b S1). Multi-currency is partial (foreign lines; no translation), as it says.
- "Explicitly not on the roadmap: payroll" while `ledger-core::payroll` and the payroll tools exist (accounting only, no tax tables). The sentence means tax tables and filing; it does not say so.
- Nothing names the destination: the installed app (P11a, P11b) and the hosted service (served.md section 11).
## plan/gui.md
- "Status (2026-10-12)" predates: the Books menu (back up, restore, new books, connect, close; P2 slice 8), 80 color schemes (D-19's family menu), Invoices & Bills pages and document pages with timelines (P4b S2, S3), Projects pages, old-books compatibility tests, Needs attention computed by `ledger-package` and only routed by the viewer (U0b), the data root as the only source (`wanderbooks gui <book>`; `--data-dir` and `--books-toml` removed, D-44), the W-9 and TIN clipboard copy (D-29), the format-upgrade dialog (D-39).
- Principle 4 says the GUI "builds its own in-memory view" and offers prompts for the agent; the prompts now come from the shared attention engine.
- The "Next" list (cash forecast, reconciliation view, receipt zoom, keyboard navigation, virtualized lists, web build) was never revisited; the reconciliation page exists; the web build is the hosted service's viewer (section 11).
## README.md
- "118 MCP tools" twice (122 on `main`); "190+ workspace tests" (about 2,700 test functions across the two workspaces).
- The quickstart and the installer claim Linux and macOS. On macOS the executable builds and the viewer runs, but `wanderbooks connect` and the agent bridge fail: tokens live in the OS keyring and only the Linux Secret Service store is built (`tokens.rs`, `NOT_YET`). Windows is WSL2 only, as it says.
- "Status" says the Google Sheet stays the system of record until a clean month and cutover approval; the cutover happened 2026-10-20 (P2 slice 9) and the Sheet is frozen as of 2026-10-11.
- "Mutation testing via cargo-mutants" is paused for development until P12 (D-33; CI still runs its weekly shards).
- The layout omits `ledger-vault`, `bookspec/`, `verify/`, `deploy/`, `fuzz/`, `oracle/`, `site/`.
## AGENTS.md
- "`ledger-core` depends only on `rust_decimal`, `thiserror`, `chrono`, `serde`, `serde_json`": it also depends on `jiff` (the time-zone database for `company.timezone`'s "today", P1). The rule needs the sixth name or a justification recorded.
- The docs index omits `docs/testing.md`, `docs/parties-and-attachments.md`, `plan/served.md` (the plan every remaining unit is built from), `plan/HANDOFF.md`, `bookspec/`, `deploy/`.
## docs/architecture.md
- "Current crate layout" shows `ledger-core` alone with six files; the workspace has ten crates (plus the bookspec workspace of two), and `ledger-core` has about 25 modules. "Future crates (do not create until the roadmap says so)" lists `ledger-store`, `ledger-import`, `ledger-export`, `ledger-oracle` as future: the first two exist, `ledger-export` was folded into `ledger-import`, and the GnuCash cross-check is `tests/oracle_gnucash.rs` with `oracle/gnucash/`, not a crate. `ledger-config`, `ledger-mcp`, `ledger-cli`, `ledger-host`, `ledger-vault`, `ledger-gui`, `ledger-package` are described in later sections or not at all; there is no dependency graph.
- "the projection has a table for each (schema v12)": 16 (17 on branch S5).
- The `ledger-mcp` groups list will need `sent` and `settlements` when S5 and S6 merge (their branches add them).
- The P6 branch's `ledger-store` → `ledger-import` dependency is not covered by the dependency rules (see served.md above).
## docs/parity.md
- "**Floor: 10 done** (2026-10-10)" while the table holds 21 `done` rows.
- No P4b entry at all. S1 (documents read their figures from standing lines, the control guard, `books.void_document`, `books.control_check`), S2 (`books.documents`, `books.document`, the viewer pages), S3 (the invoice PDF) and S4.1-S4.3 (terms, numbers, line accounts, the issued PDF filed) landed without touching the catalog, against AGENTS.md's "every feature change updates `docs/parity.md` in the same commit". The A/R and A/P rows' notes still read "R-FUTURE-5".
- "Automated cross-implementation diff harness (GnuCash first) | todo" while `just oracle` runs it weekly (docs/oracle.md Layer 5); what remains is the fixture-book snapshot diff and the machine-readable catalog.
- "Workflow/UI parity ... gets its own catalog when the egui phase starts": the viewer exists; no such catalog was started (not a defect: the owner made MCP the primary interface, 2026-10-10).
## docs/capability-parity.md
- The cutover rule reads as pending. The cutover happened 2026-10-20 (P2 slice 9); the Sheet is frozen as of 2026-10-11 and the final `verify-sheet` run is a filed workpaper (served.md 8.4). The document should say so and keep the rule for the record.
## docs/parallel-run.md
- Entirely pre-cutover ("70 workspace tests"; "delete the wanderbooks data dir" as rollback). Historical since 2026-10-20; it carries no banner saying so.
## docs/requirements.md
- R-13 names `require_receipts_above` with a default of `"25.00"` enforced by the MCP layer; the policy is the journaled setting `policy.evidence.*` (P1, B-29), evaluated by `ledger-config`'s `ReceiptPolicy` today and moving into `ledger_core::evidence` in P4 (I-5 as amended by D-47).
- "CPA handoff package: ... P&L and balance-sheet PDFs (printpdf, MIT)": Typst since 2026-10-11, and the package holds the cash flow, GL, journal IIF, receipts, documents, the 1099 worksheet and the K-1 worksheets.
- "A/R and A/P workflows ... MCP tools for the full workflow" says nothing of D-45 (figures derived from tagged standing lines; hand lines on the control accounts refused) or of what `documents_v2` adds behind the owner's upgrade.
## docs/oracle.md
- Layer 3 (mutation testing) is "live now"; development mutation runs are paused until P12 (D-33), CI's weekly shards aside.
- Layer 5 both says the GnuCash differential is live and that "a `ledger-oracle` crate will run fixture books ... `cargo xtask oracle`"; there is no crate and none is planned (the harness is `tests/oracle_gnucash.rs`).
- "What the oracle does NOT cover: workflows ... a UI concern for the egui phase, where storytold's screenshot-in-the-loop comes back": the viewer exists with screenshot tests (`crates/ledger-gui/tests/*.rs`, `shot(..)`).
## docs/receipt-store.md
- "Migration from Google Drive" is written as future work; the company records were filed at the P1 cutover (D-20) and the Drive manifest and comparison tools were struck (served.md 8.4). The schema notes (v16, a file per schema) are current.
## docs/parties-and-attachments.md
- "Status: design; built after asset tax basis": built (parties, roles, the TIN vault, attachments to any subject, 2026-10-15 to 2026-10-17); D-55's contact block is built on branch S4.4.
## docs/mcp-interface.md
- The per-tool sections are held to the code by `every_tool_is_documented_and_every_documented_tool_exists`; no drift there. The framing is stale: "Crates in this phase" lists two crates and calls `ledger-store` "SQLite persistence" (the journal is the source of truth); "Muse" among the clients; "Out of scope for this phase". P5 owns the overview rewrite (its step 6).
## docs/testing.md
- The Layers table says `just prove` runs 48 harnesses and `prove-slow` 8; the code has 60 (`#[kani::proof]`), 51 in `prove` and 9 in the justfile's `kani_slow`.
- The mutation rows say "weekly" with no mention of D-33 (development runs paused until P12; CI's `scheduled.yml` still runs the shards).
- Units U0a and S4.1-S4.3 have no section; U0a added no tests (none owed) and S4's For-P12 paragraph is S4.5's by the plan, so this is deferred, not missing.
## docs/verification.md
- The harness table lacks P4b S1's two Kani harnesses, `bounds_check_matches_definition` and `bounds_kept_is_the_definition_on_books_in_bounds` (`kernel::running_bounds`, `bounds_kept`), and there is no section for S1's law (Lean `control_agrees`, `control_agrees_through`, `Reachable.control_is_documents` in `Documents.lean`), against AGENTS.md's "every harness and theorem listed". S7's branch amends the "out of scope" list; S5's branch adds rule 34 (`Step.markSent`).
- "Running it": 48 and 8 harnesses (51 and 9).
## docs/spec/README.md, docs/spec/rules.md
- No drift detected beyond the open sources already listed in 8.4 (B-38 to B-45 stay CONVENTION until vendored). The branches add B-41 (S7), B-42 (S6), B-44 (P6) and their bookspec ids.
## site/index.html, install.sh
- Both claim Linux and macOS. On macOS the install succeeds and the viewer runs, but `wanderbooks connect claude` (the installer's last step) fails on the keyring (see README above), so the one-line promise does not hold there until P11a's keyring stores. "Native Windows is on the way" is right. The site is deployed by hand (`just deploy`); the built copy under `site/dist` lags any source edit until then.
## deploy/README.md, deploy/wanderbooks-server.service
- No drift detected against P9a as built. Done-when 1 (the GitHub Actions job's first run) and 2 (the recipe walked on a clean VM by a non-author in under 30 minutes) are still the owner's to verify.
## bookspec/README.md
- No drift detected. Branch S7 extends the example schema (`write_off`, a refused `lines` entry); the README on that branch says so.
## plan/review-2026-10-26/
- Historical. No drift detected.
## Housekeeping found on the way (not plan drift)
- Build caches: about 1 TB under the six `target/` directories (`wanderbooks` 196 GB; `wb-S6` 220 GB, `wb-S5` 194 GB, `wb-P6` 167 GB, `wb-S4.4` 117 GB, `wb-S7` 109 GB) with 1.7 TB free. Once the branches merge, `cargo clean` in each worktree and `git worktree remove` recover it.
- 27 jj workspaces are registered (`p3-*`, `p4-*`) whose directories under `~/.cache/wanderbooks/` no longer exist: `jj workspace forget` each.
- Branch `rescue/p4-invproj-20261026` ("wip: rescue uncommitted p4-invproj work before cache cleanup, never merged", 51 files) sits beside `main`, which holds that work's landed form (`528c0706`, including its bookspec example `projects-invoice-and-bill-lines-count-by-project`); nothing on it is missing from `main`. Delete it after a last look.
## The deviations, judged
Every departure recorded in an As-built block was read against the unit's text and AGENTS.md:
- **Reasonable, keep:** S4.1's interim guard (removed by S4.3 as promised); S4.2 declaring `documents_v2` early (the settings writes needed the gate); S4.3 skipping the parties columns (no parties table exists; replay and `differs_from` carry the facts) and the `_with` carriers; S4.4 requiring the new bill fields only under `documents_v2` (8.0.4's "everything else works at once"); S5's Lean step for `mark_sent` (I-13 wins over the unit's "no Lean change") and the `recipients` rename (the lint is older than the unit); S6's `tools/settlements.rs` (the EM approved it to keep `documents.rs` single-owner) and the fee's processor in the description; S7's `least_owed_from` bound (B-38 invariant 2 at every later day, stricter than the unit) and the one-receipt-once rule; U0a's 122 (the unit's 118 was stale); U0b's extra `PackageBooks` reads and the integrity fix (a real parity gap found); P9a's loopback-only door (the review caught a plaintext static-bearer door bound to every address); P7 keeping the filing scan narrow (B-26's design); P13's `Engine::change` and the CHOICE vocabulary.
- **Reasonable but owed back:** S4.3's missing journal transaction (an I/O failure between the invoice's lines and its attachment's is not rolled back: a property of every multi-line command, to be fixed once for all in P12 or a small unit of its own); S6 deferring `confirmed` to P4 (right, since P4's sweep touches every confirm tool, but P4 must now add it rather than only `preview`); S6's unwritten bookspec examples (owed to P13 step 4 or S6's follow-up now that terms are journaled); the two S1 harnesses missing from `docs/verification.md`.
- **Needs a decision:** P6's `ledger-store` → `ledger-import` dependency (architecture), and P6's whole branch is a checkpoint whose gate never ran: it is not yet a reviewed unit.
- **Not reasonable, fix:** none found. No golden moved on `main`; no kernel arithmetic outside `kernel.rs` was introduced by the landed units; no unit touched the owner's books.
## Where to go next (the order)
1. **Resume and land the paused branches**, in this order, each rebased on `main` and `just check` (and `just prove` where it says) re-run after the rebase: S4.4 → S5 (resolve `documents.rs` by concatenation, `types.rs` by keeping both appends; schema 17 stands) → S6 (`documents.rs`, `docs/mcp-interface.md`) → S7 (`documents.rs`, `types.rs`, `store/lib.rs`; `just prove` for `writeOff_within_bounds`) → P6 (eight files; retake schema 18; run its gate to the end; review the store → import dependency). Then S4.5, the only unstarted P4b slice.
2. **Ask the owner Q-5 and Q-8** (served.md 10.3) when S4.4 lands; the `documents_v2` upgrade of the live books follows the answer (after S7 and P4 under D-52).
3. **Start P11a now** (D-56), beginning with its new step 0 (the macOS and Windows keyring stores, the Windows data root and pipes, a CI matrix on macOS and Windows runners), then the cargo-packager trial. P11a is independent of the P4b and P4 chain and is the owner's destination.
4. **Then the chain as planned:** P4 (now also adding `confirmed` to the settlement tools) → P5 → P8 → P10; P13 steps 4-6 beside; P11b after P11a; P12 last.
5. **Update the documents in this report's list** (done in the same change as this report where the fix is a fact, not a decision).
+13 -7
View File
@@ -1,6 +1,6 @@
# Hand-off: the remaining wanderbooks work, for a team running in parallel
This file is the prompt to give the implementing team's harness (an engineering-manager agent that coordinates worker agents, each in its own git worktree). Paste the block under "The prompt" as the manager's instructions. Everything it refers to is in this repository. Written 2026-10-26.
This file is the prompt to give the implementing team's harness (an engineering-manager agent that coordinates worker agents, each in its own git worktree). Paste the block under "The prompt" as the manager's instructions. Everything it refers to is in this repository. Written 2026-10-26; revised 2026-10-28 after the first wave was paused (see "Resuming the paused worktrees").
## The prompt
@@ -10,17 +10,23 @@ You are the engineering manager (EM) of a team implementing the remaining work o
1. `AGENTS.md` (the repo's operating manual: the six non-negotiables, the verification protocol, the formal-methods bar).
2. `plan/served.md` section 0 ("How to read this document") and section 8.0 ("How the work is organized"): the status and dependency table (8.0.1), the dependency graph and merge order (8.0.2), the shared files, their owners and the allocated names (8.0.3), every unit's bar and the eight-field template (8.0.4), the recipes R-A to R-G (8.0.5), the journal-safety checklist (8.0.6), how to work in a worktree (8.0.7).
3. `plan/served.md` section 10 (the decisions, D-1 to D-54; the open questions Q-4 to Q-7; the decisions-by-unit index 10.4) and section 2 (the invariants I-1 to I-13).
3. `plan/served.md` section 10 (the decisions, D-1 to D-56; the open questions Q-4 to Q-8; the decisions-by-unit index 10.4) and section 2 (the invariants I-1 to I-13).
4. `plan/STATUS.md` (where the live books stand) and `docs/architecture.md`.
5. Only when a unit is assigned: that unit's section in `plan/served.md` 8.2, and the parts of 8.3 (the P4b reference design) it points into.
### What is true today (2026-10-26)
### What is true today (2026-10-28)
- `main` is at the commit that landed P4b S3 or later. P0, P1, P2, P3, Projects and P4b S1, S2, S3 are built and live on the owner's books. Nothing after that is built.
- The plan's section 8 was rewritten on 2026-10-26 for this hand-off. Sections 1 to 7 are the older design and carry strike-throughs (`~~text~~ → D-n`) and "As built" notes where the build or a decision departed; where section 8 and an earlier section disagree, section 8 is right.
- `main` is `44ee4083`. Landed since the hand-off: U0a, U0b, U0c, P7, P9a, P13 steps 1-3, P4b S4.1, S4.2, S4.3 (all 2026-10-26 to 2026-10-27). Live on the owner's books: P0 to P3, Projects, P4b S1 (`document_standing`); everything behind `documents_v2` waits for the owner's upgrade (Q-5).
- Built but unmerged, on branches paused 2026-10-27: S4.4 (`002fb9f8`), S5 (`ad649be3`), S6 (`6c4480cd`), S7 (`4b4fecb9`), P6 (`ce366408`, a checkpoint whose gate never finished). Their worktrees are `../wb-<unit>`. "Resuming the paused worktrees" below is the first thing to do.
- Not started: S4.5, P4, P5, P8, P10, P11a (starts now: D-56), P11b, P12, P13 steps 4-6.
- The plan's section 8 was rewritten on 2026-10-26 for this hand-off and revised on 2026-10-28 (section 0, "What changed on 2026-10-28"; `plan/2026-10-28_DRIFT_REPORT.md`). Sections 1 to 7 are the older design and carry strike-throughs (`~~text~~ → D-n`) and "As built" notes where the build or a decision departed; where section 8 and an earlier section disagree, section 8 is right.
- Mutation testing is paused until unit P12 (decision D-33). Workers never run `cargo mutants`; each unit writes a "For P12" paragraph in `docs/testing.md` instead (recipe R-G).
- The owner's live books are never touched by anyone on this team. The only books a worker uses are test fixtures and throwaway books made by `wanderbooks setup` in a scratch root. A unit's new writes are refused on the owner's books until the owner's format upgrade; merging never waits for that.
### Resuming the paused worktrees (2026-10-27 pause)
The five branches were stopped mid-gate; nothing was merged, rebased or discarded. Resume in this order, one at a time (the single-owner rule): S4.4, S5, S6, S7, P6, then S4.5. For each: rebase on `main`; resolve the known conflicts (served.md 8.0.2, "Resuming the paused wave": `crates/ledger-cli/tests/documents.rs` is an add/add on every P4b branch after the first, concatenate; `types.rs` keeps both appends; P6 retakes schema 18 and resolves eight files); renumber the laws in `docs/verification.md` at merge (S1 is 34 on `main`; S5 35, S6 36, S7 37); re-run `just check`, and `just prove` for S7 and any branch that touched `verify/lean/` or a `Ledger` command, after the rebase, since the pause killed the running gates; review against the unit's text and its As-built block (each branch carries its own); merge; move the 8.0.1 row to landed and append to `plan/STATUS.md`. P6's checkpoint is not a reviewed unit: run its gate to the end and review its `ledger-store` → `ledger-import` dependency before merging (ask the owner if you would keep it). Ask Q-5 and Q-8 when S4.4 lands.
### How to run things
- `mise install` once (Rust 1.99 with clippy and rustfmt, just, Kani, Lean, sccache, all pinned in `mise.toml`). Then `just` lists the recipes.
@@ -30,7 +36,7 @@ You are the engineering manager (EM) of a team implementing the remaining work o
### Assigning work
Use the table in 8.0.1 and the graph in 8.0.2. The order that is forced:
Use the table in 8.0.1 and the graph in 8.0.2. The first wave below ran 2026-10-26 to 2026-10-27; start from "Resuming the paused worktrees", and staff P11a (step 0 first) as soon as an engineer is free (D-56). The order that is forced:
1. First, in parallel: **U0a** (split `server.rs` by tool group; single owner), **U0b** (the attention engine over `PackageBooks`; single owner), **U0c** (three missing `docs/testing.md` sections), **P4b S4.1** (core: terms, numbers, line accounts) and **P4b S4.2** (settings and party fields), **P13** steps 1 to 3 (the bookspec checker crate), **P7** (the TIN scanner's separators), **P9a** (the self-host recipe).
2. When U0a has merged: no other branch may add MCP handlers before it; after it, every unit adds handlers only in its own `crates/ledger-mcp/src/tools/<group>.rs`.
@@ -77,4 +83,4 @@ Weekly, or when asked: the 8.0.1 table as it stands (which units landed, with co
- The review that produced this plan is in `plan/review-2026-10-26/`; `consolidated_review_report.md` lists every finding and what was done with it. Nothing in the code changed on 2026-10-26.
- The sizes in 8.0.1 are rough, for an entry-level engineer new to the codebase; the recipes exist to make them hold.
- Four owner questions are open (Q-4 to Q-7, section 10.3). None blocks the first wave of units.
- Five owner questions are open (Q-4 to Q-8, section 10.3); Q-5 and Q-8 are due when S4.4 lands. None blocks the merges.
+71 -2
View File
@@ -1,6 +1,75 @@
# STATUS — 2026-10-26: "Served" P0 to P3 and P4b S1-S3 live; the plan reworked for a team
# STATUS — 2026-10-28: nine units landed, five built on paused branches; P11a starts
## Now: the plan is a hand-off (plan/served.md §8.0); P4b S4 next
## Now (2026-10-28): land the paused wave, then S4.5; start P11a beside it
**Where things stand.** `main` is `44ee4083`. Since the hand-off of
2026-10-26, nine units landed in two days: U0c (`198aa2a1`), P7
(`3e65c83f`), P13 steps 1-3 (`579d0eed`), P4b S4.1 (`13282cf8`), S4.2
(`bf91c5a7`), U0a (`45396bdc`), U0b (`26d3a994`), P9a (`c8541ea9`) and
S4.3 (`d19fb464`); the owner made D-55 (the party contact block). Five
more units are built to their Done-when lists on branches the owner
paused on 2026-10-27 to free the machine, none merged: S4.4 (`002fb9f8`),
S5 (`ad649be3`), S6 (`6c4480cd`), S7 (`4b4fecb9`), and P6 checkpointed as
`ce366408` (feature complete, its gate interrupted, "not for merge" as
is). Not started: S4.5, P4, P5, P8, P10, P11a, P11b, P12, P13 steps 4-6.
The live books are unchanged since the P3 cutover and the
`document_standing` upgrade of 2026-10-24; `documents_v2` waits for Q-5.
**The 2026-10-28 review.** The planning session read the whole plan and
every design document against `main`, the five branches and dry-run
merges; the result is `plan/2026-10-28_DRIFT_REPORT.md`, and the plan
and docs were brought up to date in the same change (served.md section
0, "What changed on 2026-10-28"). The gate on `main` at `44ee4083`:
green (`exit 0`, 70 minutes on a loaded machine: fmt, clippy and
rustdoc for both workspaces, 167 test suites, 2,871 tests passed, 0
failed, 7 ignored, the server-only build with no window libraries).
The five branches' gates are being re-run in their worktrees, one at a
time, and each is recorded in 8.0.1 when it lands.
**What the review judged.** Every departure the workers recorded was
reasonable and is kept (the drift report lists them with the reason);
three are owed back (S4.3's missing journal transaction across a
multi-line command; S6's `confirmed`, deferred to P4's sweep; S6's
three bookspec examples); one needs a decision (P6 made `ledger-store`
depend on `ledger-import` so the writer can extract at attach time).
No golden moved, no kernel arithmetic left `kernel.rs`, no unit touched
the owner's books.
**The merge hazards the pause left** (dry-run merges, nothing touched):
every P4b branch created `crates/ledger-cli/tests/documents.rs` from
8.0.3's one allocated file (add/add on every merge after the first);
`types.rs` appends collide; P6 branched before S4.3 and took schema 16,
which S4.3 holds (S5 took 17), so P6 retakes 18; S5 and S6 both numbered
their law 34 in `docs/verification.md` (S1's documents law is now 34 on
`main`; S5 becomes 35, S6 36, S7's write-off 37). The order and the
resolutions are in served.md 8.0.2, "Resuming the paused wave".
**The destination (D-56).** The owner, 2026-10-28: the work is
"ultimately taking it to a single bundled server+GUI installation for
Mac/Windows/Linux and then beyond". The installed app (P11a, then P11b)
is the plan's destination and the hosted service (served.md section 11)
what follows. Today the executable is Linux-first: tokens live in the OS
keyring and only the Linux Secret Service store exists, so on macOS
`wanderbooks connect` and the agent bridge fail (`tokens.rs`,
`NOT_YET`), Windows is WSL2 only, and no macOS or Windows build runs in
CI. P11a gains step 0 for exactly that groundwork and starts now, beside
the P4b finish; the P10 chain (P4, P5, P8) keeps its order.
**Next, in order:** (1) resume the five branches in the 8.0.2 order,
each rebased and `just check`ed again (the pause killed every gate),
P6 last with its gate run to the end and its dependency reviewed; (2)
ask the owner Q-5 and Q-8 when S4.4 lands; (3) S4.5; (4) P11a step 0
and the packaging trial, staffed now; (5) P4 (adding `confirmed` to the
settlement tools too), P5, P8, P10; P13 steps 4-6 beside; P11b after
P11a; P12 last.
**Housekeeping found:** about 1 TB of `target/` directories across the
six checkouts (1.7 TB free); 27 registered jj workspaces whose folders
are gone (`jj workspace forget`); branch `rescue/p4-invproj-20261026`
holds nothing `main` lacks (its bookspec example landed) and can go
after a last look.
## 2026-10-26 to 2026-10-27: the hand-off and its first wave
**2026-10-26: the plan was reviewed and rewritten for a team of engineers
working in parallel worktrees.** A nine-stage Elephant-Goldfish review
+59 -14
View File
@@ -1,6 +1,6 @@
# ledger-gui — design
Phase 4 of the roadmap. A desktop app (egui/eframe; web later) for the
Phase 4 of the roadmap (`plan/roadmap.md`). A desktop app (egui/eframe) for the
people who own the books and the accountant who checks them. Same
audience as QuickBooks, none of its visual language.
@@ -86,7 +86,7 @@ document, or report; back/forward (Alt+←/→); light and dark themes.
new journal lines (or reloads if the file was rewritten).
- `ledger-config` (moved out of `ledger-mcp`): `wanderbooks.toml`.
- `ledger-gui`:
- `data` — a loader thread polls the journal and sends new snapshots.
- `data` — a loader thread follows the journal (notify-driven, polling as the fallback) and sends new snapshots.
- `model` — view models built from a snapshot (pure, unit-tested).
- `ui/*` — one module per screen; `widgets` (money, tiles, sparkline,
tables, charts); `theme`; `receipts` (PDF via `hayro`, images via
@@ -95,17 +95,62 @@ document, or report; back/forward (Alt+←/→); light and dark themes.
against a fixture book.
- Web build later: the model is plain data, so a server can ship it.
## Status (2026-10-12)
## Status (2026-10-28)
Built: every screen above, the palette, history, themes, live updates
(tested end to end: a store write reaches the view model in ~30 ms),
receipt rendering for PDFs and images, a deterministic demo company
(`ledger-gui --demo`; also the screenshot fixture), and a screenshot test
(`SHOT_DIR=… cargo test -p ledger-gui --test screens`, optionally
`SHOT_BOOKS`, `SHOT_ONLY`, `SHOT_DARK`).
Built 2026-10-12 (the first version): every screen above, the palette,
history, themes, live updates (a store write reaches the view model in
~30 ms), receipt rendering for PDFs and images, a deterministic demo
company (`wanderbooks gui --demo`; also the screenshot fixture), and a
screenshot test (`SHOT_DIR=… cargo test -p ledger-gui --test screens`,
optionally `SHOT_BOOKS`, `SHOT_ONLY`, `SHOT_DARK`).
Next, in rough order: a budget-free cash forecast with a confidence band;
reconciliation view (cleared vs. uncleared per bank account); receipt
zoom and multi-page navigation; keyboard navigation in lists;
virtualized lists for very large books; the web build (ship the view
model from a server).
Built since, by the "Served" plan (`plan/served.md`):
- **The data root is the only source** (D-44): `wanderbooks gui <book>`
opens a book of the data root, read-only, its settings from the
journal and its vault from its own `vault/` and `keys/`; `--data-dir`
and `--books-toml` are gone. The viewer holds the books open (a lease
of kind app) and still opens with the server stopped.
- **The Books menu** (P2 slice 8, D-19): Back up now, Restore…, New
books…, Connect Claude Code, Connect Codex, Close the books, each
handed to the server through the same functions the command line
uses; the Export menu (the CPA package, the 1099 worksheet, Save a
copy, Save the W-9), each a new file in Downloads. The viewer writes
nothing of the books (`tests/read_only.rs`, `tests/owner_menu.rs`).
- **The format-upgrade dialog** (D-39): asked at every open of waiting
books, a standing notice, the owner passphrase typed in the viewer.
- **Color schemes** (D-19's menu): the viewer's own family and twenty
editor families, 80 schemes, each at WCAG AA contrast, worn live on
hover (`tests/schemes.rs`, `docs/color-schemes.md`).
- **Needs attention is the engine's** (U0b, D-53): one function in
`ledger-package::attention` over `PackageBooks`, read by the viewer and
by `books.start`; the viewer only maps each item's target to a route,
and `the_viewer_and_books_start_see_the_same_attention` proves the two
lists equal. Principle 4's "ready-to-paste prompt" now comes from that
engine.
- **Pages added:** Invoices & Bills (Money in, Money out, a document's
page with its timeline, overview tiles; P4b S2) and Save invoice PDF
(S3); Projects and a project's snapshot (D-43); parties with roles,
W-9 and the TIN clipboard copy (D-29); fixed assets with the tax-basis
figures (P3); reconciliation; the journal page describing every event
in plain words.
- **Compatibility tests:** `tests/old_books.rs` (books an earlier version
wrote open to their figures), `tests/newer_journal.rs` (a newer journal
says "update wanderbooks", never half-read), `tests/view_model.rs`
(every figure shown is the engine's).
On the paused branches (2026-10-27): the invoice page shows sends (S5),
a discount-deadline column and the tie-out badge (S6), write-offs on the
timeline (S7), documents grouped by category and subject (P6). S4.5 adds
the number, terms, bill-to and the issued copy to Save.
Next, in the plan's order: S4.5's page changes; P4's draft states in
Needs attention; P11a (the installed app: the viewer is its face, with
"Check for updates" in the menu) and P11b (the agent dock along the
bottom of the window, Claude Code or Codex in it, started in the book's
books home; D-27). Not planned: a web build, which belongs to the hosted
service (`plan/served.md` section 11, a browser viewer); the remote
viewer replica (D-51: a backup clone opened read-only serves instead).
Still open from the first version's list: a cash forecast with a
confidence band, receipt zoom and multi-page navigation, keyboard
navigation in lists, virtualized lists for very large books.
+82 -88
View File
@@ -1,107 +1,101 @@
# Roadmap
## Phase 1 — Semantics core (done)
Where wanderbooks has been, where it is, and where it is going. The
detailed plan for the remaining work is `plan/served.md` (section 8.0:
status, order, hand-off); `plan/STATUS.md` says where things stand this
week. Revised 2026-10-28.
The engine: money, accounts, journal, ledger commands, trial balance, P&L,
balance sheet, cash flow, fixed assets with depreciation, golden files,
property tests, mutation testing, fuzzing, and the docs an agent needs to
work here. Parity floor: 12 done.
## Done
## Phase 2 — AI-first interface (done)
### Phase 1 — Semantics core (2026-10-10 to 2026-10-13)
The primary interface is MCP, not a cloned GUI (the owner's call, 2026-10-10).
The engine: exact money, five account types, balanced entries, the
immutable posted log with reversals, trial balance, P&L, balance sheet,
the cash flow statement, period close, fixed assets, schedules, tax
categories, 1099 tracking, parties, A/R and A/P, payroll (accounting
only), projects; golden files, property tests, mutation testing, fuzzing;
the formal methods bar (Kani on the kernel, Lean on the laws,
`just prove`).
- `ledger-store`: append-only hash-chained JSONL journal (source of truth),
SQLite as disposable projection with auto-rebuild, content-addressed
blob store, durable drafts.
- `ledger-mcp`: 27 tools (then over stdio and Streamable HTTP; since D-44
served only by the books server), preview-before-post,
server-side receipt policy (>$25) with anti-splitting, asset management,
digest for human review, read-only resources.
- `ledger-import`: QuickBooks CSV import (bank, chart), IIF and XLSX export.
- Capability parity 12 of 12 vs the GSheet+GDrive system.
- Parallel run with the sheet; cutover per the cutover rule
(`docs/parallel-run.md`).
### Phase 2 — AI-first interface (2026-10-10 to 2026-10-15)
## Served (2026-10-16; reworked for a team 2026-10-26)
MCP is the primary interface, not a cloned GUI (the owner, 2026-10-10).
`ledger-store` (hash-chained journal, SQLite projection, blob store),
`ledger-mcp` (now 122 tools on `main`, 2026-10-28), `ledger-import`
(QuickBooks CSV in; IIF, XLSX, PDF out), `ledger-package` (the CPA
package), the read-only viewer `ledger-gui` (first version 2026-10-12;
`plan/gui.md`). Capability parity 12 of 12 against the GSheet+GDrive
workflow; the Sheet was frozen as of 2026-10-11 and the books cut over
on 2026-10-20 (`docs/capability-parity.md`, `docs/parallel-run.md`, both
historical now).
The remaining work, its order, its dependencies and its hand-off are in
`plan/served.md` section 8.0; the team's prompt is `plan/HANDOFF.md`.
### Phase 3 — Oracle harness (partly done)
The books become a server that owns its data; every agent reaches them
only through the MCP, from anywhere; no scaffold. Phases P0 (guard
rails) through P10 (full re-audit of the first company's books through
the MCP alone), with the owner's decisions of 2026-10-16:
`plan/served.md`.
Done: the GnuCash differential (`just oracle`: 200 random books, 15,800
exact comparisons, adjudicated from principles; `docs/oracle.md` Layer
5), the mutation, fuzz and proof layers. Open: fixture books diffed as
`snapshot()` output automatically, and the machine-readable parity
catalog with CI enforcing the non-regression floor (the floor is 21
`done` rows, enforced by review until then).
## Phase 3 — Oracle harness
### "Served" P0 to P3, Projects, P4b S1 to S4.3 (2026-10-16 to 2026-10-27)
- `ledger-oracle`: fixture books through our engine and other
implementations (GnuCash headless first), automatic `snapshot()`
diffing. Each diff is adjudicated from principles; no other program is
the authority.
- Parity catalog becomes machine-readable; CI enforces the non-regression
floor.
- Done when: a fixture book produces byte-identical snapshots from both
engines with zero manual steps.
The books became a server that owns its data, reached only through the
MCP from anywhere, every setting in the journal, one executable, backups
that restore, the format gate, the live books moved and re-verified
(`plan/served.md` 8.1, `plan/STATUS.md`). Engine correctness (the 24
audit defects), projects, receivables and payables first class
(documents read their figures from tagged standing lines), the invoice
PDF, terms, numbers and line accounts in the core and the journal.
## Phase 4 — Read-only GUI (first version done, 2026-10-12)
## In flight (2026-10-28)
`ledger-gui`: see `plan/gui.md` for the design and what's built.
Built on paused branches, to be rebased and landed in order: P4b S4.4
(the create tools preview and confirm; the party contact block, D-55),
S5 (sent tracking), S6 (paying on terms: multi-document payments,
discounts, the processor fee, bills due, aging exports), S7 (bad debts),
P6 (the evidence pipeline: extraction, dedup, annotations). Then S4.5
(the PDF, viewer and handbook of `documents_v2`) and the owner's one
`documents_v2` upgrade of the live books (Q-5).
- Consumes the `ledger-store` event log: live updates — the answer to
"watch its files to update live."
- egui or web; a dumb client holding no accounting logic.
- This is the trust layer for humans (the owner, the other member, the CPA), not the
primary interface. Read-only at first; editing stays with the agent.
- Design references (the owner, 2026-10-11; screenshots shared in session,
described here):
- **Reports with a date range and a column interval** (QuickBooks
Desktop's P&L: From/To plus Columns = Year/Quarter/Month/...): any
statement split into one column per interval plus TOTAL, to see the
books over time. The multi-column statement layout in
`ledger-import::report` already renders this shape; the GUI (and the
exports) need a per-interval builder over the period-scoped core
statements.
- **Financial dashboard** (Coupler.io's QuickBooks dashboard): P&L,
balance sheet, and cash flow overview tables with Last month / Month to
date / Year to date columns, each beside charts — income vs. COGS +
expenses vs. earnings bars; stacked assets vs. liabilities + equity;
cash at end of period; net cash change.
- **Business overview** (QuickBooks Online home): cards for cash balance
with a trend, expenses by category (donut), profit and loss (income
vs. expenses), invoices (unpaid, overdue, paid), sales trend, and bank
account balances.
- **Revenue dashboard** (Coupler.io): KPI tiles (paid, overdue, open
invoices this month), an invoice table (number, customer, dates,
currency, home and foreign amounts, balance, totals), expenses by
category by month, invoices by status per month.
- **QuickBooks Online dashboard**: invoices (unpaid in the last year,
overdue vs. not yet due; paid in the last 30 days, deposited vs. not),
expenses by category (donut, last month), bank account balances (book
vs. bank, items to review), profit and loss (net income, income vs.
expenses bars), sales trend (line, by quarter).
- **KPI tiles with comparison** (QuickBooks accounting dashboard): income,
cost of goods sold, expenses, net profit, each with % change vs. the
previous 30 days; an auto date-range picker; cash balance over time
with a trend line; revenue by month, stacked.
- **Cash-flow dashboard**: bank balance, debtors, burn rate, cash runway
(days) tiles; income vs. expenses for the last six months; a net cash
flow forecast with a confidence band; A/P and A/R aging by days past
due (the engine already computes both agings); total burn over time.
## Next
## Phase 5 — Workflow parity
The order is `plan/served.md` 8.0.2. Two tracks run beside each other:
- A/R and A/P workflows, bank reconciliation, budgets, scheduled transactions.
- Multi-currency with FX translation.
- Period close.
- The goal: a self-hosted bookkeeping system with a tested claim to
proved accounting semantics (cross-checked against GnuCash and others)
and capability parity with the old
GSheet+GDrive workflow — no SaaS subscription required.
1. **The installed app: the destination (D-56, owner 2026-10-28).**
P11a: the platform groundwork first (the macOS and Windows keyring
stores, the Windows data root and pipes, a macOS and Windows CI
build; today the agent path works on Linux only), then the
cargo-packager trial, `wanderbooks update` and `rollback`, the Linux
packages (AUR, apt, dnf, AppImage), signing, the `.dmg` and the
per-user Windows installer, updates staged and applied at restart
(D-19, D-22, D-24 to D-26). Then P11b: the agent dock (Claude Code or
Codex in a terminal along the bottom of the viewer) and books homes
(D-27). "One app, one executable, separate processes."
2. **The agent surface and the re-audit.** P4 (draft states, one
evidence gate, the preview digest, the digest tool), P5 (the result
envelope, prompts, `books.start` v2, journal history, agent evals),
P8 (audit and attestations), P10 (the owner's full re-audit of the
first company's books through the MCP alone). P13 (bookspec, the
formal accounting specification: steps 4 to 6, the spec text, the
spec's own checker, the GnuCash adapter) runs beside. P12 (the whole
max-testing pass again: mutation, fuzzing, full property runs, proofs)
comes last, over everything.
## And then beyond
Self-host for the owner is built (P9a: a system unit, the move with the
head check, a static bearer over a tunnel). What follows the installed
app, in order of the plan's decisions: claude.ai and ChatGPT reaching a
self-hosted server through an external identity provider (P9b, after
Q-6); then the paid, multi-tenant hosted service `plan/served.md` section
11 describes and does not build (per-tenant processes, client-side vault
unwrap before any paid launch, a browser viewer, email-in, invitations).
The design is kept compatible with it at every step.
## Explicitly not on the roadmap
Bank feeds, payment processing, payroll, tax filing. Those are integrations
and regulated domains, not cloning targets. The engine gets clean seams for
them; someone else's API provides them.
Bank feeds, payment processing, payroll tax tables and filing, tax
filing. Those are integrations and regulated domains, not cloning
targets. The engine gets clean seams for them; someone else's API
provides them. Budgets were declined as bloat (R-FUTURE-6).
+34 -24
View File
@@ -57,6 +57,8 @@ Written 2026-10-26, when the plan was reworked for a team of engineers working i
**What changed on 2026-10-26.** A nine-stage review (`plan/review-2026-10-26/`) found the plan sound as a design record and not executable as a hand-off. Section 8 was rewritten: 8.0 to 8.4 are new; P4 was rewritten against the P4b slices built after it and D-47 (reversals stay posted); P6, P7, P8, P9, P10, P11 were cut to what the owner's decisions ask for; superseded sentences in sections 1 to 7 and 9 were struck through; the owner's P4b answers were numbered; decisions D-47 to D-54 and questions Q-4 to Q-7 were added. The review's reports list every finding and what was done with it.
**What changed on 2026-10-28.** The team's first wave was paused on 2026-10-27 (`plan/STATUS.md`). This revision records where that left things: 8.0.1 and the unit Status lines name the five branches built but unmerged (S4.4, S5, S6, S7, P6) and 8.0.2 the merge hazards between them, the owner's destination (D-56: the installed app; P11a starts now) and the resume order; 8.0.3 lists the names the EM approved during the wave (`tools/sent.rs`, `tools/settlements.rs`, `books.set_entry_settles`, `recipients`); P11a gains step 0 (the platform groundwork the design had assigned to P11 without a step); Q-5 is marked due and Q-8 added; superseded Landlock sentences in section 2 and `server.toml` in 3.2 and 3.4 are struck. The full comparison of plan, code and documents is `plan/2026-10-28_DRIFT_REPORT.md`.
---
## 1. Summary
@@ -83,14 +85,14 @@ Written 2026-10-26, when the plan was reworked for a team of engineers working i
| # | Invariant | Enforced by |
|---|---|---|
| I-1 | **The MCP is the only agent interface to the books.** Locally this is **advisory** (owner decision 2026-10-16): the server runs as the human, and the books are hidden, not locked. Mechanical enforcement is the self-host deployment on another machine, where agents have no access to the data root. | A data root outside every project directory (3.4), mode 0700, created with an explicit `set_permissions` call (not the umask). No tool, instruction, handbook text or result names a filesystem path (I-2, I-12). The stdio data-dir transport is gone (D-44): books are served only by the books server. `books.start`, `wanderbooks doctor` and the docs report `isolation: "same_user (advisory)"`. Landlock and seccomp confine the server itself where available; they do not restrict the agent and are never described as if they did. Test `agent_uid_cannot_read_tenant`, run in CI against the two-user self-host deployment, not the desktop default. |
| I-2 | **No tool takes or returns a server filesystem path.** | Schema lint `no_path_params`: the build fails on any parameter matching `*path*`, `save_to` or `*_file`. Landlock harness `no_tool_touches_outside_tenant`, run with fuzzed arguments. Static check: no `std::fs` in `ledger-mcp/src/tools/**` outside the ledger-store APIs. |
| I-1 | **The MCP is the only agent interface to the books.** Locally this is **advisory** (owner decision 2026-10-16): the server runs as the human, and the books are hidden, not locked. Mechanical enforcement is the self-host deployment on another machine, where agents have no access to the data root. | A data root outside every project directory (3.4), mode 0700, created with an explicit `set_permissions` call (not the umask). No tool, instruction, handbook text or result names a filesystem path (I-2, I-12). The stdio data-dir transport is gone (D-44): books are served only by the books server. `books.start`, `wanderbooks doctor` and the docs report `isolation: "same_user (advisory)"`. ~~Landlock and seccomp confine the server itself where available; they do not restrict the agent and are never described as if they did.~~ → D-32 (no confinement). Test `agent_uid_cannot_read_tenant`, run in CI against the two-user self-host deployment, not the desktop default. |
| I-2 | **No tool takes or returns a server filesystem path.** | Schema lint `no_path_params`: the build fails on any parameter matching `*path*`, `save_to` or `*_file`. ~~Landlock harness `no_tool_touches_outside_tenant`, run with fuzzed arguments.~~ → D-32. Static check: no `std::fs` in `ledger-mcp/src/tools/**` outside the ledger-store APIs. |
| I-3 | **The journal holds all books state.** Settings, conventions, decisions, draft states, evidence links, annotations, extraction records and attestations are journaled. Reports are pure functions of the journal. `wanderbooks.toml` is import/export text only. The server never reads a toml file. | `ledger-core::settings` replay. Property test `settings_replay_is_pure` (Store, Snapshot and the view are identical). Test `toml_round_trip_zero_events`. The daemon binary contains no toml file-read code path. |
| I-4 | **Money is exact Decimal, every entry balances, and posted entries are permanent.** Corrections are posted reversals; a reversal's evidence is its original's (D-47). ~~Corrections are reversal drafts that need evidence.~~ → D-47 | Existing kernel, Kani and Lean. New `Step.discard` (P4) with its preservation proof. ~~`Step.draftReversal`~~ → D-47 |
| I-5 | **Evidence gate.** One function, `ledger_core::evidence::requirement` (P4), decides whether a draft entry may post. Store, MCP and GUI all call it. Reversals are exempt: their evidence is the original's (D-47, D-12). Depreciation, amortization, closes and the entries the document, payroll, payout and disposal commands post are exempt by origin, and the exemption is sourced. ~~Reversals are not exempt.~~ → D-47 | The gate is called from `Store::post_entry` (P4 step 2). Test `gui_and_server_gate_agree`. Test `a_reversal_needs_no_receipt_of_its_own`. ~~`reversal_needs_evidence`~~ → D-47 |
| I-6 | **A confirmed commit is bound to the server's most recent preview of that exact draft or operation** (a stale or altered preview is refused). It does not prove that a human saw the preview; it detects drift (D-50). | `preview` = SHA-256 of the canonical preview payload (a draft's state and the settings seq; or the tool, its canonical arguments, the settings seq and the journal head seq), returned by every preview and required by every confirm from P4 on; a mismatch is refused with guard `stale_preview`. ~~`preview_token` = HMAC-SHA256 … keyed with a server secret held in `keys/`~~ → D-50 (a same-user key proves nothing; a digest detects the same drift). |
| I-7 | **A TIN passes through the agent only on its way into the vault; no result shows one except the TIN-bearing exports the owner chose (D-28, D-29).** ~~The agent never holds a full TIN or vault key material.~~ → D-28 | The v1 vault (`ledger-vault`, one key in `keys/legacy.key`, carried in every backup: D-31, D-48). A pattern-based TIN scanner (`has_full_tin`, `redact_full_tins`; P7 fixes its separators) fails closed on every result and masks the access log. The canary TIN tests in `crates/ledger-cli/tests/spec_vault.rs`. ~~HPKE, keyslots, human-page handlers, the GUI unlock path~~ → D-48 |
| I-8 | **The GUI never mutates and never uses the MCP.** Locally it reads the data root directly, read-only, as today. It finds the root from the platform's well-known location or from `wanderbooks gui <book>`, never from a project directory or `wanderbooks.toml`. `books.show` reaches it through `ops/show.jsonl` in the book's own data root, never through the MCP. Remote books (self-host) are viewed through a read-only replica stream (P9). | `ledger-gui/tests/read_only.rs`. Tests `gui_works_under_read_only_landlock` and `gui_finds_root_without_project_dir`. Test `replica_snapshot_equals_store_snapshot` (P9). The GUI writes nothing under the data root and leaves no files under `$HOME` except eframe preferences. |
| I-8 | **The GUI never mutates and never uses the MCP.** Locally it reads the data root directly, read-only, as today. It finds the root from the platform's well-known location or from `wanderbooks gui <book>`, never from a project directory or `wanderbooks.toml`. `books.show` reaches it through `ops/show.jsonl` in the book's own data root, never through the MCP. Remote books (self-host) are viewed through a read-only replica stream (P9). | `ledger-gui/tests/read_only.rs` (the viewer's read-only proof). ~~Tests `gui_works_under_read_only_landlock`~~ → D-32; `gui_finds_root_without_project_dir`. Test `replica_snapshot_equals_store_snapshot` (P9). The GUI writes nothing under the data root and leaves no files under `$HOME` except eframe preferences. |
| I-9 | **Every access through the server is logged, and logging fails closed.** | A hash-chained `access.jsonl` (own genesis). Property: exactly one record per tool call, upload, download, human action, remote replica connection and backup, refusals included (as built, slice 7: a backup's own runs are records of `ops/backup.jsonl`; `books.back_up_now`, a tool call, is in the access log). The local viewer's direct reads are not logged, because the GUI never writes; the docs say so. |
| I-10 | **Tamper evidence.** Every mutating result carries `head {seq, hash}`. The head is handed off when a session goes quiet. The customer can clone the archive and run `wanderbooks verify-archive --expect-head`. Backup and access records stay out of the journal, so they never advance the head they report. (As built, slice 7, D-31: each backup commit records its head; a restore's preview proves a clone and names its head, and weekly drills prove each target; no separate `verify-archive`.) | Test `backup_does_not_advance_head`. Test `clone_verify_expect_head` (as built: `a_restore_is_of_the_backup_previewed_only`, the drills). |
| I-11 | **No loss of ease of use.** Local setup is at most 3 commands on a clean machine, with no sudo, no system account and no container, beyond installing the app itself (D-24: on Linux the package manager asks for `sudo` as it does for every package; the dmg, the Windows installer and the AppImage ask for nothing). There is nothing to do per session, it works from any directory, the daily flow adds no client permission prompts (no `requiresUserInteraction`), and the viewer updates within 1 s of a post. | Acceptance criteria in P2 and P5. Tests `setup_needs_no_root` and `annotations_complete`. The agent-eval harness. |
@@ -169,7 +171,7 @@ The data root is `$XDG_DATA_HOME/wanderbooks` on Linux (default `~/.local/share/
### 3.2 Transport (one code path, local and remote)
Replaces `StreamableHttpServerConfig::default()` in `serve_http` (`ledger-mcp/src/main.rs:154-180`) with an explicit configuration:
- `allowed_hosts` taken from `server.toml` (deployment config only).
- ~~`allowed_hosts` taken from `server.toml` (deployment config only).~~ → not built: there is no `server.toml`; the deployment flags are `wanderbooks serve --http [ADDR]` (loopback only) and `--isolation` (P9a as built, 8.2).
- `enforce_origin_validation()` with an explicit list: loopback by default, plus `https://claude.ai` once OAuth exists in P9. Today's empty list turns the Origin check off.
- `json_response=true`.
- `legacy_session_mode=true` while Cursor and claude.ai stay on ≤ 2025-11-25.
@@ -231,7 +233,7 @@ Both protocol eras are served: `initialize` and `server/discover` are both built
<root>/ Linux: $XDG_DATA_HOME/wanderbooks (default ~/.local/share/wanderbooks)
macOS: ~/Library/Application Support/wanderbooks
self-host (P9): /srv/wanderbooks
server.toml deployment only: listen, public_url, allowed_hosts/origins, archive targets, issuer
(server.toml: not built → `serve --http`, `--isolation` carry the deployment flags, P9a; backup targets are book settings, D-30)
auth/principals.jsonl principals, sha256(token), scopes, labels; passkeys (hash-chained)
run/admin.sock
legacy/<id>-<date>/ old copies moved here at adoption if the owner agrees (Q-3); the server never deletes them
@@ -570,7 +572,7 @@ Report results also carry `as_of_status {drafts_open_on_or_before, unreconciled,
- Every mention of `just` or `wanderbooks.toml` in tool text: S:340, 390, 525, 546, 637, 640, 1902, 3061, 3251, 3374, 4060, 4315, 4568, 5194, 5829.
- `server.rs` (12,566 lines on 2026-10-26; six groups in `tools/` so far) is split by tool group in one go (U0a) before the remaining units open.
The tool count is 118 (2026-10-26) and grows by about 15. Only `books.start` and `books.handbook` load upfront under tool search.
The tool count is 122 on `main` (2026-10-28; the 118 of 2026-10-26 was stale, U0a's As-built) and becomes 130 when the paused S5, S6, S7 and P6 branches merge; P4, P5 and P8 add about 15 more. Only `books.start` and `books.handbook` load upfront under tool search.
---
@@ -798,7 +800,7 @@ Phases are labelled P0 to P13, with P4b (receivables and payables) between P4 an
### 8.0 How the work is organized
#### 8.0.1 Status and dependency table (2026-10-26)
#### 8.0.1 Status and dependency table (2026-10-28)
One row per unit of work. A unit is what one engineer takes into one git worktree and brings back as one or a few reviewed pull requests. "Depends on" lists the units that must be merged into `main` first. "Beside" lists units that may run at the same time in other worktrees because they share no exclusive file (8.0.3 lists the shared files every unit appends to by rule). "Go-ahead" is the owner's format upgrade a unit's writes need on the live books (D-39); merging never waits for it.
@@ -815,20 +817,20 @@ One row per unit of work. A unit is what one engineer takes into one git worktre
| U0a | Split `server.rs` by tool group | landed 2026-10-27 (`45396bdc`) | none | U0b, U0c, S4.1, S4.2, S7.1 (core steps only) | none | 3-4 |
| U0b | The attention engine over `PackageBooks` | landed 2026-10-27 (`26d3a994`) | none | U0a, U0c, S4.1, S4.2 | none | 4-6 |
| U0c | `docs/testing.md` sections for S1-B, S2, S3; `docs/mcp-interface.md` cleanup of stale P4b notes | landed 2026-10-26 (`198aa2a1`) | none | everything | none | 0.5-1 |
| P4b S4 | `documents_v2`: numbers, terms, line accounts, snapshots, preview and confirm, the issued PDF filed, party email and terms, invoicing settings | in progress: S4.1, S4.2, S4.3 landed 2026-10-27 (`d19fb464`); S4.4-S4.5 open | S4.1 and S4.2 need nothing; S4.3 needs S4.1, S4.2; S4.4 needs U0a, S4.3; S4.5 needs S4.4 | S5 (after S4.2), S7 (core after S1), P6, P9a, P11a, P13 | `documents_v2` (one upgrade after S7, D-52) | 12-16 |
| P4b S5 | Sent tracking | not started | S1; S4.2 for the defaults (works without it, see the unit) | S4.3 onward, S6 | `documents_v2` | 3-4 |
| P4b S6 | Paying on terms: multi-document payments, discounts, the processor fee, bills due, aging exports | not started | S4.1 (`Terms`), U0a | S5, S7, P6 | `documents_v2` | 8-10 |
| P4b S7 | Bad debts (write-offs) | not started | S1; S4.3 for the same-call evidence attach; U0a | S4.4 onward, S5, S6 | `documents_v2` | 4-6 |
| P4b S4 | `documents_v2`: numbers, terms, line accounts, snapshots, preview and confirm, the issued PDF filed, party email and terms, invoicing settings | in progress: S4.1-S4.3 landed 2026-10-27 (`d19fb464`); S4.4 built on branch `S4.4` (`002fb9f8`), paused 2026-10-27, unmerged; S4.5 not started | S4.1 and S4.2 need nothing; S4.3 needs S4.1, S4.2; S4.4 needs U0a, S4.3; S4.5 needs S4.4 | S5 (after S4.2), S7 (core after S1), P6, P9a, P11a, P13 | `documents_v2` (one upgrade after S7, D-52) | 12-16 |
| P4b S5 | Sent tracking | built on branch `S5` (`ad649be3`), paused 2026-10-27, unmerged; schema 17 | S1; S4.2 for the defaults (works without it, see the unit) | S4.3 onward, S6 | `documents_v2` | 3-4 |
| P4b S6 | Paying on terms: multi-document payments, discounts, the processor fee, bills due, aging exports | built on branch `S6` (`6c4480cd`), paused 2026-10-27, unmerged; no schema change; `confirmed` deferred to P4 | S4.1 (`Terms`), U0a | S5, S7, P6 | `documents_v2` | 8-10 |
| P4b S7 | Bad debts (write-offs) | built on branch `S7` (`4b4fecb9`), paused 2026-10-27, unmerged | S1; S4.3 for the same-call evidence attach; U0a | S4.4 onward, S5, S6 | `documents_v2` | 4-6 |
| P4 | Draft states, the evidence gate in one place, the preview digest, the digest tool | not started | S4-S7 merged (one sweep over every confirm tool), U0b | P6, P9a, P11a, P13 | `drafts_v2` (same upgrade as `documents_v2`, D-52) | 8-10 |
| P5 | Agent surface complete: the result envelope, prompts, `books.start` v2, journal history, agent evals | not started | P4, U0b; the envelope step is single-owner and merges when no other MCP branch is open | P6, P9a, P11a, P13 | `source_revisions` | 10-12 |
| P6 | Evidence pipeline: extraction, dedup, annotations, company record categories | not started | U0a, U0b | S4-S7, P4, P5 (not its envelope step), P9a, P11a, P13 | `attachment_text` | 8-10 |
| P6 | Evidence pipeline: extraction, dedup, annotations, company record categories | built on branch `P6`, checkpointed `ce366408` (gate interrupted; not for merge as is: rebase, retake schema 18, run `just check` to the end, review the store → import dependency) | U0a, U0b | S4-S7, P4, P5 (not its envelope step), P9a, P11a, P13 | `attachment_text` | 8-10 |
| P7 | The TIN scanner's separators; vault v2 closed (D-48) | landed 2026-10-26 (`3e65c83f`) | none | everything | none | 1 |
| P8 | Audit and attestations | not started | P6 (extraction), P4 (drafts), U0b | P9a, P11a, P13 | `audits` | 10-12 |
| P9a | Self-host recipe, `books adopt` move with the head check, static bearer over a tunnel, the two-user CI job | landed 2026-10-27 (`c8541ea9`); Done-when 1-2 are owner/EM to verify | none (code); a second machine to try it on | everything | none | 3-4 |
| P9b | claude.ai through an external identity provider (D-7 b, Q-6) | not planned until Q-6 is answered | P9a | | | |
| P9c | Remote viewer replica, invitations | not planned (D-51) | | | | |
| P10 | The re-audit runbook and its CI mirror; the owner runs the re-audit | not started | P5, P6, P8 | P11a, P13 | none | 1 (+ owner days) |
| P11a | Packaging and updates: the trial, `wanderbooks update`/`rollback`, Linux packages, signing, macOS and Windows bundles | not started | none (code); certificates and keys from the owner for the signing steps; Q-4 before the manifest step | everything | none | 20-25 |
| P11a | Packaging and updates: step 0 the platform groundwork, the trial, `wanderbooks update`/`rollback`, Linux packages, signing, macOS and Windows bundles | not started; **starts now, beside the P4b finish (D-56, 2026-10-28)** | none (code); certificates and keys from the owner for the signing steps; Q-4 before the manifest step | everything | none | 20-25 |
| P11b | The agent dock and books homes | not started | P11a (an installed app to dock into) | P12 | none | 8-10 |
| P12 | Max testing, again | not started | everything else merged | | none | 2-3 (+ machine time) |
| P13 | bookspec: checker crate, `Engine` trait, rule ids, the spec text, the runner | in progress: steps 1-3 landed 2026-10-26 (`579d0eed`); steps 4-6 open | none for steps 1-4; the engine stable for step 5 | everything | none | 15-20 |
@@ -853,6 +855,10 @@ everything ─> P12
The shortest path to P10 (the owner's goal: the whole re-audit through the MCP alone) is U0a, U0b → S4 (S5, S6, S7 beside it) → P4 → P5 → P6 (can start earlier) → P8 → P10. P9a, P11a, P13 and P7 run beside that chain whenever an engineer is free. P11b and P12 come last.
**The destination (D-56, 2026-10-28).** The owner's destination is one installed app for Mac, Windows and Linux (P11a, then P11b), and after it the hosted service of section 11. P11a is therefore staffed now, beside the P4b finish, not "any time"; its step 0 (the platform groundwork) comes first, because today the executable's agent path works on Linux alone (the keyring store exists for Linux only). The P10 chain keeps its order and runs beside it.
**Resuming the paused wave (paused 2026-10-27; see `plan/STATUS.md`).** Five units are built on branches and unmerged. Land them in this order, each rebased on `main` with its `just check` (and `just prove` where the unit says) re-run after the rebase, since the pause killed every gate: (1) S4.4 (`002fb9f8`; merges clean); (2) S5 (`ad649be3`; conflicts: `crates/ledger-cli/tests/documents.rs` add/add, which every P4b branch created from 8.0.3's one allocated file, so concatenate; `crates/ledger-mcp/src/types.rs`, both appends kept; schema 17 stands); (3) S6 (`6c4480cd`; `documents.rs`, `docs/mcp-interface.md`); (4) S7 (`4b4fecb9`; `documents.rs`, `types.rs`, `crates/ledger-store/src/lib.rs`; `just prove` for `writeOff_within_bounds`); (5) P6 (`ce366408` is a checkpoint, not a reviewed unit: rebase, resolve `types.rs`, `store/src/lib.rs`, `store/src/schema.rs` (retake schema 18: it took 16, which S4.3 holds), `store/tests/store.rs`, `docs/parity.md`, `docs/receipt-store.md`, `docs/spec/rules.md`, `docs/testing.md`; run its gate to the end; review its `ledger-store` → `ledger-import` dependency before merging). Law numbers in `docs/verification.md` at merge: S1's documents law is 34 (added on `main` 2026-10-28); S5's `Step.markSent` becomes 35 and S6's `settle_is_exact` 36 (both branches wrote 34); S7's write-off 37. Then S4.5, the only unstarted P4b slice. The single-owner rule of U0a holds throughout: no two of these merge at once.
Recommended staffing for a team of five: engineer A on U0a then S4.4/S4.5; B on U0b then P6; C on S4.1/S4.3 then S6; D on S4.2 then S5 then S7; E on P13 steps 1-3, then P9a, then P11a. The EM merges in the order above and holds the three single-owner moments: U0a (before any MCP-touching branch opens), P4's one sweep over the confirm tools, and P5's envelope step.
#### 8.0.3 Shared files, owners, and allocated names
@@ -861,7 +867,7 @@ These files are edited by nearly every unit. Each has one owner (the EM, or a na
| File | What every unit adds | Rule |
|---|---|---|
| `crates/ledger-mcp/src/server.rs` and `crates/ledger-mcp/src/tools/<group>.rs` | tool handlers | after U0a, a unit adds handlers only in its own group file (`tools/documents.rs`, `tools/drafts.rs`, `tools/evidence.rs`, `tools/audit.rs`, ...); `server.rs` keeps the router and the shared helpers |
| `crates/ledger-mcp/src/server.rs` and `crates/ledger-mcp/src/tools/<group>.rs` | tool handlers | after U0a, a unit adds handlers only in its own group file (`tools/documents.rs`; `tools/sent.rs` and `tools/settlements.rs`, which the EM approved during the first wave so S5 and S6 did not share S4.4's file, the payment and aging tools now in `settlements.rs`; `tools/drafts.rs`, `tools/evidence.rs`, `tools/audit.rs`, ...); `server.rs` keeps the router and the shared helpers |
| `crates/ledger-mcp/src/types.rs` | params and output structs | append at the end, under a `// <unit>` comment |
| `crates/ledger-mcp/src/scopes.rs` | one row per tool and the array length | append at the end of `TABLE`; bump the length |
| `crates/ledger-store/src/format.rs` | `KNOWN_FEATURES`, `EVENT_TYPES`, `setting_feature` arms | feature and event names are the ones allocated below; append |
@@ -897,7 +903,7 @@ These files are edited by nearly every unit. Each has one owner (the EM, or a na
| setting keys | `invoicing.number_prefix`, `invoicing.first_number`, `invoicing.default_terms`, `invoicing.payment_methods`, `invoicing.footer`, `invoicing.unsent_days`, `invoicing.reminder_days`, `bills.remind_days`, `bills.discount_warn_days`, `company.email`, `company.website` | S4 (S5 and S6 read the day counts) |
| setting key | `policy.attestation_bar` | P8 |
| roles | `bad_debts` (6990), `purchase_discounts` (6995), `sales_allowances` (4100, existing account), `payment_processing_fees` (the account payouts' fee lines already use) | S7, S6 |
| MCP tools, new | `books.mark_sent` (S5); `books.bills_due` (S6); `books.write_off_invoice` (S7); `books.preview_entry`, `books.list_drafts`, `books.set_draft_state`, `books.discard_draft` (P4); `books.journal_history` (P5); `books.find_attachment`, `books.annotate_attachment`, `books.consolidate_duplicates` (P6); `books.audit`, `books.workpaper`, `books.attest_receipt`, `books.review_entry`, `books.attest_period`, `books.attestations` (P8) | |
| MCP tools, new | `books.mark_sent` (S5; its recipients parameter is `recipients`, since the path lint refuses `to`); `books.bills_due` (S6); `books.write_off_invoice` (S7); `books.preview_entry`, `books.list_drafts`, `books.set_draft_state`, `books.discard_draft` (P4); `books.journal_history` (P5); `books.find_attachment`, `books.annotate_attachment`, `books.consolidate_duplicates`, `books.set_entry_settles` (P6; the last named in its Build step, allocated here 2026-10-28); `books.audit`, `books.workpaper`, `books.attest_receipt`, `books.review_entry`, `books.attest_period`, `books.attestations` (P8) | |
| MCP tools, changed | `books.create_invoice`, `books.create_bill`, `books.update_party` (S4); `books.receive_payment`, `books.pay_bill`, `books.ar_aging`, `books.ap_aging`, `books.export` (S6); `books.post_entry`, `books.reverse_entry`, `books.digest`, every tool with `confirmed` (P4); `books.start`, `books.set_convention`, `books.record_decision`, `books.raise_item` (P5); `books.get_receipt`, `books.attach_receipt`, `books.file_document` (P6); `books.export_cpa_package`, `books.verify` (P8) | |
| handbook sections | `invoices-and-bills` (S4; S5, S6, S7 add their steps to it), `drafts-and-reversals` rewritten (P4), `evidence-and-receipts` extended (P6), `attestations-and-audit` (P8), `self-host` (P9a) | |
| rules.md | B-39 terms (S4), B-40 numbers and the issued copy (S4), B-41 write-offs (S7), B-42 settlements and the fee (S6), B-43 drafts and evidence (P4), B-44 extraction and dedup (P6), B-45 audits and attestations (P8) | |
@@ -1279,7 +1285,7 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1
#### P4b S4: `documents_v2`
1. **Status:** not started.
1. **Status:** in progress: S4.1 (`13282cf8`), S4.2 (`bf91c5a7`) and S4.3 (`d19fb464`) landed 2026-10-27; S4.4 built on branch `S4.4` (`002fb9f8`), paused 2026-10-27, unmerged (its As-built block is on the branch); S4.5 not started.
2. **Depends on:** S1-S3 (landed). Inside the unit: S4.1 and S4.2 need nothing and may run in two worktrees; S4.3 needs both; S4.4 needs U0a and S4.3; S4.5 needs S4.4. S6 may start when S4.1 has merged; S5 when S4.2 has; S7.2 when S4.3 has. Go-ahead: `documents_v2`, one upgrade after S7 (D-52; Q-5 asks the owner whether to upgrade earlier). Until the go-ahead, on the owner's books a document carrying any new field is refused with `format_upgrade_pending`; a document carrying none posts exactly as before.
3. **Feature and schema:** feature `documents_v2` (R-A; shared with S5, S6, S7, so S4 creates the constant and the test and the later slices add their call sites). New fields on `invoice.created` and `bill.created` and on their lines, and on `party.updated`, as 8.0.3 lists; no new event type. Provisional schema 16: columns on the documents and document lines tables, a `parties.email` and two terms columns.
4. **Build:**
@@ -1327,7 +1333,7 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1
#### P4b S5: sent tracking (`invoice.sent`)
1. **Status:** not started.
1. **Status:** built on branch `S5` (`ad649be3`, 2026-10-27), paused, unmerged; its As-built block is on the branch.
2. **Depends on:** S1. S4.2 gives the defaults (`to` from the party's email; `invoicing.unsent_days`, `invoicing.reminder_days`); if S5 merges before S4.2, `to` is required and the day counts are the constants 2 and 14, and both paths are tested. MCP step needs U0a. Go-ahead: `documents_v2` (D-52).
3. **Feature and schema:** feature `documents_v2` (S5 adds its `ensure_feature` call site; the constant is S4's, or S5 creates it per R-A if S5 merges first); new event type `invoice.sent { invoice_id, on, by, via, to: [String], kind, reference?, note? }` (R-B); provisional schema 17: table `invoice_sends`.
4. **Build:**
@@ -1343,7 +1349,7 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1
#### P4b S6: paying on terms (multi-document payments, discounts, the processor fee, bills due, aging exports)
1. **Status:** not started.
1. **Status:** built on branch `S6` (`6c4480cd`, 2026-10-27), paused, unmerged; its As-built block is on the branch (`confirmed` deferred to P4's sweep; handlers in `tools/settlements.rs`).
2. **Depends on:** S4.1 (`Terms`, `discount_by`, `kernel::discount_max`), U0a. Go-ahead: `documents_v2` (D-52).
3. **Feature and schema:** feature `documents_v2` (call site in `Store::ensure_payment_features`); no new event type: `invoice.payment_received` and `bill.paid` gain `line` (the index of the control line this event tags), `discount`, `discount_line`, `discount_reason`, `fee`, `fee_line` (8.0.3). A payment entry that settles N documents is N events naming the same entry, each with its `line`; legacy events without `line` keep the positional rule ("the first untagged control line for the amount", rules.md B-38 item 1, test `several_payment_events_on_one_entry_tag_its_lines_in_order`). Provisional schema 18 if a column is needed for discounts and fees in the projection's payments table.
4. **Build:**
@@ -1362,7 +1368,7 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1
#### P4b S7: bad debts (`write_off_invoice`)
1. **Status:** not started.
1. **Status:** built on branch `S7` (`4b4fecb9`, 2026-10-27), paused, unmerged; its As-built block is on the branch.
2. **Depends on:** S1; S4.3 for the same-call attach (the write-off needs its evidence filed in the same store call); U0a for the MCP step. Go-ahead: `documents_v2`.
3. **Feature and schema:** feature `documents_v2`; new event type `invoice.written_off { invoice_id, entry_id, date, amount, reason }` (R-B). No schema change expected (the entry and its tag carry the figures; a column only if the projection's documents table needs `written_off`).
4. **Build:**
@@ -1420,7 +1426,7 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1
#### P6: evidence pipeline
1. **Status:** not started. Rewritten 2026-10-26 (D-32: no sandbox; D-46: no inline bytes; D-17: no email-in; no migration tools).
1. **Status:** built on branch `P6`, checkpointed `ce366408` (2026-10-27, "not for merge": its `just check` was interrupted by the pause and must run to the end after a rebase that retakes schema 18); its As-built block is on the branch. Rewritten 2026-10-26 (D-32: no sandbox; D-46: no inline bytes; D-17: no email-in; no migration tools).
2. **Depends on:** U0a, U0b. Independent of P4b and P4. Go-ahead: `attachment_text`.
3. **Feature and schema:** feature `attachment_text`; event types `attachment.text_extracted { attachment_id, text_sha256, extractor, version, pages, status: ok | none | failed }`, `attachment.annotated { attachment_id, fields { receipt_number?, payee?, amount?, date?, instrument?, category?, source?, reimbursable_to? }, note? }`, `entry.settles { entry_id, settles: [entry_id] }` (R-B); `attachment.withdrawn` gains `duplicate_of?`. Provisional schema 20: tables `extractions`, `annotations`.
4. **Build:**
@@ -1512,10 +1518,11 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1
#### P11a: packaging and updates (D-19, D-22, D-24, D-25, D-26)
1. **Status:** not started. P11 was split 2026-10-26 (D-54): P11a is installers and updates; P11b the agent dock and books homes.
1. **Status:** not started; starts now, beside the P4b finish (D-56, 2026-10-28). P11 was split 2026-10-26 (D-54): P11a is installers and updates; P11b the agent dock and books homes.
2. **Depends on:** none in code. From the owner before the signing steps: the Apple Developer ID certificate and notarization credentials as CI secrets; the Windows signing identity (Azure Artifact Signing if eligible, else an OV certificate); GitHub Releases enabled on the public mirror; the release hardware token; clean VMs or runners for the install tests. Q-4 (keep the two-key release manifest of D-25, or minisign alone) before step 5.
3. **Feature and schema:** none.
4. **Build:**
0. **Platform groundwork** (added 2026-10-28, D-56; the design assigned it to P11 in 3.3, 3.4, 3.9 and D-19 without a step): the macOS and Windows keyring stores behind `crates/ledger-host/src/tokens.rs::Keeper` (today every OS but Linux gets `NOT_YET`, so `wanderbooks connect` and the bridge fail there; `keyring-core`'s native stores, the same one-item-per-account rule and the same tests through the `file_keyring` knob); the Windows data root from the known-folder API under `%LOCALAPPDATA%` with an owner-only DACL (3.4) and named pipes with the SID check for `run/` (3.9); a CI matrix that builds and runs `cargo test --workspace` on `macos-latest` and `windows-latest` beside `ubuntu-24.04` (`.github/workflows/check.yml`), with the `cfg` gaps that build finds fixed. Done when `wanderbooks setup`, `books create`, `connect claude`, a bridge session, an upload and `wanderbooks gui` work on each OS from a source build, and the matrix is green. Independent of the trial; may run beside it. `crates/ledger-host/src/tokens.rs (changed)`, `crates/ledger-store/src/root.rs (changed)`, `crates/ledger-host/src/lease.rs` and the sockets (changed), `.github/workflows/check.yml (changed)`.
1. **The trial** (2-3 days): build all six formats with `cargo packager` (pinned in `mise.toml`: `cargo-packager`, `cargo-packager-updater`, `cargo-generate-rpm`) on clean VMs; record in `docs/packaging.md (new)` what each produced, what failed, and the decision for each format (a table: format | built by | installs as | updated by | signed by). Anything the tooling cannot meet is written there before anything is built around it.
2. **`wanderbooks update` and `rollback`** (`crates/ledger-host/src/commands.rs (changed)`, a new `update.rs`): check the feed (`releases/latest/download/manifest.json` on GitHub Releases, D-26), download and verify (step 5's signatures), stage under `<root>/updates/<version>/`, swap the executable atomically, then trigger the restart the host already has (`host.rs` INVARIANT 7: `run/update.lock`, `Ending::Restart`, `restart()`; `bridge.rs` `with_list_changed`: these exist; the updater only triggers them). `rollback` swaps back to the kept previous executable and refuses for a book that consented to a newer format (3.9). A package-managed install (AUR, apt, dnf) refuses `update` and says to use the package manager; the host notices the replaced executable and restarts when idle (exists). The format gate is unchanged (3.9). Tested against a `file://` feed: `update_is_atomic`, `failed_update_rolls_back`, `unsigned_update_refused` (a bad signature, a sha that differs from the manifest, each refused, nothing changed), `bridge_survives_update`, `update_waits_for_a_running_call`, `package_managed_install_refuses_update`.
3. **Linux packages** in CI containers (unsigned first): `.deb` with an apt repository index and `.rpm` with a dnf index served from GitHub Pages; the AUR `PKGBUILD`; the AppImage with self-update. `linux_packages_install_and_upgrade` (Arch, Debian, Fedora containers: install, open, upgrade, the host restarts, the books' head unchanged).
@@ -2019,6 +2026,7 @@ The owner decisions of 2026-10-16 (at the top of this document) replace the form
| D-53 | No `books.job` locally; no `ledger-view` or `ledger-extract` crate (2026-10-26 review) | Jobs, the 20 s rule and jobs as lease holders are not built locally (no call over the bridge approaches a client limit; 3.9 as built lets a running call finish before a close); they come with P9b if measured necessary. Needs attention lives in `ledger-package` over `PackageBooks` (U0b), not a new crate; extraction is in-process in `ledger-import` (P6), not a sandboxed subprocess (D-32). |
| D-54 | P11 split (2026-10-26 review; D-24 to D-27 unchanged) | **P11a:** installers and updates. **P11b:** the agent dock and books homes. The dock starts the agent as an ordinary child process of the viewer's `Owner` (D-32 removed the helper and the confinement); the viewer stays read-only by design and by test. The two-key release manifest of D-25 is built unless the owner answers Q-4 "minisign only". |
| D-55 | Party contact details (owner, 2026-10-27: asked which fields, chose "Full contact block") | A party carries, all optional and journaled on `party.updated` behind `documents_v2`: `phone`, `contact` (a named person), `billing_address`, `shipping_address`, `billing_email`. The existing `email` stays the general address and the existing `address` the general/business one; when `billing_email` or `billing_address` is set, an invoice's bill-to uses it, else the general one. `PartySnapshot` carries the same at issue; the issued PDF prints the contact person, phone, billing address and billing email, and prints a Ship-to line when a shipping address is set. `books.update_party` and `books.create_invoice`'s `bill_to` override take all six; `""` clears a text field. Both emails go through `parties::check_email` (one `@`, no spaces, the full-TIN scan). S4.4 builds the core, store, journal and MCP parts; S4.5 the PDF. Folded into `documents_v2` because the owner's upgrade has not happened (D-52), so no second go-ahead. No projection columns: there is no parties table in the SQLite projection, and replay plus `differs_from` carry the facts. Terms per side are already D-52/S4.2's and are unchanged. |
| D-56 | The destination, and when P11a starts (owner, 2026-10-28: the work is "ultimately taking it to a single bundled server+GUI installation for Mac/Windows/Linux and then beyond") | **The installed app is this plan's destination** (D-19, D-22 and D-24 to D-27 unchanged), and the hosted service of section 11 is what comes after it. So P11a is no longer "any time": it starts as soon as an engineer is free, beside the P4b finish, with its new step 0 first (the macOS and Windows keyring stores, the Windows data root and pipes, a macOS and Windows CI build), because today the executable's agent path works on Linux alone. The P10 chain (P4, P5, P8) keeps its order and runs beside it. |
### 10.2 Deferred
@@ -2027,16 +2035,18 @@ The owner decisions of 2026-10-16 (at the top of this document) replace the form
### 10.3 Open questions for the owner, and the closed ones
**Open (2026-10-26).** Each is asked when its unit starts, one at a time, in plain English; none blocks the units before it.
**Open (2026-10-28).** Each is asked when its unit starts, one at a time, in plain English; none blocks the units before it.
**Q-4 (before P11a step 5).** Releases: should the app check updates against our own signed release list as well (two keys, one on your hardware token and one offline, a version that only goes up, an expiry), as decided on 2026-10-18 (D-25), or is the packaging tool's own single-key signature plus Apple's and Microsoft's code signing enough? The second is simpler and already refuses an older version; the first also stops a frozen or replayed update list. Recommended: the first, as decided, since the key work is small once the token exists.
**Q-5 (when S4 lands).** The receivables and payables work needs one more go-ahead to switch your books to the new format (numbers, terms, line accounts, sent records, discounts, write-offs). Should we ask once, after everything is built (write-offs and discounts included), or earlier, after invoice numbers and terms land, with a second ask later? Recommended: once, after everything, unless you need numbered invoices sooner.
**Q-5 (due now: S4.1-S4.3 landed 2026-10-27 and S4.4 is built).** The receivables and payables work needs one more go-ahead to switch your books to the new format (numbers, terms, line accounts, sent records, discounts, write-offs). Should we ask once, after everything is built (write-offs and discounts included), or earlier, after invoice numbers and terms land, with a second ask later? Recommended: once, after everything, unless you need numbered invoices sooner.
**Q-6 (before P9b).** For claude.ai on the web to reach the books on your own server, it needs a sign-in service. Should we run an existing one (Authentik, Ory or Keycloak) beside the books, which we only trust tokens from, or write our own small one into the books? Recommended: an existing one (D-7 b): no security-critical code of ours, no outside review needed.
**Q-7 (when P11b starts).** When the app connects Codex to a company's books folder, may it mark that folder as trusted in Codex's own settings, or should Codex ask you itself the first time? Recommended: let Codex ask.
**Q-8 (now, with Q-5).** The 2026-10-26 review made eight engineering decisions in your name (D-47 to D-54: reversals stay posted with no reversal drafts; the vault stays v1; the P4b deferrals; the preview digest with no key; the P9 and P11 splits; one `documents_v2` upgrade; no jobs and no new crates), and S5, S6, S7 and P6 were built on them. Do they stand? Recommended: yes, as built; any you reverse becomes a new unit.
**Closed: the P2 cutover questions (Q-1 to Q-3).** Answered 2026-10-17 and 2026-10-20; the cutover happened 2026-10-20 (P2 slice 9). Kept for the record:
**Q-1. Where should the automatic backups go?** The books back themselves up after every change. Where should that copy live: in a private git repository you name (for example on your own git server), or on another disk? Either way, the backup includes the whole history and the sealed tax ID numbers, and it is locked with a key only you hold.
@@ -2080,7 +2090,7 @@ The cutover's check adds: the project folder holds none of the above, and `wande
| P8 | D-9, D-12, D-39 |
| P9a, P9b, P9c | top decision 4; D-7, D-27, D-28, D-31, D-32, D-51 |
| P10 | D-9, D-12, D-29, D-31, D-47 |
| P11a, P11b | D-19, D-22, D-24, D-25, D-26, D-27, D-32, D-54; Q-4, Q-7 |
| P11a, P11b | D-19, D-22, D-24, D-25, D-26, D-27, D-32, D-54, D-56; Q-4, Q-7 |
| P12 | D-33 |
| P13 | D-34 |
+1 -1
View File
@@ -292,7 +292,7 @@ footer { padding: 72px 0 48px; color: var(--faint); font-size: 14px; display: fl
<p class="sub">The one line at the top does everything: installs Rust if you don't have it, builds wanderbooks, makes a private folder for your books, starts them, and connects Claude Code. Nothing needs administrator rights, and nothing keeps running in the background once you're done.</p>
<div class="grid">
<div class="card"><h3>Linux</h3><p>Needs a C compiler and git (<code class="inline">build-essential</code> on Debian and Ubuntu). The installer tells you if anything's missing.</p></div>
<div class="card"><h3>macOS</h3><p>Needs Apple's command line tools: <code class="inline">xcode-select --install</code>.</p></div>
<div class="card"><h3>macOS</h3><p>Needs Apple's command line tools: <code class="inline">xcode-select --install</code>. The install, your books and the viewer work today; connecting Claude Code or Codex waits for the macOS keyring store, which comes with the app (soon).</p></div>
<div class="card"><h3>Windows</h3><p>Run it inside WSL2 (<code class="inline">wsl --install</code>, then Ubuntu). On Windows 11 the viewer opens as a normal window. Native Windows is on the way.</p></div>
</div>
<p class="note" style="margin-top:24px">Already installed? <code class="inline">wanderbooks books create another</code>, then <code class="inline">wanderbooks connect claude --book another</code>. <code class="inline">wanderbooks gui</code> opens the viewer; its Books menu backs up, restores, starts new books and closes them.</p>