Calculation catalog › Accounts and growth

Accounts investable total annual

Cash + taxable + traditional + Roth + HSA (+ unassigned) balances at year end.

Field: Investable total Unit: US dollars Basis: nominal dollars Computed by: Engine Status: Complete chain

Appears in: csv (investable); results-table (Investable column); report (year-ledger block investable and ReportPage year table); chart (Path to FI chart investable line); scenarios-page (Annual ledger comparison "Investable assets"); survivor-page (Survivor spending "low point" (minimum over survivor years)); results-table (Bucket lens investableTotal row and bucket sum); insights (spending-guardrails and hecm-buffer cards read year-one investableTotal)

Calculation records

  • Annual investable total Composition record, justified by derivation

    Purpose: The year-end balance a plan can actually spend from, and what is deliberately left out.

    Statement: projection/internal/annualSnapshot.ts#annualSnapshot opens the investable fold at unassignedCash and adds every investable balance in simulator order (cash, taxable, equity-compensation, traditional, Roth and HSA accounts), publishing the sum as projection/internal/types/result.ts#YearResult.investableTotal. Property values, ordinary debts, HECM loans and permanent-life cash values are folded into their own separate totals and are not members; the TIPS ladder value is computed outside the snapshot and is likewise not a member. netWorth adds those channels. Units: nominal USD at year end. Rounding: none; the additions are left in their original loop order because regrouping binary floats can move the last bit.

    Formula: investableTotal = unassignedCash + sum over investable balances of balance

    • unassignedCash: Cash with no modeled account to land in; opens the fold (unit: usd) (domain: nonnegative)
    • balance: One investable account's year-end balance (unit: usd) (domain: nonnegative)
    • insuranceCashValueTotal, propertyTotal, debtTotal, ladderValue: Separate channels, excluded here (unit: usd) (domain: nonnegative; members of netWorth only)

    Timing: once per projection year, at the end-of-pass snapshot

    Rounding: none

    Limits:

    • The worksheet's case is asserted at annualSnapshot, the function that computes the field, because unassigned cash and a cash or taxable account cannot coexist in a real plan: simulatePlan only tracks cash as unassigned when there is no cash or taxable account for surplus to land in, so the worksheet's $2,000 of unassigned cash alongside $15,000 of cash accounts and $120,000 of taxable accounts is not a state a plan produces
    • The member list is separately asserted on a real simulatePlan run carrying the worksheet's six account balances plus a permanent-life policy: the published investableTotal is the six balances and excludes the policy cash value and the property, both of which the same row publishes
    • Equity compensation is a member whether or not it has vested; the vesting mode gates spending, not the balance total

    Provenance: derived by codex, implemented by claude.

    Independent review: cursor

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: accounts-investable-total-annual.md Mutation receipt: accounts-investable-total-annual.mutation.md

    Evidence tests: annualSnapshot.evidence.test.ts

    Implemented in: annualSnapshot.ts; result.ts

    Is the number of: accounts-investable-total-annual

    Feeds: accounts-net-worth-annual, projection-result-ending-investable

Records that feed this number

  • Unrebalanced weights after one year of class returns Formula record, justified by derivation

    Purpose: How an allocation drifts when each class grows at its own total return and nothing is rebalanced.

    Statement: grown_i = w_i x max(0, 1 + r_i/100), with a missing r_i read as 0; total = sum of grown_i; the drifted vector is grown_i/total when total > 0, else the input weights unchanged. Units: fractions. Rounding: none. The ledger calls it after each year's growth with r_i = returnPct_i plus the year's class shock, and the result is the next year's tracked weights until a rebalance retargets them.

    Formula: w'_i = w_i (1 + r_i/100) / sum_j w_j (1 + r_j/100), each factor floored at 0

    • w_i: Beginning weight of class i (unit: 1) (domain: w_i >= 0, sum 1)
    • r_i: Total return of class i over the year (unit: percent) (domain: r_i >= -100 for a positive factor)
    • w'_i: Ending weight of class i (unit: 1) (domain: sum 1 when the total is positive)

    Timing: end of year, after growth

    Rounding: none

    Limits:

    • Total-return convention: distributions are treated as reinvested pro rata, so a class's weight moves with its total return rather than its price return
    • A class return at or below -100% is floored at zero ending value rather than going negative
    • A zero total ending value returns the input weights unchanged instead of refusing
    • The worksheet names bucket-lens-allocation upstream; the bucket lens (its own record) reads the published investable total and net portfolio need, refusing a year whose need is not a finite number, and is not listed here

    Provenance: derived by codex, implemented by claude-subagent.

    Independent review: grok

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: allocation-total-return-drift.md Mutation receipt: allocation-total-return-drift.mutation.md

    Evidence tests: assetClasses.evidence.test.ts

    Implemented in: assetClasses.ts

    Feeds: accounts-balance-per-account-annual, accounts-investable-total-annual

  • Allocation weights to a normalized fraction vector in class order Formula record, justified by derivation

    Purpose: Turns a percent-weights record into the fraction vector every allocation calculation indexes by class.

    Statement: For a weights record in percent, raw_i = max(0, w_i) in ASSET_CLASS_IDS order (usStocks, intlStocks, bonds, cash); W = sum of raw_i; the vector is raw_i/W. When W <= 0 (every weight zero or negative) the vector is all cash, [0, 0, 0, 1]. Units: fractions summing to 1. Rounding: none.

    Formula: f_i = max(0, w_i) / sum_j max(0, w_j); f = [0, 0, 0, 1] when the sum is not positive

    • w_i: Weight of class i as entered (unit: percent) (domain: schema: 0 <= w_i <= 100, total 100 +/- 0.5)
    • W: Sum of the floored weights (unit: percent) (domain: W >= 0)
    • f_i: Normalized fraction of class i (unit: 1) (domain: 0 <= f_i <= 1, sum 1)

    Timing: time-invariant

    Rounding: none

    Limits:

    • Negative weights are floored at 0 before normalizing rather than rejected; the schema already bounds each weight to [0, 100] and the total to 100 +/- 0.5, so a near-100 total normalizes exactly to 1
    • A zero total returns the all-cash vector instead of refusing; the worksheet's domain is a positive total and its test does not reach that branch
    • Class order is positional and fixed by ASSET_CLASS_IDS; every consumer indexes the vector by that order, never by magnitude
    • The worksheet names bucket-lens-allocation upstream; the bucket lens (its own record) reads the published investable total and the published net portfolio need, and refuses a year whose need is not a finite number, so the family is reached only through the balances every growth record feeds and is not listed here

    Provenance: derived by codex, implemented by claude-subagent.

    Independent review: grok

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: allocation-weight-normalization.md Mutation receipt: allocation-weight-normalization.mutation.md

    Evidence tests: assetClasses.evidence.test.ts

    Implemented in: assetClasses.ts

    Feeds: accounts-balance-per-account-annual, accounts-investable-total-annual

Engine source: engine/src/projection/internal/types/result.ts (YearResult.investableTotal)

The evidence links on this page (each record's worksheet, mutation receipt, evidence tests and implementation, and the source links) are pinned to engine commit 2624dbdba9fd, committed 2026-10-11. The live calculation index and output-family census links point at the repository's main branch, so you can check this snapshot against them.