Calculation catalog › Cash flow and summary

Income pension annual

Pension income paid in a projection year.

Field: Pension income Unit: US dollars Basis: nominal dollars Computed by: Engine Status: Complete chain

Appears in: chart (pension); csv (pension); scenarios-page (Lifetime income "Pension"); cash-flow-drilldown (pension source line)

Calculation records

  • Annual pension income, with COLA and survivor continuation Model record, justified by derivation

    Purpose: What a pension pays in a projection year, including the share a surviving spouse keeps.

    Statement: projection/internal/annualPensionAndAnnuityIncome.ts#annualPensionAndAnnuityIncome pays a pension from the owner's startAge onward (the owner the plan names, required on every pension since schema v7; guaranteed-income-owner) as monthlyAmount x 12 compounded by its annual COLA over the years since the start age, and publishes it as projection/internal/types/result.ts#YearResult.incomes.pension. While the owner is alive the full amount pays; after the owner dies it continues to a surviving household member at survivorPct/100 of that full amount, and stops when no survivor is alive. A pension commuted by a lump-sum election pays nothing. Units: nominal USD per year. Rounding: none.

    Formula: full = monthlyAmount * 12 * (1 + colaPct/100)^(age - startAge); paid = full while the owner lives, full * survivorPct/100 to a survivor after the owner dies

    • monthlyAmount: Monthly pension at the start age (unit: usd/month) (domain: nonnegative)
    • colaPct: Annual cost-of-living adjustment (unit: percent/year) (domain: 0 is a fixed-nominal pension)
    • age - startAge: COLA years elapsed since payments began (unit: years) (domain: integer at or above 0)
    • survivorPct: Percent of the benefit continuing to a surviving spouse (unit: percent) (domain: 0..100)

    Timing: income pass 2, once per projection year

    Rounding: none

    Limits:

    • Asserted on a real simulatePlan run over 2028-2030. Plan assumptions beyond the worksheet's inputs: a two-person household filing jointly in KY with a zero state rate, zero inflation and zero account returns, the owner's planning age set to 65 so the run's own longevity makes them dead from 2029 on, and the survivor's planning age set to 95 so the survivor continuation is the only thing being read
    • The COLA count is driven by the owner's would-be attained age, not by whether they are alive: the survivor keeps a benefit that has continued to compound
    • A lump-sum election is a separate path this record does not price; the test’s pension carries no election

    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: income-pension-annual.md Mutation receipt: income-pension-annual.mutation.md

    Evidence tests: annualPensionAndAnnuityIncome.evidence.test.ts

    Implemented in: annualPensionAndAnnuityIncome.ts; result.ts

    Is the number of: income-pension-annual

    Feeds: income-total-annual

Records that feed this number

  • Whose age and life a pension or annuity is paid on Model record, justified by derivation

    Purpose: Every pension and annuity names its owner, and the income is timed and ended on that person, never on whoever is listed first.

    Statement: Every pension and annuity names its owner (schema v7, decision D-PEOPLE-ORDER, rule R2): a pension's participant, an annuity's (first) annuitant. model/planCrossFieldChecks.ts refuses one with none, a qualified annuity purchase named for anyone but the owner of the traditional account that paid for it (except the surviving spouse once that owner's planning age has ended by the purchase year, IRC 402(c)(9) and 408(d)(3)(C)(ii)(II)), an annuity bought for a person whose planning age has ended by its purchase year (it would never pay), and a pension lump sum rolled into another person's account. projection/internal/annualPensionAndAnnuityIncome.ts#annualPensionAndAnnuityIncome reads that owner through model/plan.ts#guaranteedIncomeOwnerId (which refuses an owner-less account rather than reading the first person): payments start in the owner's birth year plus startAge (not before a purchase year), a pension pays in full while the owner lives and survivorPct/100 to the other household member after, and an annuity pays by its payout form on the owner's life and the other member's (the second annuitant). The pre-start contract value (simulate.ts), the runtime source-series check (internal/ownedNonRothIraRuntimeSourceSeries.ts), the late-start warning, the pension election and the Scenarios levers read the same owner. Plans saved before v7 are given the funding account's owner for a qualified purchase (the surviving spouse after that owner's death), else the person then listed first, never a person dead at the purchase, and the load says so. Every stored plan still opens (the independent review's N1): a purchase of any kind whose annuitant has died by its purchase year is given the other person when that person is alive then, the only one who could have bought it, and is removed, its premium kept where it was, when nobody is; the load says the figures change. Units: calendar years; nominal USD per year. Rounding: none.

    Formula: owner = account.ownerPersonId (required); firstYear = max(birthYear(owner) + startAge, purchase.year); pension: full while owner alive, full * survivorPct/100 to the other after; annuity: full * payoutFraction(form, ownerAlive, otherAlive)

    • owner: The participant or first annuitant the plan names (unit: person id) (domain: a household person)
    • startAge: The owner's age at the first payment (unit: years) (domain: integer)

    Timing: income pass 2, once per projection year

    Rounding: none

    Limits:

    • The joint-and-survivor form reduces on the owner's death only (the contingent form); a form that reduces on the first death of either would be a new payout form, not an owner value
    • Statute and regulation name the lives (irc-72-c-3-A-annuity-measured-on-named-lives); the rule that a qualified contract belongs to the funding account's owner is the IRA's exclusive benefit (IRC 408(a), 408(b)) and the QLAC's employer-or-IRA-owner purchase (Treas. Reg. 1.401(a)(9)-6(q)(1), 1.408-8(a)(3))
    • The annuitization insight, the Monte Carlo annuity sweep and the SPIA candidates name no owner in the plan, so they are written on the person model/peopleOrder.ts#canonicalFirstPerson puts first (the older; between two people born the same day, the sex order female, male, average and then the smaller id by ordinal comparison decide, so for two people with the same birth date and sex renaming the ids can move the annuitant and every figure on that life), whoever is listed first, and each names that person

    Provenance: derived by claude, implemented by claude.

    Independent review: codex

    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: guaranteed-income-owner.md Mutation receipt: guaranteed-income-owner.mutation.md

    Evidence tests: peopleNamed.evidence.test.ts

    Implemented in: plan.ts; planCrossFieldChecks.ts; annualPensionAndAnnuityIncome.ts

    Feeds: income-pension-annual, income-annuity-annual

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

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.