Calculation catalog › Medicare and ACA

Medicare premiums annual

Total Medicare premiums charged to the household during the projection year.

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

Appears in: scenarios-page (Total Medicare premiums); scenarios-page (Annual ledger comparison "Medicare premiums" and lifetime "Total Medicare premiums" sum); survivor-page (SSA-44 premium savings column (difference of two runs of this value)); mcp (run_projection.years[].medicarePremiums)

Calculation records

  • Medicare base Part B premium Data record, justified by derivation

    Purpose: Annualize the standard Part B premium for a covered person at tier 0.

    Statement: tax/medicare.ts#medicareAnnualPremiumPerPerson publishes the 2026 standard Part B premium per Medicare-covered person as year2026.medicare.partBStandardMonthly times twelve, with no Part D surcharge and no IRMAA surcharge at tier 0. Units: nominal USD per person per year. Rounding: none stated.

    Formula: partBAnnual = partBMonthly(tier) x premiumScale x 12; at tier 0 partBMonthly = base

    • base: year2026.medicare.partBStandardMonthly (unit: usd/person/month) (domain: positive)
    • partBMonthly(tier): The standard premium at tier 0; above it, CMS's published tier total (medicare-irmaa-first-tier-boundary) (unit: usd/person/month) (domain: positive)
    • premiumScale: Healthcare-inflation scale to the premium year, from the latest year CMS has published (unit: 1) (domain: positive; 1 in a year CMS has published)

    Timing: one premium year, per covered person

    Rounding: none stated

    Limits:

    • Per person, not per household: a two-person Medicare year charges this twice
    • The Part D out-of-pocket threshold the published parameters also carry is not a premium and never enters this figure
    • Restated 2026-09-28 under decision D-2027-ROLLOVER: the premium scale runs from the year of the latest CMS publication (params/index.ts#componentPackView), not the year of the whole set of published figures, so a year whose Medicare premiums CMS has published reads them at a scale of 1 while its other figures may still be projected. Until CMS publishes 2027 the scale from 2026 is exactly the one used before

    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: medicare-base-part-b-premium.md Mutation receipt: medicare-base-part-b-premium.mutation.md

    Evidence tests: medicare.evidence.test.ts

    Implemented in: medicare.ts; index.ts

    Is the number of: medicare-premiums-annual, irmaa-surcharge-annual

    Feeds: spending-healthcare-annual

  • Medicare IRMAA tier premiums and the first-tier boundary Formula record, justified by derivation

    Purpose: Price each IRMAA tier at the premiums CMS publishes, and the cliff at the first threshold on both sides of the same dollar.

    Statement: tax/medicare.ts#medicareAnnualPremiumPerPerson applies the 2026 single-filer first IRMAA tier only when two-year-lookback MAGI is strictly greater than the tier's magiOver (the top tier when it is at or above its floor), then prices Part B at CMS's published total monthly premium for the tier (params/data/year2026.ts, irmaaTiers[i].partBTotalMonthly: 284.10, 405.80, 527.50, 649.20 and 689.90 dollars for 2026) and adds CMS's published monthly Part D amount (14.50, 37.50, 60.40, 83.30 and 91.00). The table is read as published, not re-derived as the standard premium times the applicable percentage over 25, which CMS applies to the unrounded actuarial rate and which misses four of the five totals by cents. The IRMAA-only surcharge is the Part B amount above standard plus the Part D amount. A year after the latest CMS publication grows the latest published figures by the Medicare component's projection factor (cmsMedicare), as the standard premium grows. At 109,001 of single MAGI Part B is 3,409.20 a year and the IRMAA-only surcharge 1,148.40. Units: nominal USD per person per year, and an integer tier. Rounding: none; the published figures are whole cents.

    Formula: tier = 1 when MAGI > magiOver (the top tier when MAGI >= its floor); partBMonthly = partBTotalMonthly(tier) x premiumScale, standard at tier 0; irmaaSurchargeAnnual = max(0, partBMonthly - base x premiumScale) x 12 + partDSurchargeMonthly x premiumScale x 12

    • MAGI: Two-year-lookback MAGI (unit: usd/year) (domain: nonnegative)
    • magiOver: First-tier floor, year2026.medicare.irmaaTiers[0].magiOver for the filing status (unit: usd/year) (domain: positive)
    • partBTotalMonthly(tier): CMS's published total monthly Part B premium for the tier, full Part B coverage (unit: usd/person/month) (domain: above base)
    • base: year2026.medicare.partBStandardMonthly (unit: usd/person/month) (domain: positive)
    • partDSurchargeMonthly: CMS's published Part D income-related monthly adjustment for the tier (unit: usd/person/month) (domain: nonnegative, or null when unverified)
    • premiumScale: Healthcare-inflation scale to the premium year from the latest year CMS has published (unit: 1) (domain: positive; 1 in a year CMS has published)

    Timing: one premium year, per covered person

    Rounding: none; the published figures are whole cents

    Limits:

    • The tier totals are CMS's published figures, not the standard premium times the applicable percentage over 25 (284.06 against 284.10 at the 2026 first tier); reading the percentage as a surcharge on the standard premium (35% as standard plus 35%) understates every tier further
    • A year after the latest CMS publication is projected: it grows the latest published totals and Part D amounts by the Medicare component's factor, a stand-in for CMS's next table, which re-derives every tier from a new actuarial rate
    • The lower tiers use a strict greater-than test and only the top tier is inclusive; that asymmetry is the module's own stated convention
    • A tier whose Part D surcharge is unpublished sets partDSurchargeUnverified rather than inventing a figure; every 2026 tier's is published
    • The table is the full-Part-B-coverage table for single and joint filers; the separate tables for married people filing separately who lived with their spouse, and for immunosuppressive-drug-only coverage, are not read

    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: medicare-irmaa-first-tier-boundary.md Mutation receipt: medicare-irmaa-first-tier-boundary.mutation.md

    Evidence tests: medicare.evidence.test.ts

    Implemented in: medicare.ts; year2026.ts

    Is the number of: medicare-premiums-annual, irmaa-surcharge-annual

    Feeds: spending-healthcare-annual

Records that feed this number

  • IRMAA lookback MAGI selection Model record, justified by derivation

    Purpose: Choose which calendar year's MAGI, and from which source, prices a premium year's IRMAA.

    Statement: projection/internal/annualHealthcareExpenses.ts#annualHealthcareExpenses resolves premium-year IRMAA MAGI from year minus two, except that an active SSA-44 life-changing event selects year minus one only when it is strictly lower; a tie retains year minus two and its source. For lookback years before the projection ledger, projection/simulate.ts#simulatePlan resolves them through its own resolveMagiFor closure, which falls back to the plan's matching historicalAnnualMagiByYear entry, then to its coarse recentAnnualMagi stand-in, and publishes which arm supplied the figure. Units: calendar years, nominal USD and a source enum. Rounding: none; the selection performs no numerical approximation.

    Formula: primary = resolveMagiFor(y - 2); selected = ssa44(y) and resolveMagiFor(y - 1).magi < primary.magi ? resolveMagiFor(y - 1) : primary

    • y: Premium year being priced (unit: year) (domain: integer)
    • primary.magi: Ledger or fallback MAGI for year minus two (unit: usd/year) (domain: nonnegative)
    • ssa44(y): Whether an SSA-44 life-changing event is active in y (unit: boolean) (domain: true or false)

    Timing: once per premium year

    Rounding: none

    Limits:

    • The comparison is strictly lower, so equal MAGIs keep the ordinary two-year year; reading it as always selecting year minus one under SSA-44 changes the tie case
    • The planFallback arm is the coarse recentAnnualMagi stand-in, published as evidence of which arm answered rather than as evidence of the household's income
    • The selection is asserted two ways: the three SSA-44 branches through annualHealthcareExpenses with resolveMagiFor supplied at its documented injection point, and the two first-year fallback arms through a real simulatePlan run that publishes irmaaLookbackMagi, its source and its year. The fallback resolver is a closure inside simulatePlan rather than a module-scope symbol, so the pin names the exported function that owns it

    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: irmaa-lookback-selection.md Mutation receipt: irmaa-lookback-selection.mutation.md

    Evidence tests: annualHealthcareExpenses.evidence.test.ts

    Implemented in: annualHealthcareExpenses.ts; simulate.ts

    Feeds: irmaa-surcharge-annual, medicare-premiums-annual, survivor-scenario-row-ssa44premium-savings

  • Medicare IRMAA two-year lookback Data record, justified by derivation

    Purpose: Name which calendar year's MAGI a premium year reads.

    Statement: tax/medicare.ts#medicareAnnualPremiumPerPerson selects an IRMAA tier for a premium year from MAGI two calendar years prior, so 2026 premiums use 2024 MAGI rather than current-year or prior-year MAGI. The rule is a timing selector, not a MAGI forecast: the caller resolves the figure and the module names its input magiTwoYearsPrior. Units: calendar years and nominal USD. Rounding: none.

    Formula: lookbackYear = premiumYear - 2; tier = tierFor(magi[lookbackYear])

    • premiumYear: Year the premium is charged (unit: year) (domain: integer)
    • magi[y]: Ledger MAGI for calendar year y (unit: usd/year) (domain: nonnegative)

    Timing: once per premium year

    Rounding: none

    Limits:

    • The two-year offset is the ordinary rule; an active SSA-44 life-changing event can substitute the year-minus-one figure when it is lower, which is the separate irmaa-lookback-selection record
    • The module takes the already-resolved lookback figure, so this record pins which year the caller must hand it, not how that year's MAGI was computed

    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: medicare-irmaa-two-year-lookback.md Mutation receipt: medicare-irmaa-two-year-lookback.mutation.md

    Evidence tests: medicare.evidence.test.ts

    Implemented in: medicare.ts

    Feeds: medicare-premiums-annual, irmaa-surcharge-annual

  • Ledger MAGI composition Composition record, justified by derivation

    Purpose: Publish the five-term annual MAGI the IRMAA lookback and the ACA credit both read.

    Statement: projection/internal/types/result.ts#YearResult.magi publishes max(0, ordinary income realized + realized gains + qualified dividends + taxable Social Security + tax-exempt interest); projection/internal/annualFundingApplicationAndClosePhase.ts#annualFundingApplicationAndClosePhase is the site that computes it and writes the year into magiHistory. Untaxed Social Security is not a separate add-back, and foreign income enters only indirectly through taxable-Social-Security provisional income. Units: nominal USD. Rounding: none; the only transformation is the zero floor.

    Formula: magi = max(0, ordinaryRealized + gainsRealized + qualifiedDividends + taxableSs + taxExemptInterest)

    • ordinaryRealized: Ordinary income realized this year, the carryforward netting's ordinaryAfter (unit: usd/year) (domain: nonnegative; the netting floors it at zero)
    • gainsRealized: Signed net capital gain after carryforward netting (unit: usd/year) (domain: at or above minus the annual ordinary-offset limit)
    • qualifiedDividends: Qualified dividends realized this year (unit: usd/year) (domain: nonnegative)
    • taxableSs: Taxable share of Social Security under section 86 (unit: usd/year) (domain: nonnegative)
    • taxExemptInterest: Federally tax-exempt interest realized this year (unit: usd/year) (domain: nonnegative)

    Timing: once per projection year, in the funding-and-close phase

    Rounding: none

    Limits:

    • Asserted on real simulatePlan runs rather than at a seam. The positive case is a real plan whose single year realizes all five terms exactly as the worksheet states them (a recurring ordinary stream, a one-time capital-gain income, a taxable account whose wholly qualified dividend yield and municipal sleeve carry the third and fifth terms, and a Social Security benefit sized so that section 86 makes exactly the fourth taxable, with cost basis equal to balance so nothing else can realize a gain), and the published magi is checked against that year's own published components
    • The floor case is the only negative sum the ledger can reach: a deductible capital loss on the capital line with nothing else realized, because the ordinary-income term is applyCapitalLossCarryforward's ordinaryAfter and is floored at zero. The worksheet's first floor case gave ordinary income realized as minus 10,000, which that floor rules out; it was re-derived on the reachable path (a 20,000 carryforward carried into a year that realizes nothing else deducts the 3,000 annual limit on the capital line) and re-checked, and the test builds that year and checks each of the five terms and the published magi against the worksheet's inputs

    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: medicare-magi-composition.md Mutation receipt: medicare-magi-composition.mutation.md

    Evidence tests: annualFundingApplicationAndClosePhase.evidence.test.ts

    Implemented in: result.ts; annualFundingApplicationAndClosePhase.ts

    Is the number of: magi-annual

    Feeds: irmaa-surcharge-annual, medicare-premiums-annual

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

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.