From 8255ac210373484b253898bbce24f29b196d5d09 Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Wed, 21 Oct 2026 09:36:55 -0600 Subject: [PATCH] Tests and docs: no figures from the first company's books The odd-cent regression's net loss and its splits, the website's example Apple charge and the GUI plan's example receipt now use made-up amounts. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj --- .../members-close.odd-cent-across-closes.toml | 40 ++++++++--------- crates/ledger-core/src/ledger.rs | 8 ++-- crates/ledger-core/tests/odd_cent.rs | 44 +++++++++---------- docs/testing.md | 6 +-- plan/gui.md | 2 +- site/index.html | 2 +- 6 files changed, 51 insertions(+), 51 deletions(-) diff --git a/bookspec/examples/members-close.odd-cent-across-closes.toml b/bookspec/examples/members-close.odd-cent-across-closes.toml index ca5b66c..532465f 100644 --- a/bookspec/examples/members-close.odd-cent-across-closes.toml +++ b/bookspec/examples/members-close.odd-cent-across-closes.toml @@ -6,18 +6,18 @@ sources = ["26 U.S.C. §704(a)", "Treas. Reg. §1.704-1(b)(2)(iv)(b)"] tags = ["partnership", "close", "rounding", "book", "us"] # The regression this example comes from (wanderbooks P3 defect 17, audit -# F52, anonymized): a net loss of 399.23 at 50/50, closed in January and +# F52, anonymized): a net loss of 287.53 at 50/50, closed in January and # again in March, with February closed to retained earnings. Restarting the -# count at March gave A the tied cent twice (A −399.24, B −399.22). +# count at March gave A the tied cent twice (A −287.54, B −287.52). # # By hand, from the rule: -# January: −399.23 × 0.5 = −199.615 each; rounded toward zero, −199.61 +# January: −287.53 × 0.5 = −143.765 each; rounded toward zero, −143.76 # each, one cent short; the remainders tie (0.005), so the cent goes to -# the member listed first: A −199.62, B −199.61. +# the member listed first: A −143.77, B −143.76. # February: 10.00 to retained earnings; the members' count skips it. -# March: the count's running total is −798.46, −399.23 each exactly; -# less January's −199.62 / −199.61, March gives A −199.61, B −199.62. -# Each member ends at −399.23, their exact share. +# March: the count's running total is −575.06, −287.53 each exactly; +# less January's −143.77 / −143.76, March gives A −143.76, B −143.77. +# Each member ends at −287.53, their exact share. [setup] currency = "USD" @@ -65,8 +65,8 @@ share = "0.5" date = "2026-01-15" description = "January's fees" lines = [ - { account = "6000", side = "debit", amount = "399.23" }, - { account = "1000", side = "credit", amount = "399.23" }, + { account = "6000", side = "debit", amount = "287.53" }, + { account = "1000", side = "credit", amount = "287.53" }, ] [[events]] # event 2: the closing entry @@ -91,8 +91,8 @@ close = { start = "2026-02-01", to = "retained_earnings" } date = "2026-03-15" description = "March's fees" lines = [ - { account = "6000", side = "debit", amount = "399.23" }, - { account = "1000", side = "credit", amount = "399.23" }, + { account = "6000", side = "debit", amount = "287.53" }, + { account = "1000", side = "credit", amount = "287.53" }, ] [[events]] # event 6 @@ -105,25 +105,25 @@ query = "entry" entry = 2 [expect.values] -"6000.credit" = "399.23" -"3000.debit" = "199.62" -"3001.debit" = "199.61" +"6000.credit" = "287.53" +"3000.debit" = "143.77" +"3001.debit" = "143.76" [[expect]] query = "entry" entry = 6 [expect.values] -"6000.credit" = "399.23" -"3000.debit" = "199.61" -"3001.debit" = "199.62" +"6000.credit" = "287.53" +"3000.debit" = "143.76" +"3001.debit" = "143.77" [[expect]] query = "balances" as_of = "2026-03-31" [expect.values] -"3000" = "-399.23" -"3001" = "-399.23" +"3000" = "-287.53" +"3001" = "-287.53" "3999" = "-10.00" -"1000" = "-808.46" +"1000" = "-585.06" diff --git a/crates/ledger-core/src/ledger.rs b/crates/ledger-core/src/ledger.rs index dbe3ac9..1c38ee1 100644 --- a/crates/ledger-core/src/ledger.rs +++ b/crates/ledger-core/src/ledger.rs @@ -2225,10 +2225,10 @@ impl Ledger { /// 6. IF a journaled MembersCumulative names a start other than the /// one the books derive: SHOULD refuse (InvalidMembers) /// BECAUSE replay would split differently from the journal. - /// 7. IF 50/50 members closed −399.23 in January (A −199.62, B - /// −199.61), February closed to retained earnings, and March closes - /// −399.23 to the members: SHOULD give A −199.61, B −199.62, so - /// each has −399.23 (the count skips February's close). + /// 7. IF 50/50 members closed −287.53 in January (A −143.77, B + /// −143.76), February closed to retained earnings, and March closes + /// −287.53 to the members: SHOULD give A −143.76, B −143.77, so + /// each has −287.53 (the count skips February's close). /// ``` pub fn close_period_to( &mut self, diff --git a/crates/ledger-core/tests/odd_cent.rs b/crates/ledger-core/tests/odd_cent.rs index f75efe5..768fcb3 100644 --- a/crates/ledger-core/tests/odd_cent.rs +++ b/crates/ledger-core/tests/odd_cent.rs @@ -205,50 +205,50 @@ const THIRDS: [&str; 3] = ["0.3333", "0.3333", "0.3334"]; // The regression (audit F52, 2026-10-16, anonymized) // --------------------------------------------------------------------------- -/// Regression (P3 defect 17; audit F52's −399.23, anonymized): members A -/// and B at half each. January's net loss of 399.23 closes to them: exact -/// −199.615 each, so A −199.62, B −199.61 (the tie to the member listed +/// Regression (P3 defect 17; audit F52's −287.53, anonymized): members A +/// and B at half each. January's net loss of 287.53 closes to them: exact +/// −143.765 each, so A −143.77, B −143.76 (the tie to the member listed /// first). February's 10.00 loss closes to retained earnings. March's -/// 399.23 loss closes to them again. The run rule (2026-10-13 to P3) +/// 287.53 loss closes to them again. The run rule (2026-10-13 to P3) /// started over at March, handing A the tied cent a second time: A -/// −399.24, B −399.22 for an exact −399.23 each. Now February's close is -/// skipped and March continues January's count: the running −798.46 splits -/// −399.23 each, less January's −199.62 / −199.61, so March gives A -/// −199.61 and B −199.62. The March entry: Cr 6000 399.23, Dr 3000 199.61, -/// Dr 3001 199.62. +/// −287.54, B −287.52 for an exact −287.53 each. Now February's close is +/// skipped and March continues January's count: the running −575.06 splits +/// −287.53 each, less January's −143.77 / −143.76, so March gives A +/// −143.76 and B −143.77. The March entry: Cr 6000 287.53, Dr 3000 143.76, +/// Dr 3001 143.77. #[test] fn the_audit_odd_cent_never_piles_up_across_closes() { type Rule = fn(Vec) -> CloseTo; let (run, cumulative): (Rule, Rule) = (CloseTo::MembersRun, CloseTo::Members); for (rule, a, b) in [ - (run, "-399.24", "-399.22"), - (cumulative, "-399.23", "-399.23"), + (run, "-287.54", "-287.52"), + (cumulative, "-287.53", "-287.53"), ] { let mut co = company(Currency::USD, 2); let to = rule(co.members(&[0, 1], &HALF)); - let jan = co.month(1, "-399.23", &to); + let jan = co.month(1, "-287.53", &to); let jan_entry = co.l.get_period(jan).unwrap().closing_entry.unwrap(); assert_eq!( co.lines(jan_entry), [ - line("6000", Side::Credit, "399.23"), - line("3000", Side::Debit, "199.62"), - line("3001", Side::Debit, "199.61"), + line("6000", Side::Credit, "287.53"), + line("3000", Side::Debit, "143.77"), + line("3001", Side::Debit, "143.76"), ] ); co.month(2, "-10.00", &CloseTo::RetainedEarnings { sweep: vec![] }); - let mar = co.month(3, "-399.23", &to); + let mar = co.month(3, "-287.53", &to); assert_eq!(co.capitals(), decs(&[a, b])); let retained = co.l.chart().find_by_code("3999").unwrap().id; assert_eq!(co.l.account_balance(retained).unwrap(), dec("-10.00")); - if a == "-399.23" { + if a == "-287.53" { let mar_entry = co.l.get_period(mar).unwrap().closing_entry.unwrap(); assert_eq!( co.lines(mar_entry), [ - line("6000", Side::Credit, "399.23"), - line("3000", Side::Debit, "199.61"), - line("3001", Side::Debit, "199.62"), + line("6000", Side::Credit, "287.53"), + line("3000", Side::Debit, "143.76"), + line("3001", Side::Debit, "143.77"), ] ); let (since, split) = co.l.member_close_split(mar).unwrap(); @@ -257,8 +257,8 @@ fn the_audit_odd_cent_never_piles_up_across_closes() { assert_eq!( rows, [ - (dec("-199.61"), dec("-399.23"), dec("-399.23")), - (dec("-199.62"), dec("-399.23"), dec("-399.23")), + (dec("-143.76"), dec("-287.53"), dec("-287.53")), + (dec("-143.77"), dec("-287.53"), dec("-287.53")), ] ); } diff --git a/docs/testing.md b/docs/testing.md index 5f8703a..7b23aa2 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -602,10 +602,10 @@ Defect 17 (rules.md B-13; D-10, D-38), built without its mutation run worked by hand in the test's comment. **The named regression.** `the_audit_odd_cent_never_piles_up_across_closes` -(`ledger-core` `tests/odd_cent.rs`): audit F52's −399.23 at 50/50, +(`ledger-core` `tests/odd_cent.rs`): an audit finding's −287.53 at 50/50, anonymized, with a close to retained earnings between two members closes. -The run rule left A −399.24 / B −399.22; the rule since P3 gives −399.23 -each (March: Dr 3000 199.61, Dr 3001 199.62). Its bookspec example is +The run rule left A −287.54 / B −287.52; the rule since P3 gives −287.53 +each (March: Dr 3000 143.76, Dr 3001 143.77). Its bookspec example is `bookspec/examples/members-close.odd-cent-across-closes.toml`; it and the other `members-close.*` examples are checked with every example by `ledger-core` `tests/bookspec.rs` (`every_bookspec_example_holds`). diff --git a/plan/gui.md b/plan/gui.md index 2f3956d..f151710 100644 --- a/plan/gui.md +++ b/plan/gui.md @@ -37,7 +37,7 @@ journal with its verification status. hash-chained journal and the blob store and builds its own in-memory view (`ledger_store::Snapshot`). Changes happen through the agent (MCP). Where the GUI finds something to fix, it offers a ready-to-paste prompt - for the agent ("Attach the receipt for entry 12 — Anthropic, $5.82"). + for the agent ("Attach the receipt for entry 12 — Anthropic, $7.40"). 5. **Live.** It follows the journal: a change made by the agent appears within a second, highlighted as new. 6. **Numbers are typography.** Tabular figures everywhere (Inter with diff --git a/site/index.html b/site/index.html index 9a655de..439faa7 100644 --- a/site/index.html +++ b/site/index.html @@ -193,7 +193,7 @@ footer { padding: 72px 0 48px; color: var(--faint); font-size: 14px; display: fl

Just ask.

Your bookkeeper is the AI you already use, working through an accounting engine that won't let it be wrong. Talk to it the way you'd talk to a good bookkeeper. It does the work, shows you the result, and waits for your OK before anything is posted.

-
Find the receipt for the $106.38 Apple charge in my email and record it.

Searches your inbox, files the receipt as a PDF, drafts the entry with the right accounts, and shows you the preview.

+
Find the receipt for the $84.17 Apple charge in my email and record it.

Searches your inbox, files the receipt as a PDF, drafts the entry with the right accounts, and shows you the preview.

Here's last month's bank export. Categorize everything.

Imports the transactions as drafts, proposes an account for each from how you've booked them before, and asks about the ones it isn't sure of.

The domain renewal went to the wrong account. Fix it.

Reverses the entry and records it correctly. Nothing is ever erased; the history shows exactly what changed and why.

Show me every Adobe charge this year.

Opens the search in the viewer beside you, every charge listed, each one a click from its receipt.