P3: odd cents split the same running way everywhere (defect 17, D-38)
check / check (push) Canceled after 0s

Members' shares of earnings are split cumulatively by largest remainder in
the closes, the members' equity statement, the K-1 worksheet and the
viewer, so a member's capital on a given day never moves by a cent when its
month is later closed. Old closes replay as they were; the first P3 close
carries any true-up. Feature members_cumulative. Kani and Lean proofs of
the bounded drift; bookspec examples.

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-20 21:35:00 -06:00
1 parent 2390dc6553
commit a7f3cc09a9
44 files changed
+6636 -195

No files matched your search

+136 -30
View File
@@ -206,34 +206,109 @@ closed period).
## B-13 Partners share income by the partnership agreement; capital accounts carry it
**Status:** AUTHORITY (shares); DECISION (cent rounding)
**Status:** AUTHORITY (shares; capital accounts; a count ends where the
members or shares change: §706(d)(1), Treas. Reg. §1.706-4(a)); DECISION
(cent rounding, the owner 2026-10-13); DECISION (counted from the company's
first close, D-10, 2026-10-16); DECISION (the statement splits unclosed
earnings the same running way, D-38, 2026-10-20)
- 26 U.S.C. §704(a) (`sources/irs-partnerships.md`): "A partner's
distributive share of income, gain, loss, deduction, or credit shall,
except as otherwise provided in this chapter, be determined by the
partnership agreement."
- Treas. Reg. §1.704-1(b)(2)(iv)(b) (`sources/irs-partnerships.md`): each
partner's capital account "is increased by … (3) allocations to him of
partnership income and gain" and "is decreased by … (7) allocations of
partnership loss and deduction", beside the money and property
contributed and distributed. A capital account is one running balance of
contributions, allocations and distributions: the closes are the
allocations.
- Form 1065 Schedule M-2: "Show what caused changes during the tax year in
the partners' tax-basis capital accounts."
the partners' tax-basis capital accounts." Schedule K-1 Item L reports
each partner's capital account "using the tax-basis method"; that
analysis "is based on the partnership's books and records" (the Partner's
Instructions' Basis Limitations section, `sources/irs-partnerships.md`;
not Item L, which an earlier version of this rule spliced in). The K-1
worksheet is the book capital analysis, which the CPA converts for
Item L.
- **No authority** says how to round a share to the cent. Largest
remainder, ties to the earlier member: DECISION (the owner, 2026-10-13).
Closes made before then replay with the last member absorbing it.
- Rounding never piles up: a run of members closes (same members and
shares, back to back) splits cumulatively, each close giving a member
their allocation of the run's total so far less their allocation before
it, so each member's total from the run is within a cent of their exact
share (follows from the running capital account below; found
2026-10-13: closing each month on its own gave every tied cent to the
earlier member). Journaled as `"rounding": "cumulative"`; closes
journaled `"largest_remainder"` replay one at a time.
- A capital account is one running balance: Form 1065 Schedule K-1
instructions, Item L: "The partnership must report your beginning
capital account and ending capital account for the year", "based on the
partnership's books and records." So a statement of members' equity
splits undistributed earnings cumulatively, as of each date (beginning
as of the day before the period, ending as of its last day), never one
period at a time: a member's ending on one statement is their beginning
on the next, to the cent, and a member's period income is the
roll-forward's remainder (their share within a rounding cent).
remainder, ties to the member listed first: DECISION (the owner,
2026-10-13). Closes made before then replay with the last member
absorbing it.
- **Members closes split cumulatively, counted from the company's first
close** (P3 defect 17; D-10). A *count* is the members closes with one
set of (capital account, share) pairs, from the first such close since
the last members close with another set: closes to retained earnings or
to one account are skipped (they allocate nothing to the members), and
neither the members' order nor their distribution accounts matter. Each
close gives member *i* allocate(C + net)*ᵢ* − given*ᵢ*: their split of
everything the count has closed (C before it, plus its own net), to the
base currency's minor unit (cents, whole yen, thousandths of a dinar;
B-3; for a code ISO 4217 gives none, such as gold, the finest a line
carries, `kernel::MAX_LINE_SCALE` places, so every amount is still whole
units), less what the count's earlier closes gave them under whatever
rule they were made. A tied odd unit goes to the member the count's
first close listed first, whatever order later closes list the members
in, so a reorder of the members moves no cent; the statement below
breaks ties the same way, on a day before a count's first close in the
order of the count the next members close begins. Therefore each close hands out
exactly its net; after every close that posts, each member's total from
the count is one split of the count's total, under one minor unit from
their exact share; and rounding by closes made under earlier rules is
trued up by the first close that posts (D-10: from inception; listed in
the close's `members`). The true-up is under a unit per member for each
break in an earlier run and each per-close close; a last-absorbs close
rounded each member but the last to within half a unit, and the last
absorbed up to half a unit for each of the others (a unit with three
members, more with four or more).
- A change of members or shares starts a new count (26 U.S.C.
§706(d)(1): a year's distributive shares are determined by a method
"which takes into account the varying interests of the partners in the
partnership during such taxable year"; Treas. Reg. §1.706-4(a)(3)(vii):
the partnership "shall treat each segment as though the segment were a
separate distributive share period"). Income closed under
the old shares is never split again under the new ones. So the bound
holds per count: across k changes a member's total can be up to one
unit per count from the sum of their exact shares (the D-10 lifetime
bound holds while members and shares are unchanged).
- A true-up rides only on a close that posts an entry (income to close,
or a distribution to sweep): a close that posts nothing credits no one,
and the true-up waits for the next close that posts (close INVARIANT
5: never post a closing entry when there is nothing to close).
- The bound's precondition: every amount is a whole number of minor
units (B-3: every posted line is), and every product |total| × share
is exact. A product Decimal would round (a share of many decimal places
times a large total) is refused, never split
(`periods::allocate_cumulative` INVARIANT 4). Replaying a journal from
before B-3, a sub-unit fraction can make the bound two units.
- A year's income per member is the difference of two running totals,
each under a unit from exact, so under two units from share × the
year's income; the return is in whole dollars ("Rounding on the
return", `sources/irs-partnerships.md`).
- A period closes at the shares in force at the close: a share change
inside a period isn't split at its date (§706(d) and §1.706-4 would);
close the period at the change.
- Journaled `"rounding": "cumulative_since"` with `"since_seq": N`, the
close the count starts at, under the journal feature
`members_cumulative` (B-27); replay derives N again and refuses a close
journaled with another. Closes journaled `"cumulative"` (the run rule of
2026-10-13 to P3: a back-to-back run with the same members in the same
order, restarted by any other close, so a tied cent could go to the
same member at every restart), `"largest_remainder"` (each close on its
own) and none (the last member absorbs) replay under their own rules,
never changed (B-8).
- A capital account is one running balance (§1.704-1(b)(2)(iv)(b)). So the
statement of members' equity, the K-1 worksheet and the viewer split
undistributed earnings U as of each date the way the count's next close
would split them: allocate(C(d) + U(d)) − allocate(C(d)), C(d) being what
the count's closes dated on or before d closed (D-38; P3 review R-1). A
member's capital on a date never moves when a period ending on or before
it is later closed; a true-up of rounding by closes made under an earlier
rule shows only once a close posts it, dated at that close. A
statement's beginning is as of the day before its period, its ending as
of its last day: a member's ending on one statement is their beginning on
the next, to the unit, and a member's period income is the roll-forward's
remainder (their share within a rounding unit at each end).
- A correction undoes what it corrects (B-9): an entry and its reversal
both in a statement's span are neither contributions nor
distributions (`reports::cancelled_in_span`; the K-1 worksheet reads
@@ -247,15 +322,39 @@ closed period).
members credited in one entry in proportion to their credits
(`k1` INVARIANTS 3, 4, 6).
**Enforced:** `CloseTo::Members`, `periods::allocate`,
`kernel::apportion`, `members_equity`. **Checked:** Kani
`apportion_is_exact`, `apportion_is_fair`; Lean `runPart_telescopes`,
`closePart_total`; properties `prop_split_*`,
`each_members_capital_chains_across_statements`,
`each_member_stays_within_a_cent_of_their_share`;
`a_run_of_closes_never_piles_up_rounding`,
`members_closes_replay_under_the_rule_they_were_journaled_with`;
`closes_journaled_under_the_old_rule_replay_with_it`.
**Enforced:** `CloseTo::Members`, `CloseTo::MembersCumulative`,
`Ledger::members_regime`, `Regime::allocate`,
`periods::allocate_cumulative`, `kernel::apportion_cumulative`,
`periods::allocate`, `kernel::apportion`, `members_equity`,
`Store::close_period_to` (the feature declaration), the store's
`close_to_from_journal`. **Checked:** Kani `apportion_is_exact`,
`apportion_is_fair`, `apportion_cumulative_is_exact`,
`cumulative_close_never_drifts_a_unit_at_halves`, `_at_tenths`,
`_at_near_thirds`,
`cumulative_closing_entry_balances`; Lean `runPart_telescopes`,
`closePart_total`, `trueUp_total`, `trueUp_running`,
`closePart_eq_trueUp`, `cumulative_drift`, `statement_after_close`,
`statement_unmoved_by_close`, `Apportion.rem_pos_of_rank_lt`,
`apportion_drift`, `allocW_sum`, `allocW_drift`,
`allocW_cumulative_drift`, `allocW_cumulative_total`; properties
`prop_split_*`, `each_members_capital_chains_across_statements`,
`each_member_stays_within_a_cent_of_their_share`,
`members_capital_never_drifts_a_cent_from_their_share`,
`each_members_capital_chains_and_holds_through_closes`,
`period_ends_rise_with_close_order`, `apportion_cumulative_agrees`,
`allocate_cumulative_agrees_with_the_integer_model`;
`the_audit_odd_cent_never_piles_up_across_closes` and the rest of
`ledger-core` `tests/odd_cent.rs`; `a_run_of_closes_never_piles_up_rounding`,
`a_different_close_ends_a_legacy_run`,
`a_different_close_no_longer_restarts_the_count`,
`members_closes_replay_under_the_rule_they_were_journaled_with`,
`ledger-store` `tests/member_closes.rs` and the old-books fixture
`x_member_closes`; `closes_journaled_under_the_old_rule_replay_with_it`;
`ledger-mcp` `close_period_shows_each_members_running_split`,
`old_books_name_each_closes_rule_and_true_up_at_the_next_close`;
`ledger-gui` `a_members_page_shows_the_same_capital_before_and_after_a_close`,
`a_yen_members_page_splits_in_whole_yen`; the bookspec examples
`members-close.*`.
## B-14 Statements: P&L for a period; cash flow by the indirect method
@@ -716,6 +815,13 @@ lowers the format in force. Opening the books checks every complete line
before it changes anything: a cut-off last line is set aside only when the
lines before it pass, so an older version never alters newer books.
A feature (`ledger_store::format::KNOWN_FEATURES`) is a field or value on
an event type an older version knows but would misread; the writer declares
it with the format in force (at least 2) just before the first line that
needs it, so books that never use it stay readable by versions before it:
`members_cumulative` (P3, B-13: a members close counted from its count's
first close, `"rounding": "cumulative_since"`).
**Enforced:** `ledger_store::format` (`JournalFormat::admit`, `declared`,
`gate`, `settle`, `declaration`), `journal::ENVELOPE_KEYS`,
`JournalLine::parse`, `journal::read_journal_and_format`,