Calculation catalog › Cash flow and summary

Year result contributions

Employee and household dollars contributed to investment accounts during the projection year.

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

Appears in: csv (contributions); results-table (Contrib. column); report (year-ledger block contributions and ReportPage year table); cash-flow-drilldown (contribution use and employeeContribution transfer lines)

Calculation records

  • Annual contributions credited after limit trimming Formula record, justified by derivation

    Purpose: How much of the desired contribution each owner is actually allowed to put in.

    Statement: projection/internal/types/result.ts#YearResult.contributions, planned by projection/internal/annualContributionsAndEmployerMatch.ts#annualContributionsAndEmployerMatch, sums the contributions actually credited after each desired amount is trimmed to its applicable group limit and to compensation. A jointly owned account's desired amount follows joint-account-contributions. The IRA limit in params/data/year2026.ts#year2026 is 7,500 for 2026, shared per owner across that owner's traditional and Roth IRAs, with a separate age-50 catch-up only when applicable. Units: nominal USD per year. Rounding: none.

    Formula: contributions = sum over owners and accounts of min(desired, group limit, compensation)

    • desired: Plan annual contribution for the account (unit: usd/year) (domain: nonnegative)
    • group limit: Per-owner IRA limit plus any applicable catch-up (unit: usd/year) (domain: 7,500 for 2026)
    • compensation: Owner wages available to support the contribution (unit: usd/year) (domain: nonnegative)

    Timing: once per projection year, after wages land

    Rounding: none

    Limits:

    • Asserted as the published field of a real simulatePlan 2026 row built from the worksheet's inputs: two owners aged 40 and 45 with one traditional IRA each, desired 6,000 and 9,000, wages 50,000 each, and zero general inflation. Plan assumptions beyond the worksheet's inputs: the household files jointly in KY at a zero state rate, both IRAs open at a zero balance with zero returns, there are no other accounts and no spending, and the 2026 IRA limit is read from the published parameters rather than written into the test
    • Both owners are under 50, so the test isolates the base limit and evidences no catch-up band

    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: year-result-contributions.md Mutation receipt: year-result-contributions.mutation.md

    Evidence tests: simulate.evidence.test.ts

    Implemented in: result.ts; annualContributionsAndEmployerMatch.ts

    Is the number of: year-result-contributions

    Feeds: surplus-invested-annual, cash-flow-reconciliation-totals

Records that feed this number

  • HSA contribution limits by year Data record, justified by derivation

    Purpose: Hold each year's HSA contributions to the self-only and family limits the IRS publishes for that year, and grow only the years after the latest published one.

    Statement: params/hsaLimitYears.ts#hsaLimitsForYear returns the published IRC 223(b)(2) base limits for a calendar year: 4,400 self-only and 8,750 family for 2026 (Rev. Proc. 2025-19), and 4,500 and 9,000 for 2027 (Rev. Proc. 2026-24 section 3.01(1)). projection/simulate.ts#simulatePlan reads them for each year at a scale of exactly 1 when the year is published, so 2027 is read as published although its income tax figures are still projected from 2026. A year after the latest published one grows from that year at the plan inflation path. A year before the earliest gets the earliest published limits, unscaled and flagged as a stand-in, a year no plan reaches, since the examples are pinned to 2026 and a user's plan starts in the clock's year. projection/internal/annualContributionsAndEmployerMatch.ts#annualContributionsAndEmployerMatch holds each owner's HSA contributions to that base (the family base halved between two spouses filing jointly, the model's default division) plus the flat 1,000 dollar age-55 catch-up, which is not scaled. Units: nominal USD per year. Rounding: none; the projected years do not reproduce the statute's rounding to a multiple of 50 dollars.

    Formula: limit(Y) = base(Y) x g(Y) + catchUp; base(Y) = published block for Y, else the latest block before Y (or the earliest after it); g(Y) = 1 for a published Y and for Y before the earliest block, else inflation from the latest block year to Y

    • Y: Contribution year (unit: year) (domain: integer)
    • base(Y): Self-only amount, or the family amount (halved between two spouses filing jointly, the model's default division) (unit: usd/year) (domain: positive)
    • g(Y): Cumulative plan inflation from the latest published year to Y (unit: ratio) (domain: positive; 1 for a published year)
    • catchUp: IRC 223(b)(3)(B) additional amount at age 55 or older (unit: usd/year) (domain: 0 or 1,000)

    Timing: once per projection year, when contributions are credited

    Rounding: none

    Limits:

    • Years after the latest published limits (2028 and later today) are projected at the plan inflation path, not the C-CPI-U of section 1(f)(3), and without the rounding to a multiple of 50 dollars under section 223(g)(2)
    • The coverage tier, the monthly eligibility and Medicare entitlement are not modeled; irc-223-b-2-7-projection-coverage-proration-and-medicare carries those shortcuts
    • The 2027 high deductible health plan minimum deductibles (1,750 and 3,500) and out of pocket limits (8,700 and 17,400) in the same revenue procedure are not read by any calculation
    • Two spouses' family base is divided equally, the model's default: IRC 223(b)(5)(B)(ii) divides it equally unless the spouses agree on a different division, which the plan cannot state, so an agreed split such as 9,000 and 0 keeps the household total but not the owner limits

    Provenance: derived by claude, implemented by claude-subagent.

    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: hsa-contribution-limit-years.md Mutation receipt: hsa-contribution-limit-years.mutation.md

    Evidence tests: hsaLimitYears.evidence.test.ts

    Implemented in: hsaLimitYears.ts; simulate.ts; annualContributionsAndEmployerMatch.ts

    Feeds: year-result-contributions

  • When a jointly owned account takes contributions Model record, justified by derivation

    Purpose: A joint cash, brokerage or equity-compensation account belongs to the household, so its contributions follow the household, never the first-listed person.

    Statement: projection/internal/annualContributionsAndEmployerMatch.ts#annualContributionsAndEmployerMatch gives a jointly owned (ownerPersonId null) cash, taxable or equity-compensation account its desired contribution while anyone in the household is alive (decision D-PEOPLE-ORDER, rule R3): its plain annualContribution x the year's inflation factor while the household has wages (the sum of the living people's wages is above 0), and its contributionSchedule by the attained age of the person contributionScheduleAgeOf names (the only person in a one-person plan), with no wage test, as for any schedule outside an employer plan; the schedule keeps that person's age after that person dies. An owned account follows its owner's life, wages and age as before. Schema v7 requires contributionScheduleAgeOf on a joint account with a schedule in a two-person plan and refuses it on an owned one; plans saved earlier are given the person then listed first. Pat (1966, no wages from 2026, alive through 2028) and Robin (1970, wages through 2033) put 6,000 a year into a joint account from 2026 through 2033, 48,000, where the first-person rule stopped at Pat's wages. Units: nominal USD per year. Rounding: none.

    Formula: joint and anyone alive: desired = schedule(age of contributionScheduleAgeOf) if scheduled, else annualContribution * inflFactor if sum(living wages) > 0, else 0

    • sum(living wages): The household's wages this year (unit: nominal USD) (domain: nonnegative)
    • age: Attained age of the named person (unit: years) (domain: integer)

    Timing: once per projection year, after wages land

    Rounding: none

    Limits:

    • No statute governs contributions to a taxable or cash account; this is the program's rule, and it reads the facts (anyone alive, household wages) rather than list order
    • In a year the household runs a deficit the ledger funds a contribution by withdrawing, so a contribution can move tax and net worth, not only the account it lands in
    • The Scenarios levers mirror the rule (planner-ui scenarioLevers.ts receivesContributionDuringProjection)

    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: joint-account-contributions.md Mutation receipt: joint-account-contributions.mutation.md

    Evidence tests: peopleNamed.evidence.test.ts

    Implemented in: annualContributionsAndEmployerMatch.ts

    Feeds: year-result-contributions

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

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.