Display tax plus penalties annual
Settled tax plus early-withdrawal and RMD-shortfall penalties for the year, as the ledger surfaces print a single "Tax" figure.
Field: Tax plus penalties Unit: US dollars Basis: nominal dollars Computed by: UI transformation Status: Complete chain
Appears in: results-table (Tax column (y.tax + y.penalties)); report (year-ledger block taxAndPenalties and ReportPage year table); chart (Spending by category "Tax + penalties" series)
Calculation records
-
Tax plus penalties for the year Composition record, justified by derivation
Purpose: The single Tax figure the year-by-year table, the spending chart and the report print.
Statement: projection/yearFigures.ts#taxAndPenalties publishes YearResult.tax + YearResult.penalties for the year, in that order: the settled federal (regular, AMT and NIIT), state and any composed tax, plus the early-withdrawal penalty and the IRC 4974 excise. AMT is already inside tax. Units: nominal USD of the year. Rounding: none; the pages format to whole dollars.
Formula:
taxAndPenalties = tax + penalties-
tax: Settled tax of the year (YearResult.tax) (unit: usd per year) (domain: finite) -
penalties: Early-withdrawal penalty plus IRC 4974 excise (YearResult.penalties) (unit: usd per year) (domain: nonnegative)
Timing: annual
Rounding: none
Limits:
- None beyond those of tax and penalties, which their own records carry; the sum is written in the order the pages used, so the displayed figure did not change when it moved into the engine
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-tax-plus-penalties-annual.md Mutation receipt: display-tax-plus-penalties-annual.mutation.md
Evidence tests: yearFigures.evidence.test.ts
Implemented in: yearFigures.ts; result.ts
Is the number of: display-tax-plus-penalties-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 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 YearResult.tax and YearResult.penalties in projection/yearFigures.ts#taxAndPenalties, then apply the selected dollar basis on the Results page.
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.