P3: party totals by what moved the money, once (defects 14, 11, 24)

Each party's part of an entry is signed as its own account would show it,
with a direction and its cash and in-kind amounts; a reversal is its
original negated. Totals on a cash or all basis: for a member, all equals
the members' equity statement and cash the K-1's cash. Money is cash,
cards and the financing accounts, and a liability credit never pays its
own creditor (creditor_of), so accruals and declared distributions count
once. tin_last4 from the TIN or W-9 facts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-21 12:12:26 -06:00
1 parent 9ab003d0d1
commit c2ceabbae9
52 files changed
+7535 -560

No files matched your search

@@ -0,0 +1,134 @@
# P3 defect 24 (found in design; wanderbooks plan/served.md P3 "Settled in
# design"): party totals treated every liability but payables and payroll
# as money, so an accrual through another liability counted when it was
# booked and again when it was settled. Regression test: ledger-core
# tests/spec_party_totals.rs
# defect24_an_accrual_through_another_liability_counts_once. The shape:
# bookspec/README.md.
id = "p3-party-accrual-counts-once"
title = "An accrual through a liability that isn't money counts once, when it is settled"
rule = """
Money is cash, the company's cards, the members' financing and loans.
Every other liability (accrued expenses, deferred revenue) is a promise:
an entry through it moves nothing with the party until it is settled in
money.
"""
status = "CHOICE"
sources = [
"Helvering v. Price, 309 U.S. 409, 412-413 (1940): a promise to pay is not payment (wanderbooks docs/spec/sources/helvering-v-price-1940.md)",
"DECISION (owner, 2026-10-20): money is cash, cards, the members' financing and loans (wanderbooks rules.md B-35 item 5)",
]
tags = ["parties", "accruals", "deferred-revenue", "money"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-even"
cash_accounts = ["1000"]
financing_accounts = ["2100"]
[[setup.accounts]]
code = "1000"
name = "Checking"
type = "asset"
[[setup.accounts]]
code = "2100"
name = "Due to Members"
type = "liability"
[[setup.accounts]]
code = "2200"
name = "Accrued Expenses"
type = "liability"
[[setup.accounts]]
code = "2400"
name = "Deferred Revenue"
type = "liability"
[[setup.accounts]]
code = "4000"
name = "Revenue"
type = "revenue"
[[setup.accounts]]
code = "6050"
name = "Domain & Hosting"
type = "expense"
[[setup.parties]]
name = "Northwind Filings"
roles = ["vendor"]
[[setup.parties]]
name = "Riley Chen"
roles = ["customer"]
[[events]]
date = "2026-03-31"
description = "Hosting accrued"
parties = [{ party = "Northwind Filings" }]
lines = [
{ account = "6050", side = "debit", amount = "300.00" },
{ account = "2200", side = "credit", amount = "300.00" },
]
[[events]]
date = "2026-04-15"
description = "Hosting paid"
parties = [{ party = "Northwind Filings" }]
lines = [
{ account = "2200", side = "debit", amount = "300.00" },
{ account = "1000", side = "credit", amount = "300.00" },
]
[[events]]
date = "2026-01-02"
description = "A year paid ahead"
parties = [{ party = "Riley Chen" }]
lines = [
{ account = "1000", side = "debit", amount = "1200.00" },
{ account = "2400", side = "credit", amount = "1200.00" },
]
[[events]]
date = "2026-01-31"
description = "January earned"
parties = [{ party = "Riley Chen" }]
lines = [
{ account = "2400", side = "debit", amount = "100.00" },
{ account = "4000", side = "credit", amount = "100.00" },
]
[[expect]]
query = "party_part"
entry = 1
party = "Northwind Filings"
values = { resolved = "300.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
# Before P3: 600.00.
[[expect]]
query = "party_totals"
party = "Northwind Filings"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "300.00", received = "0.00" }
[[expect]]
query = "party_part"
entry = 4
party = "Riley Chen"
values = { resolved = "100.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
# Before P3: 1,300.00.
[[expect]]
query = "party_totals"
party = "Riley Chen"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "1200.00" }
@@ -0,0 +1,200 @@
# P3 defect 24 in a member's entry (found in review, 2026-10-21): a
# distribution declared to a liability that isn't money counted as paid
# when declared and again when paid. A distribution's cash is the money it
# paid, its in kind the property it gave; the rest is still owed. Regression
# tests: ledger-core tests/spec_party_totals.rs
# defect24_a_distribution_declared_to_a_payable_counts_once_when_paid and
# a_distribution_of_money_and_depreciated_property_splits_by_what_moved.
# The shape: bookspec/README.md.
id = "p3-party-distribution-still-owed"
title = "A distribution counts the money it paid and the property it gave; what is still owed counts when paid"
rule = """
An entry naming only members that moves their capital counts what moved
it. Of a distribution, the cash is the money it paid (through the cash
accounts, a card, the members' financing or a loan), the in kind the
property it gave up (at what the books carried it), and the rest, credited
to a liability that isn't money for the entry (distributions payable, or
what the members are owed when they are named its creditors), is a
promise: it counts nothing until it is paid, then once, as paid. The
statement of members' equity counts a distribution when it is declared,
so party totals catch up with it when it is paid.
"""
status = "AUTHORITY"
sources = [
"Helvering v. Price, 309 U.S. 409, 412-413 (1940): a promise to pay is not payment (wanderbooks docs/spec/sources/helvering-v-price-1940.md)",
"Treas. Reg. §1.704-1(b)(2)(iv)(b)(4)-(5): a partner's capital account falls by the money and the property distributed (docs/spec/sources/irs-capital-accounts.md)",
"DECISION (owner, 2026-10-20): a member's entry counts what moved their capital; money is cash, cards, the members' financing and loans (rules.md B-35)",
]
tags = ["parties", "members", "distributions", "promises", "in-kind", "money"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-even"
cash_accounts = ["1000"]
[[setup.accounts]]
code = "1000"
name = "Checking"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation — Equipment"
type = "asset"
[[setup.accounts]]
code = "2150"
name = "Distributions Payable"
type = "liability"
[[setup.accounts]]
code = "3000"
name = "Capital — Tobin Harlow"
type = "equity"
[[setup.accounts]]
code = "3001"
name = "Capital — Morgan Ellis"
type = "equity"
[[setup.accounts]]
code = "3100"
name = "Distributions — Tobin Harlow"
type = "equity"
[[setup.parties]]
name = "Tobin Harlow"
roles = ["member"]
[[setup.parties]]
name = "Morgan Ellis"
roles = ["member"]
[[setup.members]]
name = "Tobin Harlow"
share = "0.5"
capital_account = "3000"
distributions_account = "3100"
[[setup.members]]
name = "Morgan Ellis"
share = "0.5"
capital_account = "3001"
# 1. A distribution declared to Tobin: still owed, counts nothing.
[[events]]
date = "2026-06-30"
description = "Distribution declared"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "3100", side = "debit", amount = "200.00" },
{ account = "2150", side = "credit", amount = "200.00" },
]
# 2. It is paid: paid, money, once.
[[events]]
date = "2026-07-15"
description = "Distribution paid"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "2150", side = "debit", amount = "200.00" },
{ account = "1000", side = "credit", amount = "200.00" },
]
# 3. Declared and partly paid at once: the money now, the rest when paid.
[[events]]
date = "2026-08-31"
description = "Distribution, part paid"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "3100", side = "debit", amount = "300.00" },
{ account = "1000", side = "credit", amount = "100.00" },
{ account = "2150", side = "credit", amount = "200.00" },
]
# 4. Equipment carried at 1,000.00 less 300.00 depreciated, with 100.00 in
# cash, distributed to Morgan: 100.00 cash, 700.00 in kind.
[[events]]
date = "2026-09-01"
description = "Equipment and cash distributed"
parties = [{ party = "Morgan Ellis" }]
lines = [
{ account = "3001", side = "debit", amount = "800.00" },
{ account = "1510", side = "debit", amount = "300.00" },
{ account = "1500", side = "credit", amount = "1000.00" },
{ account = "1000", side = "credit", amount = "100.00" },
]
[[expect]]
query = "party_part"
entry = 1
party = "Tobin Harlow"
values = { resolved = "200.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 3
party = "Tobin Harlow"
values = { resolved = "300.00", direction = "paid", cash = "100.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 4
party = "Morgan Ellis"
values = { resolved = "800.00", direction = "paid", cash = "100.00", in_kind = "700.00" }
# Before the review: 700.00 (event 1's 200.00 and the 200.00 still owed
# on event 3 counted as paid, and event 2 paid the first again).
[[expect]]
query = "party_totals"
party = "Tobin Harlow"
basis = "cash"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "300.00", received = "0.00" }
# Through June: declared, not yet paid. The statement counts it already.
[[expect]]
query = "party_totals"
party = "Tobin Harlow"
basis = "all"
from = "2026-01-01"
to = "2026-06-30"
values = { paid = "0.00", received = "0.00" }
[[expect]]
query = "members_equity"
from = "2026-01-01"
to = "2026-06-30"
values = { "Tobin Harlow.contributions" = "0.00", "Tobin Harlow.distributions" = "200.00" }
# Before the review: 0.00 cash, 800.00 in kind.
[[expect]]
query = "party_totals"
party = "Morgan Ellis"
basis = "cash"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "100.00", received = "0.00" }
[[expect]]
query = "party_totals"
party = "Morgan Ellis"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "800.00", received = "0.00" }
[[expect]]
query = "members_equity"
from = "2026-01-01"
to = "2026-12-31"
values = { "Morgan Ellis.contributions" = "0.00", "Morgan Ellis.distributions" = "800.00" }
@@ -0,0 +1,92 @@
# P3 defect 24 and the card rule (found in review, 2026-10-21): the
# company's cards are the liabilities whose names say "card", so a gift
# card the company sold (deferred revenue) read as money: received when
# sold and again when redeemed. Regression
# test: ledger-core tests/spec_party_totals.rs
# defect24_a_gift_card_sold_is_received_once.
# The shape: bookspec/README.md.
id = "p3-party-gift-card-is-a-promise"
title = "A gift card the company sold is a promise, not a card it pays with"
rule = """
The company's cards are liability accounts whose names say "card", but not
"gift card": gift cards the company sold are revenue it owes its customers
in service (deferred revenue), a promise. Selling one is money received
from the buyer; redeeming it moves no money and counts nothing.
"""
status = "CONVENTION"
sources = [
"DECISION (owner, 2026-10-20): money is cash, cards, the members' financing and loans; every other liability is a promise, counted when settled (wanderbooks rules.md B-35 item 5)",
"Helvering v. Price, 309 U.S. 409, 412-413 (1940): a promise to pay is not payment (docs/spec/sources/helvering-v-price-1940.md)",
]
tags = ["parties", "cards", "deferred-revenue", "money"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-even"
cash_accounts = ["1000"]
[[setup.accounts]]
code = "1000"
name = "Checking"
type = "asset"
[[setup.accounts]]
code = "2050"
name = "Business Card"
type = "liability"
[[setup.accounts]]
code = "2410"
name = "Gift Card Liability"
type = "liability"
[[setup.accounts]]
code = "4000"
name = "Revenue"
type = "revenue"
[[setup.parties]]
name = "Riley Chen"
roles = ["customer"]
[[events]]
date = "2026-03-01"
description = "Gift card sold"
parties = [{ party = "Riley Chen" }]
lines = [
{ account = "1000", side = "debit", amount = "100.00" },
{ account = "2410", side = "credit", amount = "100.00" },
]
[[events]]
date = "2026-03-05"
description = "Gift card redeemed"
parties = [{ party = "Riley Chen" }]
lines = [
{ account = "2410", side = "debit", amount = "100.00" },
{ account = "4000", side = "credit", amount = "100.00" },
]
[[expect]]
query = "party_part"
entry = 1
party = "Riley Chen"
values = { resolved = "-100.00", direction = "received", cash = "-100.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 2
party = "Riley Chen"
values = { resolved = "100.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
# Before the review: 200.00.
[[expect]]
query = "party_totals"
party = "Riley Chen"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "100.00" }
@@ -0,0 +1,219 @@
# P3 defect 14, settled in design (wanderbooks plan/served.md P3): party
# totals count a member's entry by what moved their capital, so basis all
# is the statement of members' equity and basis cash means what it means
# on the K-1 worksheet. Regression tests: ledger-core
# tests/spec_party_totals.rs a_members_mixed_entry_splits_as_the_k1_does,
# basis_all_is_the_members_equity_statement_and_cash_the_k1s, and the
# property member_totals_are_the_members_equity_statement. The shape:
# bookspec/README.md.
id = "p3-party-members-equity-and-k1"
title = "A member's totals are their capital account: basis all the statement of members' equity, basis cash the K-1's cash"
rule = """
An entry naming only members that moves their equity counts what moved
their capital: a contribution received, a distribution paid. The
property in it (asset accounts that are neither cash nor receivables) is
in kind, shared among the members in proportion to their parts, to the
cent, leftover cents by largest remainder, ties to the member listed
first; the rest is cash, as the K-1 worksheet counts it: money, or what a
member paid for the company (an expense booked straight to capital, a
debt to them converted to capital).
"""
status = "CHOICE"
sources = [
"Treas. Reg. §1.704-1(b)(2)(iv)(b)(1)-(2), (c)(1): money and property contributed; a partnership liability a partner pays is money contributed (wanderbooks docs/spec/sources/irs-capital-accounts.md)",
"Partner's Instructions for Schedule K-1 (Form 1065), Item L: the capital contributed during the year (docs/spec/sources/irs-capital-accounts.md)",
"DECISION (owner, 2026-10-15): what a member paid for the company is cash on the K-1 (wanderbooks ledger-core k1 INVARIANT 3); DECISION (owner, 2026-10-20): a member's entry counts what moved their capital (rules.md B-35)",
]
tags = ["parties", "members", "k1", "members-equity", "in-kind", "rounding"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "largest-remainder"
cash_accounts = ["1000"]
financing_accounts = ["2100"]
[[setup.accounts]]
code = "1000"
name = "Checking"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "2100"
name = "Due to Members"
type = "liability"
[[setup.accounts]]
code = "3000"
name = "Capital — Tobin Harlow"
type = "equity"
[[setup.accounts]]
code = "3001"
name = "Capital — Morgan Ellis"
type = "equity"
[[setup.accounts]]
code = "6050"
name = "Domain & Hosting"
type = "expense"
[[setup.parties]]
name = "Tobin Harlow"
roles = ["member"]
[[setup.parties]]
name = "Morgan Ellis"
roles = ["member"]
[[setup.members]]
name = "Tobin Harlow"
share = "0.5"
capital_account = "3000"
[[setup.members]]
name = "Morgan Ellis"
share = "0.5"
capital_account = "3001"
# 1. A joint contribution of cash and property (the K-1 worksheet's
# SCENARIO 3): 500.00 each, of it 300.00 cash and 200.00 in kind.
[[events]]
date = "2026-02-01"
description = "Joint contribution, cash and equipment"
parties = [{ party = "Morgan Ellis" }, { party = "Tobin Harlow" }]
lines = [
{ account = "1000", side = "debit", amount = "600.00" },
{ account = "1500", side = "debit", amount = "400.00" },
{ account = "3000", side = "credit", amount = "500.00" },
{ account = "3001", side = "credit", amount = "500.00" },
]
# 2. One cent of property shared by two equal parts: the cent goes to the
# member listed first in the company's members (Tobin), whatever the
# order the entry names them in.
[[events]]
date = "2026-02-02"
description = "A cent of property"
parties = [{ party = "Morgan Ellis" }, { party = "Tobin Harlow" }]
lines = [
{ account = "1000", side = "debit", amount = "0.99" },
{ account = "1500", side = "debit", amount = "0.01" },
{ account = "3000", side = "credit", amount = "0.50" },
{ account = "3001", side = "credit", amount = "0.50" },
]
# 3. An expense Morgan paid, booked straight to capital: cash.
[[events]]
date = "2026-02-03"
description = "Hosting Morgan paid"
parties = [{ party = "Morgan Ellis" }]
lines = [
{ account = "6050", side = "debit", amount = "50.00" },
{ account = "3001", side = "credit", amount = "50.00" },
]
# 4. What the company owed Tobin, converted to capital: cash.
[[events]]
date = "2026-02-04"
description = "Advance converted"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "2100", side = "debit", amount = "70.00" },
{ account = "3000", side = "credit", amount = "70.00" },
]
[[expect]]
query = "party_part"
entry = 1
party = "Tobin Harlow"
values = { resolved = "-500.00", direction = "received", cash = "-300.00", in_kind = "-200.00" }
[[expect]]
query = "party_part"
entry = 2
party = "Tobin Harlow"
values = { resolved = "-0.50", direction = "received", cash = "-0.49", in_kind = "-0.01" }
[[expect]]
query = "party_part"
entry = 2
party = "Morgan Ellis"
values = { resolved = "-0.50", direction = "received", cash = "-0.50", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 3
party = "Morgan Ellis"
values = { resolved = "-50.00", direction = "received", cash = "-50.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 4
party = "Tobin Harlow"
values = { resolved = "-70.00", direction = "received", cash = "-70.00", in_kind = "0.00" }
# Tobin: cash 300.00 + 0.49 + 70.00; in kind 200.00 + 0.01.
[[expect]]
query = "party_totals"
party = "Tobin Harlow"
basis = "cash"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "370.49" }
[[expect]]
query = "party_totals"
party = "Tobin Harlow"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "570.50" }
# Morgan: cash 300.00 + 0.50 + 50.00; in kind 200.00.
[[expect]]
query = "party_totals"
party = "Morgan Ellis"
basis = "cash"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "350.50" }
[[expect]]
query = "party_totals"
party = "Morgan Ellis"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "550.50" }
[[expect]]
query = "members_equity"
from = "2026-01-01"
to = "2026-12-31"
values = { "Tobin Harlow.contributions" = "570.50", "Tobin Harlow.distributions" = "0.00" }
[[expect]]
query = "members_equity"
from = "2026-01-01"
to = "2026-12-31"
values = { "Morgan Ellis.contributions" = "550.50", "Morgan Ellis.distributions" = "0.00" }
[[expect]]
query = "k1"
from = "2026-01-01"
to = "2026-12-31"
values = { "Tobin Harlow.contributions_cash" = "370.49", "Tobin Harlow.contributions_property" = "200.01" }
[[expect]]
query = "k1"
from = "2026-01-01"
to = "2026-12-31"
values = { "Morgan Ellis.contributions_cash" = "350.50", "Morgan Ellis.contributions_property" = "200.00" }
@@ -0,0 +1,240 @@
# P3 defect 24 and wanderbooks rules.md B-35 item 6: a credit to a
# liability the company owes a party itself never counts as paying that
# party. Regression test: ledger-core tests/spec_party_totals.rs
# defect24_a_credit_to_a_partys_own_liability_never_pays_it. The shape:
# bookspec/README.md.
id = "p3-party-own-liability-never-pays"
title = "A credit to what the company owes a party itself never pays it"
rule = """
A party may be named the creditor of the liabilities the company owes it
itself: a card's issuer, a loan's lender, each member for what the
members advanced. For an entry naming it, a credit to one is a promise,
not a payment: a fee on the issuer's own card, equipment bought on the
seller's own note, a distribution credited to what the members are owed.
It counts when it is paid. Property a member contributes subject to a
loan counts at its value net of the loan, in kind.
"""
status = "AUTHORITY"
sources = [
"Helvering v. Price, 309 U.S. 409, 412-413 (1940): a promise to pay, even a secured one, is not payment (wanderbooks docs/spec/sources/helvering-v-price-1940.md)",
"Treas. Reg. §1.704-1(b)(2)(iv)(b)(2): property contributed, net of liabilities the partnership takes it subject to (docs/spec/sources/irs-capital-accounts.md)",
"DECISION (owner, 2026-10-20): a liability credit never counts as paying that liability's own creditor (rules.md B-35)",
]
tags = ["parties", "creditors", "cards", "notes", "distributions", "members"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-even"
cash_accounts = ["1000"]
financing_accounts = ["2100", "2500"]
[[setup.accounts]]
code = "1000"
name = "Checking"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "2050"
name = "Business Card"
type = "liability"
[[setup.accounts]]
code = "2100"
name = "Due to Members"
type = "liability"
[[setup.accounts]]
code = "2500"
name = "Note Payable"
type = "liability"
[[setup.accounts]]
code = "3000"
name = "Capital — Tobin Harlow"
type = "equity"
[[setup.accounts]]
code = "3001"
name = "Capital — Morgan Ellis"
type = "equity"
[[setup.accounts]]
code = "6400"
name = "Bank Fees"
type = "expense"
[[setup.parties]]
name = "Harbor Bank"
roles = ["financial_institution"]
creditor_of = ["2050"]
[[setup.parties]]
name = "Lakeside Supply"
roles = []
creditor_of = ["2500"]
[[setup.parties]]
name = "Tobin Harlow"
roles = ["member"]
creditor_of = ["2100"]
[[setup.parties]]
name = "Morgan Ellis"
roles = ["member"]
creditor_of = ["2100"]
[[setup.members]]
name = "Tobin Harlow"
share = "0.5"
capital_account = "3000"
[[setup.members]]
name = "Morgan Ellis"
share = "0.5"
capital_account = "3001"
# 1. The issuer's fee on its own card: neither.
[[events]]
date = "2026-05-01"
description = "Card fee"
parties = [{ party = "Harbor Bank" }]
lines = [
{ account = "6400", side = "debit", amount = "25.00" },
{ account = "2050", side = "credit", amount = "25.00" },
]
# 2. The card paid off: paid to the issuer.
[[events]]
date = "2026-05-20"
description = "Card payment"
parties = [{ party = "Harbor Bank" }]
lines = [
{ account = "2050", side = "debit", amount = "125.00" },
{ account = "1000", side = "credit", amount = "125.00" },
]
# 3. A distribution to Tobin credited to what the members are owed:
# still owed, counts as nothing.
[[events]]
date = "2026-06-30"
description = "Distribution declared"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "3000", side = "debit", amount = "200.00" },
{ account = "2100", side = "credit", amount = "200.00" },
]
# 4. It is paid: paid, money.
[[events]]
date = "2026-07-15"
description = "Distribution paid"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "2100", side = "debit", amount = "200.00" },
{ account = "1000", side = "credit", amount = "200.00" },
]
# 5. Equipment on the seller's own note: neither.
[[events]]
date = "2026-08-01"
description = "Equipment on a note"
parties = [{ party = "Lakeside Supply" }]
lines = [
{ account = "1500", side = "debit", amount = "900.00" },
{ account = "2500", side = "credit", amount = "900.00" },
]
# 6. A payment on the note: paid.
[[events]]
date = "2026-09-01"
description = "Note payment"
parties = [{ party = "Lakeside Supply" }]
lines = [
{ account = "2500", side = "debit", amount = "300.00" },
{ account = "1000", side = "credit", amount = "300.00" },
]
# 7. Equipment worth 1,000.00 Morgan contributes subject to 200.00 owed
# on the note: 800.00 received, in kind (before P3: "paid 200.00").
[[events]]
date = "2026-09-15"
description = "Equipment contributed with its loan"
parties = [{ party = "Morgan Ellis" }]
lines = [
{ account = "1500", side = "debit", amount = "1000.00" },
{ account = "2500", side = "credit", amount = "200.00" },
{ account = "3001", side = "credit", amount = "800.00" },
]
[[expect]]
query = "party_part"
entry = 1
party = "Harbor Bank"
values = { resolved = "-25.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
# Before naming the issuer the card's creditor: 150.00.
[[expect]]
query = "party_totals"
party = "Harbor Bank"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "125.00", received = "0.00" }
[[expect]]
query = "party_part"
entry = 3
party = "Tobin Harlow"
values = { resolved = "200.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
[[expect]]
query = "party_totals"
party = "Tobin Harlow"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "200.00", received = "0.00" }
[[expect]]
query = "party_part"
entry = 5
party = "Lakeside Supply"
values = { resolved = "-900.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
[[expect]]
query = "party_totals"
party = "Lakeside Supply"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "300.00", received = "0.00" }
[[expect]]
query = "party_part"
entry = 7
party = "Morgan Ellis"
values = { resolved = "-800.00", direction = "received", cash = "0.00", in_kind = "-800.00" }
[[expect]]
query = "party_totals"
party = "Morgan Ellis"
basis = "cash"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "0.00" }
[[expect]]
query = "party_totals"
party = "Morgan Ellis"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "800.00" }
@@ -0,0 +1,99 @@
# P3 defect 14, the second bug found in design (wanderbooks P3 brief
# §1.4): a member pays the card from their own funds; reversing it read
# as a second payment. Regression test: ledger-core
# tests/spec_party_totals.rs
# defect14_a_reversed_member_card_payment_nets_to_zero. The shape:
# bookspec/README.md (`after = N` asks a query after event N).
id = "p3-party-reversed-card-payment"
title = "A reversed payment of one liability by another nets to zero"
rule = """
A reversal's part for each party is its original's negated, never read
from the reversal's own lines. A member paying the company's card from
their own funds (Dr card / Cr due to members), tagged with the card's
issuer, is paid to the issuer; its reversal takes that back, so the pair
nets to zero; reversing the reversal pays it again.
"""
status = "AUTHORITY"
sources = [
"Pacioli, Summa (1494), Geijsbeek tr.: a mistake is corrected by the opposite entry (wanderbooks docs/spec/sources/pacioli-1494.md, rules.md B-9)",
]
tags = ["parties", "reversals", "liabilities"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-even"
cash_accounts = ["1000"]
financing_accounts = ["2100"]
[[setup.accounts]]
code = "1000"
name = "Checking"
type = "asset"
[[setup.accounts]]
code = "2050"
name = "Business Card"
type = "liability"
[[setup.accounts]]
code = "2100"
name = "Due to Members"
type = "liability"
[[setup.parties]]
name = "Harbor Bank"
roles = ["financial_institution"]
[[events]]
date = "2026-06-01"
description = "A member pays the card from their own funds"
parties = [{ party = "Harbor Bank" }]
lines = [
{ account = "2050", side = "debit", amount = "100.00" },
{ account = "2100", side = "credit", amount = "100.00" },
]
[[events]]
date = "2026-06-02"
description = "Reversed"
reverses = 1
[[events]]
date = "2026-06-03"
description = "The reversal reversed"
reverses = 2
[[expect]]
query = "party_part"
entry = 1
party = "Harbor Bank"
values = { resolved = "100.00", direction = "paid", cash = "100.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 2
party = "Harbor Bank"
values = { resolved = "-100.00", direction = "received", cash = "-100.00", in_kind = "0.00" }
# After the reversal: nothing paid (before P3: 200.00, the reversal read
# as a second payment).
[[expect]]
query = "party_totals"
after = 2
party = "Harbor Bank"
basis = "cash"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "0.00", received = "0.00" }
[[expect]]
query = "party_totals"
after = 3
party = "Harbor Bank"
basis = "cash"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "100.00", received = "0.00" }
@@ -0,0 +1,289 @@
# P3 defect 14 (wanderbooks plan/served.md P3; audit findings F36, F37):
# a party's part of an entry is signed as a line on the party's own
# account, with its direction and what of it was money or property; a
# reversal is the exact opposite of what it reverses; party totals take a
# basis. Regression test: ledger-core tests/spec_party_totals.rs
# defect14_shares_take_the_partys_side_and_reversals_flip. The shape:
# bookspec/README.md.
id = "p3-party-signs-and-reversals"
title = "A party's part of an entry is signed as its own account would show it, and a reversal is the exact opposite"
rule = """
A party's part of an entry is debit-positive, as a line on the party's own
account would be: positive when the company paid it or gave it value,
negative when the company received from it. Each part has a direction
(paid, received, neither) and a cash and an in-kind amount. An entry
naming only members that moves equity counts what moved their capital,
the property in it in kind. A reversal's part is exactly its original's
negated. A bill or invoice moves nothing with the party yet (neither).
Party totals on basis cash count the cash parts, on basis all the cash
and in-kind parts, each on its root original's side.
"""
status = "CONVENTION"
sources = [
"Pacioli, Summa (1494), Geijsbeek tr., ch. 36: debit is what owes, credit what is owed (wanderbooks docs/spec/sources/pacioli-1494.md)",
"Treas. Reg. §1.704-1(b)(2)(iv)(b)(1)-(2), (4)-(5): a partner's capital account rises by money and property contributed, falls by money and property distributed (docs/spec/sources/irs-capital-accounts.md)",
"Helvering v. Price, 309 U.S. 409, 412-413 (1940): a promise to pay is not payment (docs/spec/sources/helvering-v-price-1940.md)",
"DECISION (owner, 2026-10-20): a member's entry counts what moved their capital (wanderbooks rules.md B-35)",
]
tags = ["parties", "signs", "reversals", "members", "in-kind", "basis"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-even"
cash_accounts = ["1000"]
financing_accounts = ["2100"]
[[setup.accounts]]
code = "1000"
name = "Checking"
type = "asset"
[[setup.accounts]]
code = "1200"
name = "Accounts Receivable"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "2000"
name = "Accounts Payable"
type = "liability"
[[setup.accounts]]
code = "2100"
name = "Due to Members"
type = "liability"
[[setup.accounts]]
code = "3000"
name = "Capital — Tobin Harlow"
type = "equity"
[[setup.accounts]]
code = "3001"
name = "Capital — Morgan Ellis"
type = "equity"
[[setup.accounts]]
code = "3999"
name = "Retained Earnings"
type = "equity"
[[setup.accounts]]
code = "4000"
name = "Revenue"
type = "revenue"
[[setup.accounts]]
code = "6000"
name = "Organizational Costs"
type = "expense"
[[setup.parties]]
name = "Tobin Harlow"
roles = ["member"]
[[setup.parties]]
name = "Morgan Ellis"
roles = ["member"]
[[setup.parties]]
name = "Northwind Filings"
roles = ["vendor"]
[[setup.parties]]
name = "Riley Chen"
roles = ["customer"]
[[setup.members]]
name = "Tobin Harlow"
share = "0.5"
capital_account = "3000"
[[setup.members]]
name = "Morgan Ellis"
share = "0.5"
capital_account = "3001"
# 1. Tobin pays the filing fee for the company (through the members'
# financing account), tagged with the vendor: paid to the vendor, money.
[[events]]
date = "2026-10-04"
description = "Filing fee, paid by Tobin"
parties = [{ party = "Northwind Filings" }]
lines = [
{ account = "6000", side = "debit", amount = "64.00" },
{ account = "2100", side = "credit", amount = "64.00" },
]
# 2. Tobin's cash contribution: received, money.
[[events]]
date = "2026-10-05"
description = "Tobin's contribution"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "1000", side = "debit", amount = "400.00" },
{ account = "3000", side = "credit", amount = "400.00" },
]
# 3. Reimbursing Tobin for the fee: paid, money (cash paying down what
# the company owed him).
[[events]]
date = "2026-10-08"
description = "Reimbursement"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "2100", side = "debit", amount = "64.00" },
{ account = "1000", side = "credit", amount = "64.00" },
]
# 4. A laptop Tobin contributes: received, in kind.
[[events]]
date = "2026-10-12"
description = "Laptop contributed"
parties = [{ party = "Tobin Harlow" }]
lines = [
{ account = "1500", side = "debit", amount = "1480.00" },
{ account = "3000", side = "credit", amount = "1480.00" },
]
# 5. Its reversal: the exact opposite, paid, in kind.
[[events]]
date = "2026-10-13"
description = "Laptop contribution reversed"
reverses = 4
# 6. The laptop again, half each, by amount.
[[events]]
date = "2026-10-14"
description = "Laptop contributed jointly"
parties = [{ party = "Tobin Harlow", amount = "740.00" }, { party = "Morgan Ellis", amount = "740.00" }]
lines = [
{ account = "1500", side = "debit", amount = "1480.00" },
{ account = "3000", side = "credit", amount = "740.00" },
{ account = "3001", side = "credit", amount = "740.00" },
]
# 7. A bill from the vendor (credit to payables, its own account): neither.
[[events]]
date = "2026-10-20"
description = "Bill"
parties = [{ party = "Northwind Filings" }]
lines = [
{ account = "6000", side = "debit", amount = "80.00" },
{ account = "2000", side = "credit", amount = "80.00" },
]
# 8. The bill reversed: the exact opposite, still neither.
[[events]]
date = "2026-10-21"
description = "Bill reversed"
reverses = 7
# 9. An invoice to the customer (a debit to receivables): neither.
[[events]]
date = "2026-10-20"
description = "Invoice"
parties = [{ party = "Riley Chen" }]
lines = [
{ account = "1200", side = "debit", amount = "120.00" },
{ account = "4000", side = "credit", amount = "120.00" },
]
[[expect]]
query = "party_part"
entry = 1
party = "Northwind Filings"
values = { resolved = "64.00", direction = "paid", cash = "64.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 2
party = "Tobin Harlow"
values = { resolved = "-400.00", direction = "received", cash = "-400.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 3
party = "Tobin Harlow"
values = { resolved = "64.00", direction = "paid", cash = "64.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 4
party = "Tobin Harlow"
values = { resolved = "-1480.00", direction = "received", cash = "0.00", in_kind = "-1480.00" }
[[expect]]
query = "party_part"
entry = 5
party = "Tobin Harlow"
values = { resolved = "1480.00", direction = "paid", cash = "0.00", in_kind = "1480.00" }
[[expect]]
query = "party_part"
entry = 6
party = "Morgan Ellis"
values = { resolved = "-740.00", direction = "received", cash = "0.00", in_kind = "-740.00" }
[[expect]]
query = "party_part"
entry = 7
party = "Northwind Filings"
values = { resolved = "-80.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 8
party = "Northwind Filings"
values = { resolved = "80.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
[[expect]]
query = "party_part"
entry = 9
party = "Riley Chen"
values = { resolved = "120.00", direction = "neither", cash = "0.00", in_kind = "0.00" }
# Tobin: cash in 400.00 (event 2), paid back 64.00 (event 3); in kind
# 1,480.00 − 1,480.00 (events 4 and 5 net) + 740.00 (event 6).
[[expect]]
query = "party_totals"
party = "Tobin Harlow"
basis = "cash"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "64.00", received = "400.00" }
[[expect]]
query = "party_totals"
party = "Tobin Harlow"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "64.00", received = "1140.00" }
# The vendor: the fee a member paid for the company; the bill and its
# reversal count nothing.
[[expect]]
query = "party_totals"
party = "Northwind Filings"
basis = "all"
from = "2026-01-01"
to = "2026-12-31"
values = { paid = "64.00", received = "0.00" }
# Basis all over Tobin's equity entries is the statement of members'
# equity: contributions 400.00 + 740.00 (events 4 and 5 cancel).
[[expect]]
query = "members_equity"
from = "2026-01-01"
to = "2026-12-31"
values = { "Tobin Harlow.contributions" = "1140.00", "Tobin Harlow.distributions" = "0.00" }
+86
View File
@@ -0,0 +1,86 @@
# P3 defect 11 (audit finding F28): the directory showed a member's TIN as
# missing because it read W-9 facts only. Regression tests: ledger-core
# tests/spec_party_totals.rs
# defect11_a_partys_tin_last4_is_its_tin_facts_else_its_w9s; ledger-mcp
# tests/spec_vault.rs defect11_the_directory_shows_a_members_tin_last4.
# The shape: bookspec/README.md.
id = "p3-party-tin-last4"
title = "A party's TIN last four is its TIN facts', else its W-9's"
rule = """
The books keep a taxpayer identification number truncated to its last
four digits. A party's last four is its TIN facts' (a member's SSN for
the K-1), else its W-9 facts'; the two never disagree. A TIN purged from
the vault keeps its last four in the books. A party with neither has
none.
"""
status = "AUTHORITY"
sources = [
"Treas. Reg. §301.6109-4(a): a truncated TIN shows the last four digits (wanderbooks docs/spec/sources/irs-truncated-tin.md)",
"DECISION (owner, 2026-10-15): a party's TIN facts and W-9 facts never disagree (wanderbooks ledger-core parties INVARIANT 2a)",
]
tags = ["parties", "tin", "w9", "k1"]
# Nothing is posted: the facts are the directory's.
events = []
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-even"
[[setup.accounts]]
code = "1000"
name = "Checking"
type = "asset"
[[setup.parties]]
name = "Tobin Harlow"
roles = ["member"]
tin_last4 = "4321"
[[setup.parties]]
name = "Riley Chen"
roles = ["contractor"]
w9_tin_last4 = "8765"
[[setup.parties]]
name = "Morgan Ellis"
roles = ["member", "contractor"]
tin_last4 = "1111"
w9_tin_last4 = "1111"
[[setup.parties]]
name = "Lakeside Supply"
roles = []
[[setup.parties]]
name = "Avery Quinn"
roles = ["member"]
tin_last4 = "2468"
tin_purged = true
[[expect]]
query = "party_tin_last4"
party = "Tobin Harlow"
values = { tin_last4 = "4321" }
[[expect]]
query = "party_tin_last4"
party = "Riley Chen"
values = { tin_last4 = "8765" }
[[expect]]
query = "party_tin_last4"
party = "Morgan Ellis"
values = { tin_last4 = "1111" }
[[expect]]
query = "party_tin_last4"
party = "Lakeside Supply"
values = { tin_last4 = "" }
[[expect]]
query = "party_tin_last4"
party = "Avery Quinn"
values = { tin_last4 = "2468" }