From cfaf05b8620311b58af2ae54d1aed7fc7b341f18 Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Thu, 29 Oct 2026 13:18:39 -0600 Subject: [PATCH] docs(plan): wave 1 landings; D-62 (Windows as P11c) and D-63 (tokens in a file, no keyring); units U0e and P11c 8.0.1 and the Status lines record U0d, S4.5, P13 steps 4-5 and P11a step 0 as landed. Two owner decisions from today's questions: D-62, the first bundled app ships for macOS and Linux and the native Windows port is its own unit P11c (step 0 found it is a port: the host, the MCP transport, the store's locking and permissions, the data root); D-63, agents' tokens live in a 0600 file under the 0700 data root on every OS and no OS keyring is used (the plan had never recorded the owner's view, so step 0 built two more stores). Unit U0e removes the three keyring stores and the knob; 3.3's keyring sentence and step 0's are struck. 8.0.3 confirms the eight bookspec example ids P13 took. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp --- plan/HANDOFF.md | 2 +- plan/STATUS.md | 20 ++++++++++++++++++- plan/served.md | 52 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/plan/HANDOFF.md b/plan/HANDOFF.md index 062d43a..4a238b2 100644 --- a/plan/HANDOFF.md +++ b/plan/HANDOFF.md @@ -18,7 +18,7 @@ You are the engineering manager (EM) of a team implementing the remaining work o - `main` is `bfd453b6`. Landed since the hand-off: U0a, U0b, U0c, P7, P9a, P13 steps 1-3, P4b S4.1, S4.2, S4.3 (2026-10-26 to 2026-10-27), then S4.4, S5, S6, S7 and P6 (2026-10-29, merged from the paused branches by the planning session). 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). - Nothing is built and unmerged. Branch `ci-fixes` (`76285434`, a fuzz target's renamed path and a regression test) is the one branch left to merge. -- Not started: S4.5 (next), U0d (after S4.5), P4, P5, P8, P10, P11a (starts now: D-56; step 0 first), P11b, P12, P13 steps 4-6. +- Landed 2026-10-29 by wave 1 of this session's subagents: U0d, S4.5, P13 steps 4-5, P11a step 0 (the portable CI job; its keyring stores are being removed). Building: P4, U0e. Not started: P5, P8, P10, P11a steps 1-7, P11b, P11c, P12, P13 step 6 (the owner's call). - 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. diff --git a/plan/STATUS.md b/plan/STATUS.md index 239f627..416174a 100644 --- a/plan/STATUS.md +++ b/plan/STATUS.md @@ -1,6 +1,24 @@ # STATUS — 2026-10-28: nine units landed, five built on paused branches; P11a starts -## Now (2026-10-29): the wave has landed; S4.5 next, P11a step 0 beside it +## Now (2026-10-29, evening): wave 1 of the rest of the plan is landing + +**Who builds.** The owner chose (the question tool) that this planning +session is the EM and launches Sonnet subagents in parallel worktrees, +one per unit, briefed from `plan/HANDOFF.md`; it reviews each against +the unit's Done-when, merges with a compile and the unit's own tests +(D-60), and runs one exhaustive gate per wave. Wave 1 so far: U0d +(`39c76d3f`), P11a step 0 (`5e220cca`; see below), S4.5 (`ac0c949b`: +P4b S4 is complete), P13 steps 4-5 (`d839e709`); P4 is still building. + +**Two decisions the wave forced.** D-62: native Windows is a port, not +cfg fixes (the host, the MCP transport, the store's locking and +permissions, the data root are Unix-only), so the first bundled app is +macOS and Linux and the port is unit P11c, beside P11b. D-63: agents' +tokens live in a 0600 file under the data root on every OS, no OS +keyring; the owner's standing view, which the plan had never recorded, +so P11a step 0 had built two more keyring stores. Unit U0e removes all +three stores and the `file_keyring` knob; it starts now beside P4. + **Where things stand.** `main` is `bfd453b6`. The five branches paused on 2026-10-27 are merged, in the 8.0.2 order, each with `just check` diff --git a/plan/served.md b/plan/served.md index c929803..9114227 100644 --- a/plan/served.md +++ b/plan/served.md @@ -195,7 +195,7 @@ Both protocol eras are served: `initialize` and `server/discover` are both built ~~No scope unwraps the vault. Unwrap happens only inside an `/h/` request that has just presented a human factor, or inside the local GUI process after the human types the passphrase (3.6).~~ → D-28, D-29: the server opens the vault for `set_tin`, `set_w9`, `get_w9`, `vendor_1099 include_tins` and `export_cpa_package`, which need books:post or books:admin as the As-built notes say; the viewer reads it with the book's key. *Until P7 moves TINs to the human pages, the three tools that can still put a full TIN out (`vendor_1099` with `include_tins`, `export_cpa_package`, `get_w9`) need books:admin, and sealing one (`set_tin`, `set_w9`) needs books:post (P2 slice 4, review).* -- **Local:** a static bearer `wb_` + 32 random bytes, stored only as a sha256, compared in constant time, kept in the OS keyring, minted by `wanderbooks connect`, and revocable with `wanderbooks token revoke`. Agent and server run as the same user, so the token identifies the client and keeps other local users and web pages out. It is not a wall against processes running as the human. +- **Local:** a static bearer `wb_` + 32 random bytes, stored only as a sha256, compared in constant time, ~~kept in the OS keyring~~ → D-63 (a 0600 file under the data root, on every OS; the keyring stores are removed by U0e), minted by `wanderbooks connect`, and revocable with `wanderbooks token revoke`. Agent and server run as the same user, so the token identifies the client and keeps other local users and web pages out. It is not a wall against processes running as the human. - Claude Code: `wanderbooks connect claude-code --book ` (also the app's "Connect Claude Code") runs `claude mcp add --scope user wanderbooks- -- mcp --book `: stdio, through the bridge (D-23). The bridge reads the token from the keyring itself, so Claude's config holds no token and no helper. It offers a `permissions.allow mcp__wanderbooks-` line. - Codex: `wanderbooks connect codex --book ` writes: @@ -819,8 +819,9 @@ 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 | -| U0d | The reader crate: `extract.rs` moves out of `ledger-import` so `ledger-store` sheds the typesetter (Q-9 → D-61) | not started; after S4.5 | P6 (landed) | everything | none | 0.5 | -| 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 landed 2026-10-29 (`d329bd6f`, gate 2,883 tests green); S4.5 not started, **next** | 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 | +| U0d | The reader crate: `extract.rs` moves out of `ledger-import` so `ledger-store` sheds the typesetter (Q-9 → D-61) | landed 2026-10-29 (`39c76d3f`) | P6 (landed) | everything | none | 0.5 | +| U0e | Tokens in a file under the data root; the OS keyring stores removed (D-63) | not started; **next**, beside P4 | none | everything but P11c | none | 1-2 | +| 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 landed 2026-10-29 (`d329bd6f`, gate 2,883 tests green); S4.5 landed 2026-10-29 (`ac0c949b`): P4b S4 is complete | 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 | landed 2026-10-29 (`3a3f03d8`; schema 17; law 35) | 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 | landed 2026-10-29 (`be580598`; no schema change; law 36); `confirmed` deferred to P4 | S4.1 (`Terms`), U0a | S5, S7, P6 | `documents_v2` | 8-10 | | P4b S7 | Bad debts (write-offs) | landed 2026-10-29 (`7ebeeed2`; law 37; `just prove` green) | S1; S4.3 for the same-call evidence attach; U0a | S4.4 onward, S5, S6 | `documents_v2` | 4-6 | @@ -833,10 +834,11 @@ One row per unit of work. A unit is what one engineer takes into one git worktre | 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: 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 | +| P11a | Packaging and updates: step 0 the platform groundwork, the trial, `wanderbooks update`/`rollback`, Linux packages, signing, macOS and Windows bundles | in progress: step 0 landed 2026-10-29 (`5e220cca`) for the macOS keyring store and the portable CI job; **the keyring stores go away under D-63 (unit U0e)** and native Windows is its own unit P11c (D-62); steps 1-7 open, macOS and Linux first | 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 | +| P11c | The native Windows port: named pipes with the SID check, owner-only DACLs, file locking, the `%LOCALAPPDATA%` data root, the Windows CI job made gating (D-62) | not started; after U0e, beside P11b | U0e; P11a step 0 (the portable job) | P11b, P12 | none | 5-8 | | 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 | +| 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-5 landed 2026-10-29 (`d839e709`; ten stated rules have no example yet because the schema has no event or query for them, listed in the As-built block); step 6 (the spec's own public repository) is the owner's call | none for steps 1-4; the engine stable for step 5 | everything | none | 15-20 | #### 8.0.2 Dependency graph and merge order @@ -889,6 +891,7 @@ These files are edited by nearly every unit. Each has one owner (the EM, or a na | Kind | Name | Unit | |---|---|---| | crate | `ledger-reader` (a library; D-53's `ledger-extract` subprocess stays closed) | U0d | +| bookspec example ids | `entry-an-unbalanced-entry-is-refused`, `entry-a-line-amount-is-positive`, `entry-cents-add-exactly`, `ledger-a-fraction-of-a-cent-is-refused`, `ledger-a-child-account-has-its-parents-type`, `ledger-a-mistake-is-reversed-never-erased`, `statement-the-books-balance-and-the-equation-holds`, `period-a-close-sweeps-the-year-into-capital` (taken by the engineer, confirmed by the EM 2026-10-29) | P13 steps 4-5 | | journal feature | `documents_v2` | S4, S5, S6, S7 (one feature for the four; D-52) | | journal feature | `drafts_v2` | P4 | | journal feature | `source_revisions` | P5 | @@ -1289,7 +1292,7 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1 #### U0d: the reader crate (Q-9, D-61) -1. **Status:** not started; after S4.5 (D-61: not urgent, never before S4.5 or P11a step 0). +1. **Status:** landed 2026-10-29 (`39c76d3f`, branch `U0d` at `bb1eb842`). 2. **Depends on:** P6 (landed). No owner go-ahead. 3. **Feature and schema:** none. No journal line changes; no money moves. 4. **Build:** @@ -1301,6 +1304,20 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1 7. **Done when:** (1) `cargo tree -p ledger-store -e normal` shows no `typst*` and no `ledger-import`; (2) `cargo tree -p ledger-import -e normal` shows no `ledger-store` (as today); (3) the three P6 extraction tests and the two fuzz targets pass where they now live; (4) `docs/architecture.md` has no "under review" sentence; (5) the batch's gate (D-60) green. 8. **As built:** `extract.rs` moved whole (`git mv`) to `crates/ledger-reader/src/lib.rs`; the new crate depends on `thiserror`, `hayro`, `hayro-interpret`, `kurbo`, `zip`, `quick-xml` only. `ledger-import` drops those (keeps `zip` as a dev-dependency for its test) and re-exports the crate with `pub use ledger_reader as extract;`, so `ledger_import::extract::*` still works for `ledger-gui`, `ledger-mcp`, `ledger-host` and the two fuzz targets (no caller changed). `ledger-store` depends on `ledger-reader` instead of `ledger-import`; `store.rs` and `tests/attachments.rs` use `ledger_reader::`. The three P6 tests stay in `crates/ledger-import/tests/extract.rs` (they build their PDFs with `ledger-import`'s statement writer; moving them would need a dev-dependency cycle) and pass through the re-export; the two unit tests moved with the module. `docs/architecture.md`, `docs/testing.md`, `AGENTS.md` updated. +#### U0e: tokens in a file, the OS keyring removed (D-63) + +1. **Status:** not started; next, beside P4 (it touches `ledger-host`, the CLI tests, the two-user job and the deploy docs; P4 touches none of them). +2. **Depends on:** none. No owner go-ahead (tokens are not in the journal). +3. **Feature and schema:** none. +4. **Build:** + 1. `crates/ledger-host/src/tokens.rs`: the `Files` keeper (today the `file_keyring` test knob's) becomes the only keeper: `keeper()` returns it always; the `Os` keeper, the Secret Service, Keychain and Credential Manager code, their `cfg` blocks, `NOT_YET` and the ignored `os_keyring_keeps_and_forgets` test are deleted; the module doc's INVARIANTS say where a token lives: a 0600 file under the root's `run/` (today's path), on every OS, written atomically (`tmp` then `rename`), readable by the server account alone, never by a tool (`crates/ledger-host/src/tokens.rs (changed)`). The knob `file_keyring` is removed from `crates/ledger-host/src/knobs.rs` and from every caller (`crates/ledger-host/src/commands.rs`, `crates/ledger-host/src/bridge.rs`, `crates/ledger-cli/tests/open_while_held.rs`, `crates/ledger-cli/tests/format_upgrade.rs`, `.github/workflows/two-user.yml`: the `--test-knobs file_keyring=1` arguments go). `crates/ledger-host/Cargo.toml` drops `keyring-core`, `apple-native-keyring-store`, `windows-native-keyring-store` and the Linux store crate; `Cargo.lock` follows. + 2. The bridge (`bridge.rs`) and `wanderbooks connect`/`token create`/`token print`/`token revoke` (`commands.rs`) read and write the file; the "no Secret Service" error paths and their remedies are deleted; `token create` on a headless server just works (P9a's `dbus-run-session` dance in `deploy/README.md` goes, and `install.sh`'s macOS skip of `connect claude` goes, since there is nothing OS-specific left). + 3. Docs: `deploy/README.md` (the recipe mints a token with no keyring), `README.md` (the macOS caveat is gone), `site/index.html` (same), `docs/packaging.md` (the keyring rows of the Unix-only inventory are gone), `docs/testing.md` (P9a's and P11a's test records say the knob is gone; U0e's record with its For-P12 paragraph, R-G), `docs/architecture.md`'s `ledger-host` row. In `plan/served.md` only this unit's As-built block. +5. **Files:** owns `crates/ledger-host/src/tokens.rs`; touches `knobs.rs`, `commands.rs`, `bridge.rs`, `crates/ledger-host/Cargo.toml`, `Cargo.lock`, the two CLI tests, `.github/workflows/two-user.yml`, `deploy/README.md`, `install.sh`, `README.md`, `site/index.html`, `docs/packaging.md`, `docs/testing.md`, `docs/architecture.md`. +6. **Tests and proofs:** the existing keeper tests in `tokens.rs` run against the file store (they already do, through the knob: they lose the knob); `a_token_file_is_owner_only` (new, `tokens.rs`: mode 0600 on Unix, created atomically, a second `create` for the same name replaces the first); the bridge and `open_while_held` tests unchanged in what they assert. No kernel, Kani or Lean change. +7. **Done when:** (1) `grep -ri "keyring\|keychain\|secret service\|credential manager" crates/ deploy/ install.sh README.md site/ .github/` finds only the history notes this unit leaves (one sentence in `tokens.rs`'s module doc saying what was removed and why, D-63); (2) `cargo tree -p ledger-host -e normal | grep -i keyring` prints nothing; (3) the named tests pass; (4) `two-user.yml` runs with no knob (the EM sees it green on GitHub); (5) `cargo build --workspace --all-targets` green. +8. **As built:** none yet. + #### P4b S4: `documents_v2` 1. **Status:** in progress: S4.1 (`13282cf8`), S4.2 (`bf91c5a7`) and S4.3 (`d19fb464`) landed 2026-10-27; S4.4 landed 2026-10-29 (`d329bd6f`, merged clean from branch `S4.4` at `002fb9f8`); S4.5 built 2026-10-29 on branch `S4.5`, not merged. @@ -1590,11 +1607,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; 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. +1. **Status:** in progress: step 0 landed 2026-10-29 (`5e220cca`) as far as the macOS store and the portable CI job; its keyring stores are removed by U0e (D-63), and the Windows half of step 0 moved to P11c (D-62). Steps 1 to 7 open, macOS and Linux first. 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)`. + 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`~~ → D-63 (no keyring on any OS; U0e removes the stores step 0 built); ~~the Windows data root, DACL and named pipes~~ → D-62 (unit P11c); what remains of step 0 is the portable CI job, landed (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 `/updates//`, 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). @@ -1621,6 +1638,21 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1 7. **Done when:** the three tests pass on Linux; the dock runs Claude Code in a books home on Linux and macOS; Windows recorded as offered or not. 8. **As built:** none yet. +#### P11c: the native Windows port (D-62) + +1. **Status:** not started; after U0e, beside P11b. Until it lands Windows is WSL2-only and the `portable (windows-latest)` job is allowed to fail. +2. **Depends on:** U0e (tokens are a file, so no Credential Manager store is ported); P11a step 0's portable job. +3. **Feature and schema:** none. +4. **Build:** the inventory is `docs/packaging.md` ("Unix-only code"), written by P11a step 0; each item becomes a step, each with the Windows implementation beside the Unix one behind `cfg`, never a `cfg(unix)` left bare: + 1. The data root from the known-folder API under `%LOCALAPPDATA%\wanderbooks` with an owner-only DACL where Unix has mode 0700 (`crates/ledger-store/src/root.rs (changed)`, 3.4); the `renameat2`-based moves get the Windows equivalent (`MoveFileEx` with replace). + 2. File locking: the store's `flock` gets `LockFileEx` behind one `lock.rs` seam (`crates/ledger-store (changed)`). + 3. The local transport: the lease socket and the MCP socket (`crates/ledger-host/src/lease.rs`, the host's sockets, `crates/ledger-mcp`'s peer-credential check) get named pipes under `\\.\pipe\wanderbooks--...` with the SID check where Unix checks peer uid (3.9); `seccomp` in `refuse.rs` and `close_range` in `host.rs` are Linux-only and stay behind `cfg(target_os = "linux")` with the Windows build doing nothing there (D-32: no confinement is promised). + 4. `.github/workflows/check.yml`: the Windows matrix entry's `experimental` becomes `false` once the job is green. +5. **Files:** owns the Windows arms of the files above; touches `docs/packaging.md` (the inventory rows are struck as each lands), `docs/architecture.md`, `docs/testing.md`, `README.md` (the Windows caveat goes). +6. **Tests and proofs:** the existing root, lock, lease and transport tests run on the Windows job (`cargo test --workspace` there); `a_second_user_cannot_open_the_pipe` (new, Windows-only, `crates/ledger-host`); no kernel, Kani or Lean change. +7. **Done when:** (1) the `portable (windows-latest)` job is green with `experimental: false`; (2) `wanderbooks setup`, `books create`, `connect claude`, a bridge session, an upload and `wanderbooks gui` work on Windows from a source build (the engineer or the owner on a Windows machine; recorded in the As-built block); (3) `docs/packaging.md`'s Unix-only inventory is empty. +8. **As built:** none yet. + #### P12: max testing, again (D-33) 1. **Status:** not started. @@ -1636,7 +1668,7 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1 #### P13: bookspec, a formal accounting specification (D-34) -1. **Status:** not started as a unit. The seed exists in this repository: `bookspec/README.md` (the TOML schema: `id, title, rule, status, sources, tags, appendix?`; `[setup]`; `[[events]]` of kinds `lines | reverses | close | bill | invoice | run_depreciation | dispose_asset | run_schedules | register_schedule` with `refused`, `payee`, `parties`, `instrument`, `older`; `[[changes]]`; `[[expect]]` with its query table), 56 examples in `bookspec/examples/`, the loader `crates/ledger-core/tests/bookspec.rs` (`every_bookspec_example_holds`: applies each example to a real `Store` and verifies it) and `crates/ledger-package/tests/package.rs::the_bookspec_iif_example_matches_the_engine`. Every P3 regression test and every P4b example is written there as it is built. The spec text, the formal validation and the conformance harness are the unit. +1. **Status:** in progress: steps 1-3 landed 2026-10-26 (`579d0eed`), steps 4-5 on 2026-10-29 (`d839e709`); step 6 is the owner's call. The seed existed in this repository: `bookspec/README.md` (the TOML schema: `id, title, rule, status, sources, tags, appendix?`; `[setup]`; `[[events]]` of kinds `lines | reverses | close | bill | invoice | run_depreciation | dispose_asset | run_schedules | register_schedule` with `refused`, `payee`, `parties`, `instrument`, `older`; `[[changes]]`; `[[expect]]` with its query table), 56 examples in `bookspec/examples/`, the loader `crates/ledger-core/tests/bookspec.rs` (`every_bookspec_example_holds`: applies each example to a real `Store` and verifies it) and `crates/ledger-package/tests/package.rs::the_bookspec_iif_example_matches_the_engine`. Every P3 regression test and every P4b example is written there as it is built. The spec text, the formal validation and the conformance harness are the unit. 2. **Depends on:** nothing for steps 1-4; the engine stable (P4b, P4 landed) for step 5. Runs beside everything. 3. **Feature and schema:** none. 4. **Build:** @@ -2112,6 +2144,8 @@ The owner decisions of 2026-10-16 (at the top of this document) replace the form | D-59 | Mutation testing in CI (owner, 2026-10-29, asked how the always-red weekly mutation shards should run until P12: "Don't think we need to run the long ass shit like mutation testing in CI. It's more for local test runs.") | **Mutation testing is a local run, never a CI job.** The mutation shards are removed from `scheduled.yml`, which keeps the proofs, the GnuCash oracle and the fuzz targets weekly; `just mutants-*` stays for the desktop, and P12 runs the whole pass there (D-33). The 2026-10-26 weekly run's survivors (real ones in every crate, and timeouts) are P12's list. | | D-60 | How much checking each merge gets (owner, 2026-10-29, after the paused wave took twelve hours to land with a full gate around every merge: "merge, and then just ... compile it once, make sure it compiles. Maybe run some specific tests related to that and then move to the next one, merge ... And then after you have done either several of them or even all of them, then run the super exhaustive test suites") | **Per merge, a compile and the unit's own tests; the exhaustive gates (`just check`, `just prove`, fuzz) once per batch, at the end, and their findings fixed together.** GitHub's `check` job stays the gate on every push. `plan/HANDOFF.md` "Reviewing and merging" carries the rule; AGENTS.md's "before every commit" is read as before every push of a batch, not before every merge inside one. | Every remaining unit; the EM's merge procedure | | D-61 | Q-9 answered (owner, 2026-10-29, the question tool: "Split the reader out later") | **The reader (`extract.rs`) moves into a small library crate of its own, `ledger-reader`, that `ledger-store` and `ledger-import` both depend on; a half-day unit (U0d) for the implementing team after S4.5.** Until then the arrow stands as built; `ledger-import` never depends on `ledger-store`. | U0d; `docs/architecture.md` | +| D-62 | Native Windows (owner, 2026-10-29, the question tool, after P11a step 0 found the Windows side is a port, not cfg fixes: "macOS first, Windows port as its own unit") | **The first bundled app ships for macOS and Linux; the native Windows port is unit P11c**, built after U0e beside P11b; Windows stays WSL2-only meanwhile and the `portable (windows-latest)` job is allowed to fail until P11c lands. D-56's destination is unchanged, only its order. | P11a, P11b, P11c | +| D-63 | Where agents' tokens live (owner, 2026-10-29, the question tool, on seeing P11a step 0 add Keychain and Credential Manager stores: "why are you talking about the OS keyring? I thought we made a decision to not use that garbage"; the plan had no such decision recorded, so this one records it) | **A 0600 file under the 0700 data root, on every OS; no OS keyring.** The data root is the trust boundary already (I-1: hidden, not locked, same user), so the keyring added no wall and cost headless servers a D-Bus session, CI a knob, and every OS its own store. Unit U0e removes the Secret Service, Keychain and Credential Manager stores and the `file_keyring` knob; 3.3's sentence is struck. | U0e, P9a's recipe, P11a, P11c | ### 10.2 Deferred