Skip to content

calternal_money::budget

Exact zero-based envelope maths: Ready to Assign, Assigned, Activity, Available, rollover, funding states and card payment reserves.

Port of calculate in spikes/money-format/budget_math.py (the #404 oracle, rounds 1-3 plus two independent breakage reviews). The rules (DESIGN §48, funding states):

  • Assigning moves money from Ready to Assign into a category’s Available.
  • Income and cash opening balances add to Ready to Assign.
  • Positive Available rolls into the next month. Cash overspending (Available below zero from cash spending) is deducted from next month’s Ready to Assign; credit overspending becomes card debt instead.
  • A card purchase moves the funded part of the category’s money into the card’s payment category (the reserve). Payments consume funded purchases oldest first by date (file order breaks ties); a refund releases only its own category’s unpaid reserve.
  • Cash has first claim on a category that both cash and a card spend from in one month, independent of file order.
  • A zero-value import reconciliation row can adjust Ready to Assign alone; it keeps Account and Category totals unchanged (#462, DESIGN §48).

Every value is an exact Minor in the budget currency; every sum is checked, so an overflow is an error, never a wrapped number. Nothing here is stored: the caller derives it from the files each time (F5).

Source: crates/calternal-money/src/budget.rs

pub struct BillCoverage

A card bill compared with its funded reserve (never clamped, DESIGN §48).

Fields

  • pub bill: Minor: The full bill.
  • pub reserve: Minor: The reserve, floored at zero.
  • pub underfunded: Minor: max(0, bill - reserve).
  • pub overfunded: Minor: max(0, reserve - bill): stays for the next cycle.
  • pub status: CoverageStatus: Underfunded, Overfunded or Funded.

Implements: Clone, Copy, Debug, Eq, PartialEq, Serialize

Source: crates/calternal-money/src/budget.rs:156

pub struct CategoryMonth

One category’s derived numbers for one month.

Fields

  • pub category_id: String: Category ID.
  • pub assigned: Minor: Money assigned in this month.
  • pub activity: Minor: Posted activity in this month (spending negative, inflow positive).
  • pub available: Minor: Month-end Available after rollover in and this month’s activity.
  • pub state: FundingState: Funding state.
  • pub overspend: Option<OverspendKind>: Which account kind overspent it this month, if any.
  • pub target: Option<Minor>: Monthly target.
  • pub months_funded: Option<i64>: Full target months covered.
  • pub target_remainder: Option<Minor>: Available beyond full target months.

Implements: Clone, Debug, Serialize

Source: crates/calternal-money/src/budget.rs:219

pub struct ImportReplay<'a>

Incremental Money calculation for an importer that projects one month at a time. The metadata Ledger must stay alive for the replay; each call accepts transactions from one parsed month and releases them when it returns. This keeps large import validation from retaining every month of transaction objects (#462, DESIGN §48).

pub fn new(metadata: &'a Ledger) -> Result<Self>

Start a replay from validated Budget and Account metadata. The Ledger may have no month files; it must contain the assignments and identities used by all streamed months (#462, DESIGN §48).

pub fn month_with_transactions(
&mut self,
month: &str,
transactions: &[Transaction],
mut check: impl FnMut() -> Result<()>,
) -> Result<MonthTotals>

Calculate one month from its temporary transaction rows, then release those rows while keeping balances and card purchase queues for the next month (#462, DESIGN §48).

pub fn adjust_ready_to_assign(&mut self, amount: Minor) -> Result<()>

Apply an import-only Ready to Assign reconciliation after a month. It changes no Account or Category total and carries into later months (#462, DESIGN §48).

Source: crates/calternal-money/src/budget.rs:421

pub struct MonthTotals

One derived month. Maps are keyed by ID and sorted.

Fields

  • pub month: String: YYYY-MM.
  • pub ready_to_assign: Minor: Ready to Assign at the end of this month.
  • pub categories: Vec<CategoryMonth>: Categories sorted by ID.
  • pub card_debt: BTreeMap<String: Card account balances (negative is debt).
  • pub card_payment_balance: BTreeMap<String: Card ID -> Available in its payment category (the reserve).
  • pub debt_not_covered: BTreeMap<String: Card ID -> debt the reserve does not cover.
  • pub account_balances: BTreeMap<String: Every account balance in budget minor units.

Implements: Clone, Debug, Serialize

pub fn category(&self, id: &str) -> Option<&CategoryMonth>

Find one category’s numbers.

Source: crates/calternal-money/src/budget.rs:242

pub enum CoverageStatus

The coverage label for a bill.

Variants

  • Funded: Reserve equals the bill.
  • Underfunded: Reserve below the bill.
  • Overfunded: Reserve above the bill.

Implements: Clone, Copy, Debug, Eq, PartialEq, Serialize

pub const fn label(self) -> &'static str

The oracle’s label.

Source: crates/calternal-money/src/budget.rs:171

pub enum FundingState

A category’s derived funding state for one month.

Variants

  • Available: Available is above zero (no target, or less than one target month).
  • Funded: Available is exactly zero.
  • Overspent: Available is below zero from cash spending.
  • Underfunded: Available is below zero from card spending, or a payment category is below zero.
  • FundedAhead(i64): Available covers this many full target months (>= 1).

Implements: Clone, Copy, Debug, Eq, PartialEq, Serialize

pub fn label(self) -> String

The oracle’s label, for example Funded for next 2 months.

Source: crates/calternal-money/src/budget.rs:34

pub enum OverspendKind

Which kind of account last overspent a category this month.

Variants

  • Cash: Cash spending: reduces next month’s Ready to Assign.
  • Card: Card spending: becomes card debt.
  • Tracking: Tracking-account spending: neither.

Implements: Clone, Copy, Debug, Eq, PartialEq, Serialize

pub const fn as_str(self) -> &'static str

The oracle’s short name.

Source: crates/calternal-money/src/budget.rs:64

pub fn bill_coverage(bill: Minor, reserve: Minor) -> Result<BillCoverage>

Compare an exact bill (>= 0) with a reserve in the same currency.

Invariant: bill - underfunded + overfunded == max(reserve, 0).

Source: crates/calternal-money/src/budget.rs:194

pub fn calculate(ledger: &Ledger, months: &[String]) -> Result<Vec<MonthTotals>>

Replay months (sorted YYYY-MM, no duplicates) and return one MonthTotals per month. Transactions and assignments of months not in the list are ignored, exactly like the oracle.

Conservation invariants (property-tested in tests/properties.rs): with only cash accounts, Ready to Assign plus every category’s Available equals the sum of account balances at every month end; with cards whose purchases are fully funded, it equals the sum of cash balances (the card debt is exactly covered by its payment reserve).

Source: crates/calternal-money/src/budget.rs:1039

pub fn calculate_pair(
before: &Ledger,
after: &Ledger,
months: &[String],
) -> Result<(Vec<MonthTotals>, Vec<MonthTotals>)>

Replay two validated ledger states over the same month range in one paired call. Transaction event routes need both sides of a durable write to detect a zero-to-negative crossing (#984, DESIGN §55); keeping the validation and month walk together prevents those routes from issuing separate replays.

Source: crates/calternal-money/src/budget.rs:1073

pub fn calculate_with_check(
ledger: &Ledger,
months: &[String],
mut check: impl FnMut() -> Result<()>,
) -> Result<Vec<MonthTotals>>

Replay sorted months with bounded row checkpoints for cancellable large import previews (#462, DESIGN §48). The ordinary budget path calls calculate and uses the same arithmetic without external cancellation.

Source: crates/calternal-money/src/budget.rs:1046

pub fn continuous_months(ledger: &Ledger, through: &str) -> Result<Vec<String>>

Every month from the first month with data through through, inclusive.

The product view uses this range: a month without a file counts as a month with no transactions, and assignments in such a month still count. (The oracle only walks months that have a file; see the crate docs.)

Source: crates/calternal-money/src/budget.rs:284

pub fn file_months(ledger: &Ledger) -> Vec<String>

The months of every month file, sorted: the oracle’s month list.

Source: crates/calternal-money/src/budget.rs:269

pub fn funding_state(
kind: CategoryKind,
available: Minor,
overspend: Option<OverspendKind>,
target: Option<Minor>,
) -> Result<(FundingState, Option<i64>, Option<Minor>)>

Derive a category’s funding state and target months from exact Available.

Invariants: target, when present, is > 0; months_funded * target + remainder == max(available, 0) and 0 &lt;= remainder &lt; target.

Source: crates/calternal-money/src/budget.rs:96

pub fn ready_to_assign_label(amount: Minor) -> &'static str

The Ready to Assign label: Assigned more than you have below zero.

Source: crates/calternal-money/src/budget.rs:131

pub fn rollover(available: Minor, overspend: OverspendKind) -> (Minor, Minor)

Carry a month-end Available into the next month.

Returns (next Available, change to next Ready to Assign): positive values carry; a cash deficit resets to zero and is deducted; any other deficit resets to zero with no deduction.

Source: crates/calternal-money/src/budget.rs:144