The engine only had life-of-ledger P&L and balance sheet totals, so every
export labeled with a date range or as-of date (PDF, XLSX, CPA package)
printed all-time numbers under that label. Core now has:
- profit_and_loss_for_period(start, end, class?) and
balance_sheet_as_of(as_of), each with a line per account
(StatementLine: code, name, normal-side amount) and exact totals.
- Ledger::closing_entry_ids(). Period statements exclude closing entries.
A close (Dr revenue / Cr expense / net to Retained Earnings, dated at
period end) moves earnings; it doesn't earn or spend. Counting it made a
closed period's P&L read as break-even, and made the cash flow show zero
net income plus a fake "owner contribution" to Retained Earnings. The
as-of balance sheet keeps closing entries: after a close the earnings
belong in Retained Earnings, not current earnings.
Tests: tests/statements.rs, a two-month fixture with every expected number
computed by hand (Jan NI 1,700; Feb 880; balance sheets on four dates; a
closed January still reporting 1,700 and a cash flow with one financing
line). Mutation-checked: dropping the closing exclusion fails it (0 vs
1,700). Properties: period P&Ls partition a year at any split, and a
range's net income equals the change in current earnings across it, with
A = L + E on both dates.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu