Calculation catalog › Accounts and growth
Accounts ending balance by category
End-of-plan balance summed by account category (cash, taxable, traditional, roth, hsa) over the selected logical balance accounts.
Field: Ending balance by category Unit: US dollars Basis: nominal dollars Computed by: Engine Status: Complete chain
Appears in: results-headline (KpiBar "ending Roth $X" (endingByCategory.roth)); scenarios-page (Estate table Cash / Taxable / Traditional / Roth / HSA rows); mcp (run_projection.summary.endingByCategory); mcp (compare_scenarios.a.endingByCategory); mcp (compare_scenarios.b.endingByCategory)
Calculation records
-
Ending balances by logical account category Composition record, justified by derivation
Purpose: How the last ledger year's account balances roll up into the five published categories.
Statement: projection/compare.ts#summarizeProjection publishes endingByCategory as the sum of the LAST ledger year's published balances by the corresponding selected logical account type: cash, taxable, traditional, roth and hsa. Equity-compensation balances are not one of these five categories, and no property, debt, ladder or insurance value enters them. Units: nominal USD. Rounding: none.
Formula:
endingByCategory[c] = sum over selected accounts of type c of lastYear.balances[accountId]-
lastYear: Final row of the ledger (unit: year row) (domain: empty ledger publishes five zeros) -
c: Published category (unit: enum) (domain: cash | taxable | traditional | roth | hsa)
Timing: once per projection, on the final ledger row
Rounding: none
Limits:
- Asserted at summarizeProjection with the worksheet's six accounts, their plan types and their last-year balances verbatim, over a two-row ledger whose penultimate row carries a distinct sentinel balance on every account so a row mistake cannot pass. Plan assumptions beyond the worksheet's inputs: each account opens at a zero balance with zero returns, because the summary reads the ledger row rather than the plan; the owner-held accounts name the plan's single person
- The test also asserts that the published object has exactly the five category keys, which is how the worksheet's third wrong reading (adding property or insurance categories) is discriminated
- Since 2026-09-26 the roll-up is projection/yearFigures.ts#balancesByCategory read for the last row (the same sums in the same order, so the published figures did not move). That function refuses a plan in which an account id is also the id of a property, a debt or a permanent-life policy, so the summary now stops on such a plan instead of reporting the overwritten value as the account's; the plan checks refuse those plans and stored ones are repaired on load
Provenance: derived by
codex, implemented byclaude-subagent.Independent review:
grokGates (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-ending-balance-by-category.md Mutation receipt: accounts-ending-balance-by-category.mutation.md
Evidence tests: compareSummary.evidence.test.ts
Implemented in: compare.ts; yearFigures.ts
Is the number of: accounts-ending-balance-by-category
-
Records that feed this number
-
Annual employer match under the pay cap and the annual-additions limit Formula record, justified by derivation
Purpose: What the employer actually adds once the pay cap and the IRC 415(c) ceiling are applied.
Statement: projection/internal/types/result.ts#YearResult.employerMatch, planned by projection/internal/annualContributionsAndEmployerMatch.ts#annualContributionsAndEmployerMatch, is min(elective deferral landed, capPctOfPay/100 x wages) x matchPct/100, capped by the owner's remaining IRC 415(c) room for that plan after the elective deferrals. The 2026 tax parameters fix the 415(c) limit at 72,000. The match is computed only after every elective deferral has landed. Units: nominal USD per year. Rounding: none.
Formula:
employerMatch = min(min(E, c W) m, L - E - other additions)-
E: Elective deferral landed in the plan (unit: usd/year) (domain: nonnegative) -
W: Owner wages from the sponsoring employer (unit: usd/year) (domain: nonnegative) -
c: Match cap share of pay (unit: 1) (domain: capPctOfPay / 100) -
m: Match rate on the matched elective base (unit: 1) (domain: matchPct / 100) -
L: IRC 415(c) annual-additions limit (unit: usd/year) (domain: 72,000 for 2026)
Timing: once per projection year, after every elective deferral has landed
Rounding: none
Limits:
- Asserted as the published field of a real simulatePlan 2026 row built from the worksheet's inputs: wages 75,000, one employer traditional plan whose desired deferral of 24,500 lands in full, a 50-percent-of-pay match cap, a 200-percent match rate, and no other annual additions. Plan assumptions beyond the worksheet's inputs: the owner is 45 and filing single in KY at a zero state rate, so no age-50 catch-up can widen either the deferral or the room; the plan opens at a zero balance with zero returns and no spending; and the 2026 415(c) limit and elective-deferral limit are read from the published parameters rather than written into the test
- The worksheet's third wrong reading (applying the pay cap after the match rate) produces 37,500, which is discriminated numerically here only because the 415(c) cap lands at 47,500 rather than 37,500
Provenance: derived by
codex, implemented byclaude.Independent review:
cursorGates (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: year-result-employer-match.md Mutation receipt: year-result-employer-match.mutation.md
Evidence tests: simulate.evidence.test.ts
Implemented in: result.ts; annualContributionsAndEmployerMatch.ts
Is the number of: year-result-employer-match
Feeds: accounts-ending-balance-by-category, cash-flow-line-plan-dollars
-
Engine source: engine/src/projection/compare.ts
(ProjectionSummary.endingByCategory)
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.