Calculation catalog › Taxes

Scenario lifetime penalties

Sum of penalties over the projection.

Field: Lifetime penalties Unit: US dollars Basis: nominal dollars Computed by: Engine Status: Complete chain

Appears in: scenarios-page (Headline "Lifetime penalties")

Calculation records

  • Scenario lifetime tax and penalties Composition record, justified by derivation

    Purpose: Total each scenario side's annual tax and annual penalties as two separate channels.

    Statement: scenarios/comparison.ts#compareScenarioPlans separately sums nominal annual YearResult.tax and YearResult.penalties for each scenario side, then places each baseline/proposal total in its comparison cell without mixing the two channels.

    Formula: lifetimeTax_s = sum over years y of tax_{s,y}; lifetimePenalties_s = sum over years y of penalties_{s,y}

    • tax_{s,y}: Side s, year y published tax (unit: nominal USD) (domain: nonnegative)
    • penalties_{s,y}: Side s, year y published penalties (unit: nominal USD) (domain: nonnegative)

    Timing: every projection year of each side

    Rounding: none stated

    Limits:

    • Penalties are excluded from tax by the result-type contract, so folding them into the tax channel changes both totals, and the delta belongs to the separate comparison-cell identity rather than to these side totals. The worksheet's annual tax and penalty rows for both sides are supplied as ProjectionResult literals at the simulate seam; the aggregation and the comparison assembly are the real functions.

    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: scenario-lifetime-tax-and-penalties.md Mutation receipt: scenario-lifetime-tax-and-penalties.mutation.md

    Evidence tests: comparisonCells.evidence.test.ts

    Implemented in: comparison.ts

    Is the number of: scenario-lifetime-tax, scenario-lifetime-penalties

    Feeds: scenario-comparison-cell

Records that feed this number

  • 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 by claude.

    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: 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

Engine source: engine/src/scenarios/comparison.ts (ScenarioHeadlineComparison.lifetimePenalties (sum of YearResult.penalties))

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.