Files
wanderbooks/crates/ledger-core/src/lib.rs
T
swaitsandClaude Opus 5.5 6fa1b382ae closes: a run of members closes splits cumulatively
Each close into members' capital rounded on its own, ties to the
earlier member, so twelve monthly 50/50 closes of odd-cent income could
leave one member several cents ahead of half the year (docs/testing.md
#12, found with the members' equity fix).

- CloseTo::Members now splits cumulatively over a run (closes back to
  back with the same members and shares): each close gives a member
  allocate(run total so far) - allocate(run total before). Periods
  record their close order and a cumulative close's members and net
  (Period::close_seq, member_close) so the next close continues the run
  and replay recomputes it exactly. A close to anything else, or other
  shares, ends the run.
- Journaled "rounding": "cumulative". The per-close rule is kept as
  CloseTo::MembersPerClose for closes journaled "largest_remainder";
  older closes still replay with the last member absorbing it.
- Lean: runPart_telescopes (a member's total from a run is their
  allocation of the run's total) and closePart_total (each close hands
  out exactly its net), audited to the standard axioms.
- Tests: hand-computed three one-cent months (per close A 0.03 / B 0;
  cumulative A 0.02 / B 0.01), a run ending, a property that each member
  stays within a cent of their share (fails on the per-close rule), and
  a store contract that each rule journals and replays as itself.

The first company's books have no closes yet, so all of theirs use the new rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
2026-10-13 18:58:21 -06:00

75 lines
3.0 KiB
Rust

//! `ledger-core`: canonical double-entry bookkeeping semantics.
//!
//! This crate is the engine. Everything else in the workspace — persistence,
//! import, the oracle harness, the UI — builds on top of it and never
//! reimplements accounting logic.
//!
//! Design rules (see `AGENTS.md` at the repo root):
//!
//! * Money is [`Money`]: an exact [`rust_decimal::Decimal`] plus an ISO 4217
//! currency code. Binary floats never touch money paths.
//! * A [`Ledger`] is single-currency for now (see `docs/requirements.md` R-5).
//! * All mutations go through [`Ledger`] commands (`create_entry`, `add_line`,
//! `post_entry`, `reverse_entry`). Posted entries are immutable; corrections
//! are reversing entries.
//! * Reports ([`trial_balance`](reports::trial_balance), [`balance_sheet`](reports::balance_sheet), [`profit_and_loss`](reports::profit_and_loss)) are
//! pure functions of a ledger, which is what makes the semantic oracle
//! (`docs/oracle.md`) possible.
pub mod account;
pub mod analysis;
pub mod arap;
pub mod assets;
pub mod classes;
pub mod error;
pub mod form1099;
pub mod journal;
pub mod kernel;
pub mod ledger;
pub mod money;
pub mod payouts;
pub mod payroll;
pub mod periods;
#[cfg(kani)]
mod proofs;
pub mod reports;
pub mod rules;
pub mod schedules;
pub mod tax;
pub use account::{Account, AccountId, AccountType, ChartOfAccounts, Side};
pub use arap::{
AgingRow, Bill, BillId, Customer, CustomerId, DocumentLine, DocumentStatus, Invoice, InvoiceId,
Vendor, VendorId,
};
pub use assets::{
Asset, AssetId, AssetStatus, DepreciationMethod, DisposalAmounts, NewAsset, ScheduleLine,
accumulated_depreciation, book_value, depreciation_schedule, disposal_amounts,
};
pub use classes::{Class, ClassId};
pub use error::LedgerError;
pub use form1099::{Form1099, Vendor1099Line, Vendor1099Report, vendor_1099_report};
pub use journal::{EntryId, EntryStatus, JournalEntry, JournalLine};
pub use ledger::{
ControlAccount, GENERAL_EXPENSES, Ledger, PAYABLES, PAYROLL, RECEIVABLES, RETAINED_EARNINGS,
REVENUE, ReconciliationReport, UnclearedLine,
};
pub use money::{Currency, Money};
pub use payouts::{Payout, PayoutAdjustment, PayoutLine, PayoutTotals, payout_plan};
pub use payroll::{PayrollLine, PayrollRun, PayrollRunId};
pub use periods::{
CloseTo, MemberClose, MemberCloseRecord, Period, PeriodId, PeriodStatus, RETAINED_EARNINGS_CODE,
};
pub use reports::{
BalanceSheet, BalanceSheetStatement, CashFlowLine, CashFlowParams, CashFlowStatement,
ClassProfitAndLoss, GeneralLedger, LedgerAccount, LedgerPosting, MemberCapital,
MemberEquityColumn, MembersEquityStatement, ProfitAndLoss, ProfitAndLossStatement,
StatementLine, TrialBalance, TrialBalanceLine, balance_sheet_as_of, cash_flow, general_ledger,
members_equity, profit_and_loss_for_period, trial_balance_as_of,
};
pub use schedules::{
AmortizationSchedule, Frequency, NewRecurring, NewSchedule, RecurringEntry, RecurringId,
ScheduleId, ScheduleKind, TemplateLine,
};
pub use tax::{TaxCategory, TaxForm, TaxKind, TaxSummary, TaxSummaryLine, tax_summary};