Skip to content

Cap 401(k) and 403(b) contributions at the IRC §402(g) elective deferral limit#8391

Merged
MaxGhenis merged 1 commit into
mainfrom
enforce-401k-elective-deferral-limits
May 24, 2026
Merged

Cap 401(k) and 403(b) contributions at the IRC §402(g) elective deferral limit#8391
MaxGhenis merged 1 commit into
mainfrom
enforce-401k-elective-deferral-limits

Conversation

@MaxGhenis
Copy link
Copy Markdown
Contributor

@MaxGhenis MaxGhenis commented May 23, 2026

Summary

  • Adds traditional_401k_contributions_desired, roth_401k_contributions_desired, traditional_403b_contributions_desired, and roth_403b_contributions_desired as new pre-cap input variables.
  • Converts the four canonical *_contributions variables into formulas that proportionally scale the desired amounts when the combined total exceeds the §402(g) limit (base + age-based catch-up, including SECURE 2.0 ages 60-63).
  • Adds helper variables elective_deferral_limit, elective_deferrals_desired, and elective_deferral_scale_factor.
  • Updates policyengine_us/tools/default_uprating.py so the default dollar uprating attaches to the new _desired inputs.
  • Adds a YAML test suite covering pass-through, proportional scaling, age 50 catch-up, ages 60-63 super catch-up, age 64 revert, zero contributions, 401(k)/403(b) sharing the limit, and direct overrides of the canonical variable.

Fixes #8386.
Fixes #8390.

Design note

PR #8263 moved away from _reported shortcuts as a generic data-vs-model split. The pattern here is semantically different: _desired is the pre-cap intended amount versus the legally allowable amount. The canonical variable name remains the post-cap value that downstream code consumes, so callers that aggregate traditional_401k_contributions (e.g., pre_tax_contributions, savers_credit_qualified_contributions) are unaffected.

Direct overrides of traditional_401k_contributions (or any other canonical variant) still bypass the cap — preserving backward compatibility for any existing API caller or test that sets the post-cap value directly. Survey microdata should migrate to the _desired inputs to opt into capping; this PR does not change the microdata wiring.

Followups

Test plan

  • uv run policyengine-core test policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_cap.yaml -c policyengine_us — 9/9 pass
  • Existing tests still pass: irs_employment_income.yaml, savers_credit_*.yaml, test_fica_wage_base_excludes_401k.yaml, additional_medicare_tax.yaml (22 cases)
  • CI green on push

🤖 Generated with Claude Code

@codecov
Copy link
Copy Markdown

codecov Bot commented May 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (92fdab8) to head (6e34707).
⚠️ Report is 63 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##              main     #8391    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files            2        17    +15     
  Lines           57       177   +120     
  Branches         1         0     -1     
==========================================
+ Hits            57       177   +120     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@MaxGhenis
Copy link
Copy Markdown
Contributor Author

Companion data-side PR: PolicyEngine/policyengine-us-data#1122 — re-routes the CPS imputation pipeline to write traditional_401k_contributions_desired / roth_401k_contributions_desired so the cap formulas in this PR take effect in microsimulation.

@MaxGhenis MaxGhenis force-pushed the enforce-401k-elective-deferral-limits branch from fa35a77 to 4264fd5 Compare May 24, 2026 04:16
@MaxGhenis MaxGhenis force-pushed the enforce-401k-elective-deferral-limits branch from 4264fd5 to 6e34707 Compare May 24, 2026 04:57
@MaxGhenis MaxGhenis merged commit 3ded143 into main May 24, 2026
26 checks passed
@MaxGhenis MaxGhenis deleted the enforce-401k-elective-deferral-limits branch May 24, 2026 05:45
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.

Apply SECURE 2.0 enhanced catch-up (ages 60-63) to actual contributions Enforce 401(k) and 403(b) elective deferral limits (IRC §402(g))

1 participant