docs: the assumed list, checked against the standards; mutation score
check / check (push) Canceled after 0s

Each formerly ASSUMED behavior is now CONFIRMED, CONVENTION, DESIGN, or
CHANGE (pending), with its source (Reg. S-X, ASC 230 via Deloitte DART,
IRS K-1 instructions, OpenStax). Two need engine work: members' equity
should allocate cumulatively so each member's beginning equals the prior
ending (#7), and the cash flow should show financing gross and classify
investing by account role (#8). Two questions for the CPA are listed.
The test doc comments that relied on them now cite the verdicts.

Core mutation run: 1,011 caught + 13 timeouts of 1,024 viable, 0 missed.
No benchmark budget, by decision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-13 18:18:30 -06:00
1 parent 0dcf865ff8
commit 08d1a9c230
6 files changed
+40 -35

No files matched your search

+1 -1
View File
@@ -458,7 +458,7 @@ fn statement_lines(
/// SCENARIOS:
/// 1. IF a month was closed: SHOULD still report that month's earnings.
/// BECAUSE closing doesn't make a period break even (R-9).
/// 2. IF `start` is after `end`: SHOULD refuse. (ASSUMED)
/// 2. IF `start` is after `end`: SHOULD refuse. (DESIGN: no standard governs a reversed range; docs/testing.md #1)
/// ```
pub fn profit_and_loss_for_period(
ledger: &Ledger,
+1 -1
View File
@@ -538,7 +538,7 @@ fn create_invoice_refuses_due_before_date_books_unchanged() {
/// Closes January 2026 on `l`.
///
/// ASSUMED: closing a period with nothing in it still marks it closed
/// CONVENTION (docs/testing.md #4): closing a period with nothing in it still marks it closed
/// (close_period returns Ok(None)); the precondition is asserted.
fn close_january(l: &mut Ledger) {
let p = l
@@ -316,7 +316,7 @@ fn schedule_clamps_to_end_of_life() {
/// life ends 2026-03-15 so Mar holds 1..14 = 14/31 → 140.00. 17/31 + 14/31
/// = one full month, and the total is exactly 620.00.
///
/// ASSUMED: life ends on purchase_date + useful_life_months and the end day
/// CONVENTION (docs/testing.md #9): life ends on purchase_date + useful_life_months and the end day
/// itself is not held (matches the doc's "17/31 + 14/30" pairing for a
/// purchase on the 15th).
#[test]
@@ -343,7 +343,7 @@ fn partial_first_and_last_months_make_one_full_month_b15() {
/// Jan 17/31 → 170.00, Feb 310.00, Mar 310.00 (acc 790.00), Apr (30 days)
/// trues up to 930 − 790 = 140.00, not 14/30 × 310 = 144.67.
///
/// ASSUMED: same end-of-life convention as the test above.
/// CONVENTION (#9): same end-of-life convention as the test above.
#[test]
fn last_month_trues_up_unequal_month_lengths_b15() {
let a = asset("1030.00", "100.00", 3, date(2026, 1, 15));
@@ -867,7 +867,7 @@ fn run_payroll_posts_hand_worked_entry() {
/// 750.00, state 250.00, SS 620 + 248 = 868.00, Medicare 145 + 58 = 203.00,
/// other 200.00, net 3567.50 + 1697.00 = 5264.50.
///
/// ASSUMED: lines are aggregated per account ("zero totals are skipped"
/// CONFIRMED (docs/testing.md #10): lines are aggregated per account ("zero totals are skipped"
/// implies totals), not one line per employee.
#[test]
fn run_payroll_aggregates_employees() {
+1 -1
View File
@@ -1235,7 +1235,7 @@ fn a_loss_closes_as_a_debit_to_equity() {
}
/// Oracle: close INVARIANT 5: nothing to close posts nothing and returns
/// None. ASSUMED: the period is still marked closed (step 3 of the doc).
/// None. CONVENTION (docs/testing.md #4): the period is still marked closed (step 3 of the doc).
#[test]
fn a_close_with_nothing_to_close_posts_no_entry() {
let mut b = books();
+4 -4
View File
@@ -531,7 +531,7 @@ fn pnl_closed_month_still_reports_its_earnings() {
assert_eq!(year.net_income(), c(7000));
}
/// Oracle: P&L SCENARIO 2 (ASSUMED in the spec itself) — start after end
/// Oracle: P&L SCENARIO 2 (DESIGN, docs/testing.md #1) — start after end
/// refuses.
#[test]
fn pnl_period_start_after_end_refuses() {
@@ -1009,7 +1009,7 @@ fn me_refuses_bad_shares() {
/// earnings 100.01 -> A 50.01, B 50.00; period income 201.01 -> A 100.51,
/// B 100.50. Total ending 2251.02 = BS equity.
///
/// ASSUMED: the beginning (unclosed prior earnings) and the period's income
/// CHANGE PENDING (docs/testing.md #7): the beginning (unclosed prior earnings) and the period's income
/// are each split separately (INVARIANT 3 names them separately), not
/// cumulative-then-differenced.
#[test]
@@ -1407,7 +1407,7 @@ fn sorted_amounts(lines: &[ledger_core::CashFlowLine]) -> Vec<Decimal> {
/// 400; AR up 300 (-300), AP up 80 (+80); CFO 180; financing loan 300 +
/// contribution 100 = 400; net change 580 = cash 1000 -> 1580.
///
/// ASSUMED: one working-capital / financing line per account that changed.
/// CHANGE PENDING (docs/testing.md #8): one working-capital / financing line per account that changed.
#[test]
fn cf_hand_computed_with_designated_debt() {
let co = cf_example_books();
@@ -2418,7 +2418,7 @@ proptest! {
/// NI + depreciation + working capital; with or without a close and a
/// designated loan.
///
/// ASSUMED: with no registered fixed assets, depreciation and investing
/// CHANGE PENDING (docs/testing.md #8): with no registered fixed assets, depreciation and investing
/// are zero (receivables are current, so working capital).
#[test]
fn prop_cf_sections_sum_to_change_in_cash(gens in arb_books(), (a, _m, e) in three_days(), month in opt_month(), designate in any::<bool>()) {
+30 -25
View File
@@ -25,7 +25,7 @@ the store's journal safety; the other crates come next (gap list).
| Miri | undefined behavior in our use of dependencies (4) | the core's unit, bridge, invariant tests | `just miri` | ~2 min | on demand |
| Golden | `tests/golden/fixture_company.json` (5) | `invariants.rs` | `just check` | <1s | every change |
| Benchmarks | a baseline (6) | `benches/books.rs` | `just bench` | ~1 min | none (no budget, by decision) |
| Mutation | can the tests fail? | `ledger-core` | `just mutants` | ~12 min | weekly |
| Mutation | can the tests fail? | `ledger-core` (2026-10-13: 1,011 caught + 13 timeouts of 1,024 viable, 0 missed) | `just mutants` | ~3 h | weekly |
CI: `.github/workflows/check.yml` runs `just check` on every push;
`scheduled.yml` runs proofs, the oracle, fuzzing, and mutation weekly.
@@ -56,32 +56,37 @@ laptop:
| balance sheet | 47 µs | 1.04 ms |
| one month's P&L | 25 µs | 248 µs |
## Assumed, not confirmed (reject any)
## Formerly assumed: checked against the standards (2026-10-13)
Each was inferred, not decided by a human; the tests that rely on them
say so in their doc comments.
Stephen isn't an accountant and won't adjudicate these; each was checked
against published sources instead (rank: FASB ASC via the Deloitte DART
reproduction, SEC, IRS; then textbooks; software practice is evidence of
convention only). Verdicts: CONFIRMED (a source supports it), CONVENTION
(no standard governs; matches mainstream practice), DESIGN (not an
accounting question), CHANGE (a source says otherwise; work pending).
- ASSUMED: a P&L for a period whose start is after its end is refused.
- ASSUMED: a balance sheet omits accounts with a zero balance.
- ASSUMED: the lifetime `profit_and_loss` counts closing entries
(only period statements exclude them).
- ASSUMED: closing a period with nothing to close still marks it closed.
- ASSUMED: a sweep account (draws, distributions) is zeroed as of the
period end, like income.
- ASSUMED: reconciliation balances are debits minus credits (tested on
cash; liability accounts unspecified).
- ASSUMED: a members' equity statement allocates prior unclosed earnings
and the period's income separately; one statement's ending for a member
may differ by a cent from the next statement's beginning (only totals
are guaranteed to chain).
- ASSUMED: cash flow lists one working-capital or financing line per
account that changed; with no registered assets, investing is zero.
- ASSUMED: an asset's life ends on purchase date + life months, that day
not held.
- ASSUMED: a payroll entry has one line per account total, not per
employee.
- ASSUMED: a period with exactly the dates of an existing one nests in it
(is allowed).
| # | Behavior | Verdict | Source / note |
|---|---|---|---|
| 1 | A P&L whose start is after its end is refused | DESIGN | No standard governs a reversed range; refusing beats silently swapping a typo |
| 2 | A balance sheet omits zero-balance accounts | CONFIRMED | Reg. S-X 210.4-03(a): "No caption should be shown ... as to which the items and conditions are not present." A comparative statement must still show a zero beside a non-zero prior column |
| 3 | The lifetime `profit_and_loss` counts closing entries | CONFIRMED | Used as earnings not yet closed on the balance sheet; closed income is already in capital (OpenStax Principles of Financial Accounting 5.1). Its name misleads: rename to unclosed earnings (pending) |
| 4 | Closing a period with nothing to close still locks it | CONVENTION | A close is a lock (B-12); a dormant month must still lock and count for close-in-order |
| 5 | Draws and distributions are closed into capital at period end | CONFIRMED | OpenStax 5.1: dividends "are closed to the permanent account"; drawing accounts close to owner's capital. Monthly closes mean the year's K-1 Item L withdrawals sum across months |
| 6 | Reconciliation balances | CONFIRMED | Signed by the account's normal side (a card reads as owed), as statements show it; `reconciling_a_card_reads_its_normal_side_...` |
| 7 | A member's ending on one equity statement may differ by a cent from the next statement's beginning | CHANGE (pending) | A capital account is one running balance (Form 1065 K-1 instructions, Item L: beginning and ending capital "based on the partnership's books and records"). Allocate cumulatively so beginning equals the prior ending per member. CPA question below |
| 8 | Cash flow nets one line per account; investing comes only from registered assets | CHANGE (pending) | ASC 230-10-45-7: gross receipts and payments "more relevant" than net; 45-8 limits netting to quick-turnover items. Financing: contributions apart from distributions, borrowings apart from repayments. ASC 230-10-20/45-13: loans made and investments bought are investing, so classify by account role |
| 9 | An asset's life ends at purchase + life months, that day not held; day-count proration | CONVENTION | Exactly N months of service; day proration and the mid-month convention are both accepted book policies (ASC 360-10-35-4 not read: login) |
| 10 | A payroll entry has one line per account total | CONFIRMED | The per-employee detail the IRS requires ("Amounts and dates of all wage ... payments", Employment Tax Recordkeeping) is kept in the run; a summary entry is standard |
| 11 | A period with exactly the dates of an existing one is allowed | DESIGN | Nothing governs duplicate periods; harmless (the second close locks only). Refusing exact duplicates is an option |
Questions for Krista Baker (CPA):
1. Interim members' equity: is a per-member allocation of unclosed
earnings acceptable on interim statements, or should the books close
monthly so the capital accounts carry it?
2. How should 2100 Due to Shareholders, and expenses the owners paid
personally, appear on the cash flow statement: operating, financing,
or as a non-cash disclosure (ASC 230-10-50-3, not yet read)?
## Gap list: what isn't covered, and what would bring it in