Calculation catalog › Spending and withdrawals
Display total spending annual
Expenses, taxes, and penalties plotted together as total spending for a projection year.
Field: Displayed total spending Unit: US dollars Basis: as displayed Computed by: UI transformation Status: Complete chain
Appears in: chart (spending); report (chart-data block spendingPlusTax (expenses.total + tax + penalties), and the printed report chart's spending series)
Calculation records
-
Total spending with tax and penalties Composition record, justified by derivation
Purpose: Everything the year paid out, as the spending line of the balance chart and the report chart show it.
Statement: projection/yearFigures.ts#spendingWithTaxAndPenalties publishes expenses.total + tax + penalties for the year, summed left to right: (expenses.total + tax) + penalties, the same composite the FI number's spending base uses. Units: nominal USD of the year. Rounding: none.
Formula:
spending = (expenses.total + tax) + penalties-
expenses.total: Funded spending after guardrail cuts, net of the LTC benefit (unit: usd per year) (domain: nonnegative) -
tax: Settled tax of the year (unit: usd per year) (domain: finite) -
penalties: Early-withdrawal penalty plus IRC 4974 excise (unit: usd per year) (domain: nonnegative)
Timing: annual
Rounding: none
Limits:
- Gross of incomes: it is what the year paid out, not what the portfolio had to supply (portfolio-need-annual)
- The association is part of the figure: expenses.total + (tax + penalties) differs in the last binary digit on some inputs (40,477.35, 18,353.95 and 539.21 give 59,370.51 left to right and 59,370.509999999995 grouped the other way)
Provenance: derived by
claude, implemented byclaude-subagent.Independent review:
codexGates (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: display-total-spending-annual.md Mutation receipt: display-total-spending-annual.mutation.md
Evidence tests: yearFigures.evidence.test.ts
Implemented in: yearFigures.ts; compare.ts
Is the number of: display-total-spending-annual
-
Records that feed this number
-
Today's dollars by the ledger's own inflation factor Formula record, justified by derivation
Purpose: How a year's nominal amount becomes start-year dollars on every page, and how a start-year figure such as the FI target is placed in a year's dollars.
Statement: projection/dollarBasis.ts converts a nominal amount x of projection year y to start-year dollars as x / f(y), and a start-year amount to year-y dollars as x * f(y), where f(y) is the ledger's published YearResult.inflationScale: the left-to-right product of (1 + inflationPct/100) taken y - startYear times from 1, exactly 1 in the start year. projectionDollarBasis reads the factors from a projection's rows; planDollarBasis runs the same recurrence for a page that holds no projection rows and is bit-identical to a deterministic run's factors. nominalForDisplay shows a nominal amount in the page's mode (converted in today's-dollar mode, unchanged in nominal mode) and todayForDisplay shows a start-year amount (unchanged in today's-dollar mode, times f(y) in nominal mode), so the FI target line is fiNumber itself in today's-dollar mode and fiNumber * f(y) in nominal mode. A year outside the projection, or a fractional year, is refused. Units: USD. Rounding: none.
Formula:
f(s) = 1; f(y) = f(y - 1) * (1 + i/100); today(y, x) = x / f(y); nominal(y, x) = x * f(y); FI target in year y = fiNumber (today mode) or fiNumber * f(y) (nominal mode)-
i: General inflation rate, plan.assumptions.inflationPct (unit: percent per year) (domain: finite, above -100) -
s: Projection start year, the first ledger row (unit: calendar year) (domain: integer) -
y: Year of the amount (unit: calendar year) (domain: integer in [s, endYear]) -
x: Amount converted (unit: usd) (domain: finite) -
f(y): Cumulative general-inflation factor, YearResult.inflationScale (unit: ratio) (domain: f(s) = 1)
Timing: annual; one factor per calendar year, applied to every amount of that year
Rounding: none
Limits:
- planDollarBasis is the plan's assumed rate and matches only a deterministic run: a Monte Carlo path grows by its own inflation series, so its rows are converted with projectionDollarBasis on that path's own result
- Start-year dollars in whole-year steps: an amount paid in December and one paid in January of the same year carry the same factor
- General inflation only: the healthcare inflation premium and the Social Security cost-of-living adjustment are separate assumptions and are never the basis
- Years outside the projection are refused, never extrapolated; a projection whose horizon ends before its start year has an empty basis in which every year is refused
- Owner decision R19 (2026-09-25): the planner pages used to compound the plan's rate with Math.pow from the page's start year. The ledger's factor is a product built one year at a time, which differs from the power in the last binary digit in some years (21 of 41 years at 2.5 percent, one unit each), so a whole-dollar figure can change only on an exact half-dollar tie; the FI target in today's-dollar mode becomes exactly fiNumber instead of fiNumber * f / f
- The FI target is recorded here rather than in a record of its own: it is projection-summary-fi-number placed in a year through todayForDisplay
- Since B2-P1 slice 2 the spending page converts nothing itself: each published withdrawal rule's ending estate is converted by that rule's own run (decisions/swrComparator.ts#compareSwrRules publishes endingAfterTaxEstateTodayDollars), and the solver's evidence estate by the answer run's own factors; planDollarBasis remains for the relocation page
Provenance: derived by
claude, implemented byclaude-subagent.Independent review:
codexGates (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: display-dollar-basis-conversion.md Mutation receipt: display-dollar-basis-conversion.mutation.md
Evidence tests: swrComparator.evidence.test.ts; dollarBasis.evidence.test.ts
Implemented in: dollarBasis.ts; detectorProjection.ts; result.ts; swrComparator.ts
Is the number of: display-dollar-basis-conversion, display-fi-target-annual
Feeds: display-balance-by-category-annual, display-net-care-cost-annual, display-tax-free-gains-room-annual, display-tax-plus-penalties-annual, display-total-spending-annual, display-upside-shortfall-annual, display-upside-spending-annual
-
-
Annual net expense total Composition record, justified by derivation
Purpose: The year's actual net outflow, and which expense members compose it.
Statement: projection/internal/annualExpenseSummary.ts#annualExpenseSummary publishes projection/internal/types/yearLedger.ts#YearExpenses.total as baseSpending + oneTimeGoals + debtService + propertyCosts + healthcare + insurancePremiums + careCost - ltcBenefit, kept in that left-to-right association because regrouping the LTC pair can move the last bit. careCost is gross and ltcBenefit offsets it. guardrailFactor is descriptive: the cut is already inside baseSpending and is never multiplied in again. requiredSpending, targetSpending, idealSpending, excessSpending and intendedSpending are overlapping layer summaries, not additional members, and intendedSpending is the no-cut request and need not equal this total. Units: nominal USD per year. Rounding: none.
Formula:
total = baseSpending + oneTimeGoals + debtService + propertyCosts + healthcare + insurancePremiums + careCost - ltcBenefit-
baseSpending: Recurring lifestyle spending already net of the guardrail cut (unit: usd/year) (domain: nonnegative) -
oneTimeGoals: One-time goals funded this year (unit: usd/year) (domain: nonnegative) -
careCost, ltcBenefit: Gross care-episode cost and the policy benefit offsetting it (unit: usd/year) (domain: nonnegative; the benefit is subtracted) -
guardrailFactor: Discretionary multiplier already applied inside baseSpending (unit: 1) (domain: descriptive only)
Timing: once per projection year, at the expense summary
Rounding: none
Limits:
- Asserted at the annualExpenseSummary seam with the worksheet's eight member amounts, because the worksheet states them as published year-row components: a single real plan cannot present a chosen base spending, one-time goal, debt service, property cost, healthcare charge, insurance premium, gross care cost and LTC benefit at those exact values simultaneously
- Cross-checked on a real simulatePlan run: the published total of that year row equals the same row's own eight published members in the same association
- The guardrail factor and intended spending are asserted NOT to enter: the test drives the seam with a factor of 0.90 and an intended request of $100,000 and shows neither changes the total
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: spending-total-annual.md Mutation receipt: spending-total-annual.mutation.md
Evidence tests: annualExpenseSummary.evidence.test.ts
Implemented in: annualExpenseSummary.ts; yearLedger.ts
Is the number of: spending-total-annual
-
-
Annual penalties: early withdrawal plus the IRC 4974 excise Composition record, justified by derivation
Purpose: The two penalty channels a year composes, and why neither is part of tax.
Statement: projection/internal/types/result.ts#YearResult.penalties is composed by projection/internal/annualFundingCandidateEvaluation.ts#annualFundingCandidateEvaluation as projection/internal/annualFundingWithdrawalEffects.ts#annualFundingWithdrawalEffects reporting penaltyExcludingRmdShortfallExcise plus the IRC 4974 excise from rmd/rmdShortfallExcise.ts#computeRmdShortfallExcise. The early-withdrawal rate is 10 percent on pre-age-59-and-a-half taxable traditional withdrawals, inherited distributions are never subject to it, and the excise prices max(0, required - distributed by deadline) at the stated rate, whose post-SECURE-2 default is 25 percent, once for each obligation. In the calendar year a surviving spouse's election to treat an inherited IRA as her own takes effect, after the year of the owner's death, that IRA owes only its owner RMD (Treas. Reg. 1.408-8(c)(3)) and leaves the beneficiary's same-decedent group ((e)(2)(i)), so projection/internal/annualInheritedIraDistributions.ts#annualInheritedIraDistributions puts it in no beneficiary obligation. Penalties stay outside tax, AGI and MAGI. Units: nominal USD per year. Rounding: none.
Formula:
penalties = penaltyExcludingRmdShortfallExcise + rmdShortfallExciseTax; early = 0.10 x penalizable traditional; excise = rate x max(0, required - distributed)-
penalizable traditional: Taxable pre-59.5 traditional withdrawal (unit: usd) (domain: nonnegative; 0 for inherited accounts) -
required: Required minimum for the obligation (unit: usd) (domain: nonnegative) -
distributed: Distributed by the statutory deadline (unit: usd) (domain: nonnegative) -
rate: IRC 4974 rate (unit: 1) (domain: 0.25 default from 2023)
Timing: once per accepted funding evaluation in the projection year
Rounding: none
Limits:
- Asserted twice. At the two component producers: annualFundingWithdrawalEffects reports 2,000 of penaltyExcludingRmdShortfallExcise on the worksheet's 20,000 pre-59.5 taxable traditional withdrawal, and computeRmdShortfallExcise prices the worksheet's 12,000 required against 4,000 distributed as an 8,000 shortfall and a 2,000 excise at the default 25-percent rate with no relief elected. And as the published penalties of a real simulatePlan 2026 row that carries both channels at once: a 50-year-old whose only portfolio is a traditional IRA and whose 16,000 of required lifestyle plus the 2,000 excise drive a need-based withdrawal of exactly 20,000 under a zero-rate test calculator, alongside an inherited Roth account whose completed five-year deadline observation (opening benefit 12,000, 4,000 distributed by the 2026 deadline) prices the excise without replaying any cash
- Plan assumptions beyond the worksheet's inputs for that ledger year: filing single in KY at a zero state rate with a zero-rate test tax calculator, so tax is 0 and the whole need is spending plus penalties; the test asserts the 10-percent rate relation W = S + excise + 0.10 W closes at exactly 20,000
- The worksheet's fourth wrong reading is asserted as a rule: the same withdrawal-effects call on an inherited traditional account reports a zero penalty
- Restated 2026-09-30 and reviewed by Grok the same day: in an election year the elected IRA enters no beneficiary obligation. Asserted in simulate.spousalElectionYearOwnerRmd.test.ts on a 75-year-old spouse whose mid-2026 election takes effect: the owner RMD of 4,065.04 (100,000 / 24.6) is paid by 1,000 before the election and 3,065.04 after and is the one obligation, and the beneficiary figure of 6,689.19 (99,000 / 14.8) stays on the account's evidence as the trigger only, so the excise is 0 and not the 1,672.30 a second, unpaid obligation would charge
Provenance: derived by
codex, implemented byclaude.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: tax-penalties-annual.md Mutation receipt: tax-penalties-annual.mutation.md
Evidence tests: annualFundingCandidateEvaluation.evidence.test.ts
Implemented in: result.ts; annualFundingCandidateEvaluation.ts; annualFundingWithdrawalEffects.ts; rmdShortfallExcise.ts; annualInheritedIraDistributions.ts
Is the number of: tax-penalties-annual
Feeds: portfolio-need-annual, display-total-spending-annual, display-tax-plus-penalties-annual, scenario-lifetime-penalties
-
-
Annual composed tax Composition record, justified by derivation
Purpose: What the year's published tax figure is composed of, and what it excludes.
Statement: projection/internal/types/result.ts#YearResult.tax is the amount produced by the composed calculator built by tax/federalTax.ts#combineTaxCalculators: the federal total of regular income tax plus AMT plus NIIT, plus the state calculator amount, plus any further composed calculator amounts. Penalties are excluded from it, from AGI and from MAGI. Units: nominal USD per year. Rounding: none; the composition is an ordered fold.
Formula:
tax = federalTotal + stateAmount + sum of further calculator amounts-
federalTotal: Regular income tax + AMT + NIIT (unit: usd/year) (domain: nonnegative) -
stateAmount: State calculator amount (unit: usd/year) (domain: nonnegative) -
penalties: Early-withdrawal and IRC 4974 amounts (unit: usd/year) (domain: never a member of tax)
Timing: once per accepted tax evaluation in the projection year
Rounding: none
Limits:
- The worksheet treats the federal and state amounts as outputs independently evidenced by their own worksheets and checks only the annual composition boundary, so the test composes two calculators that report the worksheet's stated 12,000 federal total and 3,000 state amount and asserts the composed 15,000 through both compute and computeResult. Those two calculators are test doubles standing in for the evidenced federal and state records; this record makes no claim about federal or state tax arithmetic
- The 500 of penalties is asserted as excluded by composing the same calculators and showing the amount is unchanged: penalties never enter the calculator chain at all
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: tax-total-annual.md Mutation receipt: tax-total-annual.mutation.md
Evidence tests: federalTax.evidence.test.ts
Implemented in: result.ts; federalTax.ts
Is the number of: tax-total-annual
Feeds: portfolio-need-annual, surplus-invested-annual, display-tax-plus-penalties-annual, display-total-spending-annual
-
Transformations
- Add expenses.total + tax + penalties, left to right, in projection/yearFigures.ts#spendingWithTaxAndPenalties, then apply the selected dollar basis.
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.