Commit Graph
89 Commits
Author SHA1 Message Date
swaitsandClaude Opus 5.5 353bef1d5d feat: general ledger by account, trial balance as of, members' equity
Three reports a CPA expects that the engine could not produce:

- general_ledger(start, end): the canonical general ledger, organized by
  account in code order. Each account has its beginning balance, every
  posting in the period (date, entry, description, debit, credit, running
  balance on the normal side) and its ending balance, which ties to the
  trial balance. Each posting names its split: the one account on the
  opposite side of its entry, or "-Split-" when that side has several,
  so a compound entry (one debit, several credits) reads correctly from
  every account it touches. The entry-ordered listing the exports called a
  "general ledger" is really the general journal.
- trial_balance_as_of(as_of): a trial balance is always as of a date.
- members_equity(start, end, members): the statement of changes in
  members' equity for a multi-member LLC taxed as a partnership. Each
  member's capital roll-forward: beginning (capital plus their share of
  undistributed earnings), contributions, allocated net income (loss),
  distributions, ending. Allocation is by ownership share to the cent,
  the last member absorbing rounding, so totals are exact and the ending
  total equals balance-sheet equity; any equity change the roll-forward
  can't explain shows as "other" instead of disappearing. Shares must be
  positive and sum to exactly 1; capital accounts must be distinct
  equity accounts (LedgerError::InvalidMembers).
- CashFlowLine.account: the account a line is about, so renderers can
  name members instead of account codes.

Tests (every expectation computed by hand): trial balance as of Jan 31;
February general ledger with beginning balances, running balances, a
card that nets to zero, an inactive account still listed, and every
ending balance tied to the trial balance; a compound entry's splits from
all three sides; a two-member partnership where 666.67 and 100.01 split
unevenly (333.34/333.33, 50.01/50.00), with and without closing January,
tying to the balance sheet each month; bad member configuration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 20:16:25 -07:00
swaitsandClaude Opus 5.5 a0e40690d2 feat: real dates and per-account detail in every statement export
Every statement export rendered life-of-ledger totals under whatever date
range or as-of label was asked for, and the P&L and balance sheet XLSX
were totals-only. Now:

- books.profit_and_loss / books.balance_sheet and the csv, json, xlsx,
  pdf exports and CPA package all use core's profit_and_loss_for_period
  and balance_sheet_as_of, with a line per account. The tools keep their
  totals and add revenue/expense/asset/liability/equity account lines.
  An omitted start is the first posted entry, never "0001-01-01".
- ledger-import::report lays a statement out once (section, line,
  subtotal, total) for every renderer, with one exact amount formatter:
  thousands separators, negatives in parentheses, no floats. XLSX keeps
  numeric cells with an accounting number format, named sheets, company
  header, totals with borders; the trial balance gains its totals row.
- ledger-mcp reads wanderbooks.toml (next to --data-dir, or
  --books-toml): company name for headers, fiscal_year_start for the CPA
  package's fiscal year to date (end derived; Feb 29 rejected), and
  [books] receipt_threshold, which the server had been ignoring.
  config.json's receipt_policy still wins when set. New dependency: toml
  1.x (already in the lockfile via another crate).
- Store::journal_seq(); every report notes the journal seq it reflects.

Tests: company.rs unit tests (fiscal years incl. a July start, scaffold
parsing, bad settings); report.rs formatting tests; an MCP stdio test with
--books-toml (threshold 5.00 enforced, February-only P&L with account
lines, start defaults to the first entry, as-of balance sheet).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 19:11:36 -07:00
swaitsandClaude Opus 5.5 78ac7099b8 feat: period-scoped P&L and as-of balance sheet; closes don't zero periods
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
2026-10-11 19:04:18 -07:00
swaitsandClaude Opus 5.5 54590918d3 feat: cash flow statement PDF, pdf export format, cash flow in CPA package
The cash flow statement was computed and exportable as csv/json/xlsx but
missing from every PDF path, so the CPA package carried two of the three
financial statements. Now:

- ledger-import: cash_flow_pdf renders the indirect-method statement
  (operating with net income, depreciation add-back, working-capital
  lines; investing; financing; net change reconciled to beginning and
  ending cash) from the computed CashFlowStatement, so the period and
  cash accounts are the caller's.
- books.export gains format "pdf" for profit_and_loss, balance_sheet, and
  cash_flow (base64, like xlsx), plus financing_accounts for cash_flow.
- books.export_cpa_package adds cash-flow.pdf (fiscal year to date, like
  the P&L) and requires cash_accounts: without them the statement has
  nothing to reconcile to.
- One cash_flow_statement helper resolves codes and dates for xlsx, pdf,
  and the package.

Test: MCP stdio test exports all three statement PDFs, checks the
cash_accounts and bad-report refusals, and unzips the CPA package to find
all five files. Known report gaps are logged in plan/STATUS.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 18:57:12 -07:00
swaitsandClaude Opus 5.5 4ff5d1a40b feat: receipt unlink and attachment withdrawal
Posted entries stay immutable (R-3), but their evidence can now change the
same way the ledger does: by appending events, never by editing or
deleting. New R-13a.

- books.unlink_receipt {attachment_id, reason} journals receipt.unlinked
  and leaves the receipt filed, unlinked. The receipt policy holds: an
  entry that requires a receipt can't lose its last one (structured
  receipt_required error), so a replacement is attach-new, then
  unlink-old. Drafts and reversals are exempt, as at posting.
- books.withdraw_attachment {attachment_id, reason} journals
  attachment.withdrawn for an unlinked receipt or a filed document: hidden
  from list_receipts (unless include_withdrawn), never linkable again. The
  blob stays in the store, hash-verified and readable.
- link_receipt now refuses an already-linked or withdrawn attachment.
  Before, re-linking silently moved a receipt off a posted entry,
  bypassing the policy; evidence now leaves an entry only through a
  recorded unlink. dispose_asset checks its receipt ids before posting
  instead of after.
- Schema v5 adds attachments.withdrawn_at/withdrawn_reason; existing
  stores migrate on open and replay rebuilds the projection.

Tests: store test (errors, reopen, rebuild, verify, journal history) and
an MCP stdio test (policy refusal, replace flow, withdraw, listings,
under-threshold unlink). Dry-run and live use on the the first company books:
8 migrated .eml attachments swapped for their PDF renders, trial balance
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 18:40:51 -07:00
swaits ca5357546c Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:32:27 +00:00
swaits 2815265ecd Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:32:26 +00:00
swaits 34eccd5cb9 Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:32:24 +00:00
swaits 6bc5ffdafe Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:41 +00:00
swaits fb6419125f Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:38 +00:00
swaits b58f5dc169 Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:36 +00:00
swaits daa61b96d8 Docs: refresh for public repo — rewrite README, update roadmap/STATUS/requirements 2026-10-11 07:35:24 +00:00
swaits 2fb471a7b9 Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:02:53 +00:00
swaits 9a97834fd9 Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:02:48 +00:00
swaits a0b5616da3 Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:02:45 +00:00
swaits 58ab205617 Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:02:41 +00:00
swaits e051195286 Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:02:33 +00:00
swaits a32837f448 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:52 +00:00
swaits 3433c7015a asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:50 +00:00
swaits b1efe32c13 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:49 +00:00
swaits 6f99e81de2 First slice: ledger-store (journal+blobs+sqlite) and ledger-mcp (18 tools, receipt policy) 2026-10-11 01:37:34 +00:00
swaits d5f12d9ecd Storage: hash-chained JSONL journal as source of truth, SQLite as disposable projection 2026-10-11 01:16:23 +00:00
swaits 9f55a2f396 Storage: hash-chained JSONL journal as source of truth, SQLite as disposable projection 2026-10-11 01:16:21 +00:00
swaits 7da619724a QBO formats for import/export; server-side receipt enforcement policy in MCP spec 2026-10-11 01:09:49 +00:00
swaits 6e002f27d4 QBO formats for import/export; server-side receipt enforcement policy in MCP spec 2026-10-11 01:09:47 +00:00
swaits 3cb8ab9b35 QBO formats for import/export; server-side receipt enforcement policy in MCP spec 2026-10-11 01:09:45 +00:00
swaits 58127168a0 QBO formats for import/export; server-side receipt enforcement policy in MCP spec 2026-10-11 01:09:43 +00:00
swaits 0fe2db2c2e QBO formats for import/export; server-side receipt enforcement policy in MCP spec 2026-10-11 01:09:41 +00:00
swaits 4151ac0887 QBO formats for import/export; server-side receipt enforcement policy in MCP spec 2026-10-11 01:09:40 +00:00
swaits 3c567756d4 QBO formats for import/export; server-side receipt enforcement policy in MCP spec 2026-10-11 01:09:38 +00:00
swaits f40dfd8abc Spec: AI-first MCP interface phase (ledger-mcp, receipt store, capability parity) 2026-10-11 01:07:53 +00:00
swaits 8e08fc5b47 Spec: AI-first MCP interface phase (ledger-mcp, receipt store, capability parity) 2026-10-11 01:07:45 +00:00
swaits 817cc6d613 Spec: AI-first MCP interface phase (ledger-mcp, receipt store, capability parity) 2026-10-11 01:07:43 +00:00
swaits ef8c6b197d Spec: AI-first MCP interface phase (ledger-mcp, receipt store, capability parity) 2026-10-11 01:07:41 +00:00
swaits 9faf3d5ca1 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:04 +00:00
swaits 1f8228efb8 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:02 +00:00
swaits fca738a711 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:00 +00:00
swaits 7bbeb25889 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:45:58 +00:00
swaits 1ff7d38f13 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:45:57 +00:00