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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
6 files changed
+51
-51
No files matched your search
@@ -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"
|
||||
@@ -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,
|
||||
|
||||
@@ -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<MemberClose>) -> 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")),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
+3
-3
@@ -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`).
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -193,7 +193,7 @@ footer { padding: 72px 0 48px; color: var(--faint); font-size: 14px; display: fl
|
||||
<h2>Just ask.</h2>
|
||||
<p class="sub">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.</p>
|
||||
<div class="grid">
|
||||
<div class="card ask"><div class="say">Find the receipt for the $106.38 Apple charge in my email and record it.</div><p>Searches your inbox, files the receipt as a PDF, drafts the entry with the right accounts, and shows you the preview.</p></div>
|
||||
<div class="card ask"><div class="say">Find the receipt for the $84.17 Apple charge in my email and record it.</div><p>Searches your inbox, files the receipt as a PDF, drafts the entry with the right accounts, and shows you the preview.</p></div>
|
||||
<div class="card ask"><div class="say">Here's last month's bank export. Categorize everything.</div><p>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.</p></div>
|
||||
<div class="card ask"><div class="say">The domain renewal went to the wrong account. Fix it.</div><p>Reverses the entry and records it correctly. Nothing is ever erased; the history shows exactly what changed and why.</p></div>
|
||||
<div class="card ask"><div class="say">Show me every Adobe charge this year.</div><p>Opens the search in the viewer beside you, every charge listed, each one a click from its receipt.</p></div>
|
||||
|
||||
Reference in new issue
Block a user