Skip to content

Uprate HSA payroll contributions by the 223(b)(2) contribution limit - #10097

Merged
MaxGhenis merged 3 commits into
mainfrom
hsa-payroll-contribution-uprating
Oct 12, 2026
Merged

MaxGhenis merged 3 commits into
mainfrom
hsa-payroll-contribution-uprating

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

health_savings_account_payroll_contributions uprated by calibration.gov.hhs.cms.moop_per_capita, CMS per-capita out-of-pocket health spending. The NHEA methodology paper defines out-of-pocket spending as direct consumer spending on care, including payments covered by HSAs (file page 14). That counts withdrawals from accounts, not the contributions this input holds.

This PR:

  • Adds the 26 U.S.C. 223(b)(2) HSA contribution limits as parameters, with the IRS's values for 2004–2027.
  • Projects later years from the statute under 223(g).
  • Points the input at the family limit.
Per-person ×2034/2024
Before: moop_per_capita on main 1.4126
Before, with #10084's NHE refresh 1.5392
After: family HSA contribution limit 1.2530
Alternative considered: SOI employment income per capita 1.4196

What the data put in this input

Nothing. Microcosm (origin/main 909586128) never writes the column. It appears only in packages/microcosm-frame/tests/golden/concept-coverage/policyengine-us.json, under uncovered_inputs. The released populace_us_2024.h5 has no HSA column in its person table (319 columns in the newest HF snapshot 8ab57ffc, 318 in the certified 26dcad66), and no pre_tax_contributions column. Its only HSA input is the tax-unit health_savings_account_ald.

The series therefore applies in two places. The first is inputs entered for one year and calculated for another: core Simulation._calculate uprates any earlier input by index(period) / index(input period), read in policyengine-core 3.33.2 simulations/simulation.py. The second is extend_single_year_dataset, for any dataset that fills the column. Microcosm aggregates do not change.

Why the contribution limit

  • The law bounds the input. An employee's cafeteria-plan HSA contributions count toward the 223(b)(2) limit, and pe-us does not cap this input.
    • Following the limit keeps a contribution at the cap at the cap in every later year.
    • Following wages (4.07% a year) or out-of-pocket spending (3.98% a year) would push it past the legal limit within a year.
    • test_contributions_at_the_limit_stay_at_the_limit checks this in a simulation.
  • Contributions per account have grown with the limit, not with pay or health spending. Over 2015–2025:
Series 2015 2025 Growth a year
KFF EHBS average employer HSA contribution, single coverage $568 (2015 §8) $690 (2025 report, file page 149) 1.96%
KFF EHBS average employer HSA contribution, family coverage $991 $1,296 2.72%
HSA limits (this PR) $3,350 / $6,650 $4,300 / $8,550 2.54%
SOI employment income per capita (model) 4.07%
CMS out-of-pocket per capita (model, main) 3.98%
  • KFF surveyed employers with three or more workers in 2015 and ten or more in 2025 (2025 report, file page 15).
  • EBRI's HSA Database, from its 2011–2024 trends brief: "After adjusting for inflation, both employer and employee contributions were higher in the 2010s." Average contributions stay below the cap; the average combined contribution was $505 below the individual maximum in 2024 and $926 below it in 2022 (2011–2022 release).
  • The strongest point against the limit: EBRI's gap to the individual maximum shrank by $421 from 2022 to 2024 while the limit rose $500, so on that measure contributions grew faster than the limit over those two years. Over the decade, though, both KFF series sit near the limit's growth and far below wages and health spending, and EBRI finds real contributions lower than in the 2010s.
  • Why the family limit. Self-only and family limits share one adjustment and differ only in rounding. The family amount's $50 rounding is the smaller share of the amount, so its growth is closest to the 223(g) adjustment itself. A contribution at the self-only limit stays within $25 of it, which a test checks.

How the limits are projected

Values after the IRS's last publication come from extend_hsa_contribution_limits in uprating_extensions.py. It follows the existing statutory extensions such as extend_educator_expense_cap, computing each year from the base rather than chaining from the last rounded value:

  • The statutory $2,250 and $4,500 are increased by the 223(g) adjustment.
  • The adjustment is the 1(f)(3) cost-of-living adjustment with calendar year 1997 as the base, and with 1(f)(4) applied by substituting March 31 for August 31.
  • Each increase is rounded to the nearest multiple of $50, under 223(g)(2).
  • The statute text was read from Cornell LII and from axiom-corpus rows us/statute/26/223/g/1 and /g/2.

Averaging windows were checked against the IRS's own publications using the BLS series already in gov.bls.cpi:

Windows Published 2019–2027 self-only and family limits reproduced
C-CPI-U and 1997 CPI over 12 months ending March 31; 1(f)(3)(B) 2016 ratio over 12 months ending August 31 (this PR) 18 / 18
Same, with the 2016 ratio over March windows too 15 / 18
All August windows (cannot be published by 223(g)'s June 1 deadline) 4 / 16 (2019–2026)
March windows only in 1(f)(4), the literal reading 7 / 16 (2019–2026)

The adopted windows also give Rev. Proc. 2018-18's 2018 limits ($3,450 / $6,850). The parameter holds $6,900 for 2018 because Rev. Proc. 2018-27 let taxpayers use it. The extension had projected $4,500 / $9,000 for 2027 before Rev. Proc. 2026-24 published those values.

Unobserved months are interpolated toward CBO's calendar-year C-CPI-U points with the existing get_projected_cpi_u_for_month; observed C-CPI-U runs through June 2026. The extension adds about 0.1 s to system construction.

The new parameters declare uprating: gov.irs.uprating, with nearest-$50 rounding, as the educator expense cap does. The Trustees long-run reform (reforms/ssa/trustees_core_thresholds.py) wage-indexes every gov.irs parameter with that metadata after 2034, so it treats these limits like other CPI-indexed IRS amounts.

Invariants (tested)

tests/core/test_hsa_contribution_limits.py:

  1. Transcription: the parameters equal the IRS-published limits for 2004–2027. Each value is cited to the document and file page that states it.
  2. Differential: an independent 223(g) implementation, written in the test from monthly gov.bls.cpi values, reproduces every published limit for 2019–2027 and Rev. Proc. 2018-18's 2018 values. The model's get_hsa_cola equals it in every year whose window is observed.
  3. Extension rule (Hypothesis): every projected year through 2100 equals base + round₅₀(base × adjustment).
  4. Bounds and order (Hypothesis): both limits are positive multiples of $50 and never fall from one year to a later one, through 2100. |family − 2 × self-only| ≤ $50. The March-window index is positive in every year and rises in every projected year.

tests/microsimulation/test_hsa_payroll_contribution_uprating.py:

  1. Uprating is linear (Hypothesis, vectorized simulation): a 2024 contribution equals amount × family-limit ratio in any later year, and pre_tax_contributions subtracts that uprated amount.
  2. Bound: a contribution at the 2024 family limit equals the family limit in 2025, 2026, 2027, 2030, 2034, 2050 and 2100. One at the self-only limit stays within $25 of the self-only limit.
  3. Dataset extension: per-person amounts follow the limit ratio. The weighted total grows by the limit ratio times population growth: a gov.irs path is not a national total, so per_capita_uprating does not divide it.

tests/core/test_uprating_series.py now expects the family limit for this input. The methodology-page link test covers the new series.

Docs

docs-quarto/methodology/spm-poverty.qmd: HSA payroll contributions leave the sentence that lists the inputs following CMS out-of-pocket spending. A new sentence says they follow the family limit, and that the Microcosm data do not fill them.

Coordination

Axiom

axiom: us/statute/26/223/g TheAxiomFoundation/rulespec-us#1674 queued

  • rulespec-us us/statutes/26/223/b.yaml holds the $2,250 / $4,500 bases as constants from 1990 and has no 223(g) module.
  • The corpus rows for 223(g) are in the pinned release, but Rev. Proc. 2026-24's row is in a lock the release does not include yet.
  • The issue is dispatch-ready: module path, verbatim law, review_finding, and Rev.-Proc.-anchored companion tests. Signed encoder runs need Max's approval.

Tests run locally

226 passed:

  • tests/core/test_hsa_contribution_limits.py, test_uprating_series.py and test_per_capita_uprating.py
  • tests/microsimulation/test_hsa_payroll_contribution_uprating.py
  • tests/policy/contrib/ssa/test_trustees_core_thresholds.py

Local machine; CI covers the rest.

Evidence (Rev. Procs, statute captures, KFF/EBRI sources, window-convention script): ~/reviews/hsa-uprating-2026-10-11/.

🤖 Generated with Claude Code

MaxGhenis and others added 3 commits October 11, 2026 15:30
CMS per-capita out-of-pocket spending counts HSA withdrawals, not
contributions. Add the 26 U.S.C. 223(b)(2) self-only and family
contribution limits (2004-2026) and project them from the statute under
223(g): chained CPI-U over the 12 months ending March 31 against a 1997
base, rounded to the nearest $50. Point the payroll contribution input at
the family limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r once

Transcription, a differential test of an independent 223(g)
implementation against every published limit for 2018-2026, the
projection rule, and Hypothesis bounds and order. Simulation and dataset
extension tests check the input follows the family limit and that a
contribution at the cap stays at the cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every value 2004-2027 is cited to the IRS document and page that states
it. The statutory projection had already given $4,500 and $9,000 for
2027; the independent 223(g) test now covers 2018-2027.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis force-pushed the hsa-payroll-contribution-uprating branch from a141eed to e7ef37f Compare October 11, 2026 19:32
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 11, 2026 19:36
@MaxGhenis
MaxGhenis merged commit bee8954 into main Oct 12, 2026
33 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#10097 at e7ef37fa421962bee647ff34058b504b17343636 (squash): uprate HSA payroll contributions by the 26 U.S.C. 223(b)(2) contribution limit.

  • Adopted on 2026-10-12: Fleet ops found it ready with no session.
  • Review: independent GPT-6.1 Sol review APPROVE at this head. It checked all 48 published limits (2004–2027) and their IRS sources, reproduced the 223(g) projection, and confirmed the uprating applies per person. One wording point (a self-only contribution can sit $25 above the self-only limit, as the tests allow) is non-blocking.
  • Methodology ruling: the reviewer marked the choice of uprating series as a methodology choice. Max chose the family HSA contribution limit on 2026-10-12 (d1399), over wages and over the CMS out-of-pocket series on main. For $1,000 entered in 2024 and carried to 2034: $1,253 (family limit), $1,420 (wages), $1,413 (out-of-pocket).
  • Gates checked live at merge:
    • gh pr checks exits 0;
    • the latest Pull request run at the head concluded success;
    • MERGEABLE;
    • not a draft;
    • no reviewer's latest review requests changes;
    • the semantic-overlap guard;
    • head pinned.
  • Impact: none on microsimulation aggregates. The certified default dataset (sha256 6496cc4393d4…) has no HSA payroll contribution column; its only HSA input is health_savings_account_ald (hub check, 2026-10-12). The series applies to household and API inputs carried from one year to another.
  • Axiom: Encode 26 USC 223(g) indexation of the HSA contribution limits and the 2026–2027 Rev. Proc. amounts (PE-US #10097) TheAxiomFoundation/rulespec-us#1674, queued.

1 similar comment
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#10097 at e7ef37fa421962bee647ff34058b504b17343636 (squash): uprate HSA payroll contributions by the 26 U.S.C. 223(b)(2) contribution limit.

  • Adopted on 2026-10-12: Fleet ops found it ready with no session.
  • Review: independent GPT-6.1 Sol review APPROVE at this head. It checked all 48 published limits (2004–2027) and their IRS sources, reproduced the 223(g) projection, and confirmed the uprating applies per person. One wording point (a self-only contribution can sit $25 above the self-only limit, as the tests allow) is non-blocking.
  • Methodology ruling: the reviewer marked the choice of uprating series as a methodology choice. Max chose the family HSA contribution limit on 2026-10-12 (d1399), over wages and over the CMS out-of-pocket series on main. For $1,000 entered in 2024 and carried to 2034: $1,253 (family limit), $1,420 (wages), $1,413 (out-of-pocket).
  • Gates checked live at merge:
    • gh pr checks exits 0;
    • the latest Pull request run at the head concluded success;
    • MERGEABLE;
    • not a draft;
    • no reviewer's latest review requests changes;
    • the semantic-overlap guard;
    • head pinned.
  • Impact: none on microsimulation aggregates. The certified default dataset (sha256 6496cc4393d4…) has no HSA payroll contribution column; its only HSA input is health_savings_account_ald (hub check, 2026-10-12). The series applies to household and API inputs carried from one year to another.
  • Axiom: Encode 26 USC 223(g) indexation of the HSA contribution limits and the 2026–2027 Rev. Proc. amounts (PE-US #10097) TheAxiomFoundation/rulespec-us#1674, queued.

@MaxGhenis
MaxGhenis deleted the hsa-payroll-contribution-uprating branch October 12, 2026 01:33
MaxGhenis added a commit that referenced this pull request Oct 12, 2026
…wording

Keeps #10097's HSA sentence and series; the CMS out-of-pocket list now ends
with prescription expenses. Long-term care: the statute's index is for
August of the preceding year and CBO and CMS do not project it. Part B: a
growth proxy, not each person's premium. Trustees reference title carries
its file pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 12, 2026
#10097 moved health_savings_account_payroll_contributions to the family HSA
contribution limit, so it no longer uprates by moop_per_capita.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 13, 2026
…034 (#10084)

* Update CMS out-of-pocket per-capita uprater to NHE projections 2025-2034

Replace calibration.gov.hhs.cms.moop_per_capita with Table 3 of the
2025-2034 NHE projections (2018-2024 historical estimates, 2025-2034
projections), derive 2015-2017 from the historical accounts by the rule
that reproduces Table 3's 2018-2024 values, drop the hand-extended
2033-2035 values, and extend from 2034 at the 2033-2034 growth rate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Fix HSA variable name and limit rounding check to derived years

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Qualify the interval check's typo detection in its docstring

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Leave HSA payroll contributions out of the CMS series' input list

#10097 moved health_savings_account_payroll_contributions to the family HSA
contribution limit, so it no longer uprates by moop_per_capita.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant