Repository navigation
Give the saver's credit its 50% rate at negative AGI - #10541
Merged
Merged
Conversation
The first bracket of gov.irs.credits.retirement_saving.rate.joint started at $0, and a single-amount scale returns 0 below its first threshold, so savers_credit_potential was $0 for a negative adjusted gross income. The Form 8880 line 9 table's first row has no lower bound, and 26 U.S.C. 25B(b)(1) sets the rate only by "not over" amounts. The first threshold is now -.inf. Fixes #10538. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk
marked this pull request as ready for review
October 29, 2026 16:54
hua7450
approved these changes
Oct 29, 2026
hua7450
left a comment
Collaborator
There was a problem hiding this comment.
Approving at 81318db. Thanks, Pavel.
The fix is right. 26 U.S.C. 25B(b)(1)(A) gives 50 percent when AGI "is not over" the first amount, and the Form 8880 line 9 table's first row has no lower bound. With -.inf as the first threshold, negative AGI takes 50% for every filing status and every year in the parameter history. Nothing changes at AGI of zero or above. The new scale has no uprating block, so the -.inf threshold is never uprated. I recomputed the three new cases by hand, and they match.
Optional nits:
- Test header and PR body. Both say 25B(b)(1) sets the rate "only by 'not over' amounts", but (B) to (D) use "over $X but not over $Y" and "over $50,000". Only (A), the 50% row, has no lower bound. Suggested wording: "26 U.S.C. 25B(b)(1)(A) gives 50 percent when AGI 'is not over' the first amount, with no lower bound, so a negative AGI takes the 50% rate."
- Impact paragraph. "A return with negative AGI has no income tax for it to offset" holds in this model, but not in general. The credit can offset AMT, and AMTI can be positive when AGI is negative (incentive stock options, for example). Saying "in this model" would make it accurate.
- Case names. The new cases could use the "Case N, ..." form that
savers_credit_person.yamluses.
Follow-ups, outside this PR (all are the same on main):
qualified_retirement_savings_contributions.yamldrops ABLE contributions from 2026, although P.L. 119-21 sec. 70116 kept them. From 2027 the credit should cover only ABLE contributions (SECURE 2.0 sec. 103 moves the rest to the Saver's Match), with a $2,100 cap. Thejoint.yamlthresholds also have no uprating after 2026. If uprating is added, attach it to brackets 2 to 4 only, because Core's rounding raises on-inf.savers_credit_qualified_contributionssubtracts only the person's own distributions. On a joint return, 25B(d)(2)(D) and Form 8880 line 4 also count the spouse's distributions.- The bands are keyed at statutory amount + 1 and looked up on AGI / adjustment, so a fractional AGI less than $1 over a "not over" amount keeps the lower band's rate. With
-.infnow first, the bands could be keyed at the band tops with.calc(..., right=True).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #10538
Summary
gov.irs.credits.retirement_saving.rate.jointis a single-amount scale whose first threshold was $0.SingleAmountTaxScale.calcreturns 0 for a base below the first threshold, sosavers_credit_potential(Form 8880 line 10) was $0 when adjusted gross income was negative.The Form 8880 (2025) line 9 table's first row has no lower bound: "Over --- But not over $23,750: 0.5" for single filers, and the same in the other columns. 26 U.S.C. 25B(b)(1) also sets the rate only by "not over" amounts. This PR sets the first threshold to
-.inf, as other scales in the repo do (for examplegov/ed/student_loans/repayment_assistance_plan/base_payment/rate.yaml).Impact
Under current law the final
savers_credit(line 12) does not change. The credit is nonrefundable, and a return with negative AGI has no income tax for it to offset. The change shows insavers_credit_potentialand in any reform that makes the credit refundable or changes its limit.Tests
savers_credit_potential.yamlwith negative, just-below-zero and zero AGI cases. I put them in a new file because open PR Count only elective deferrals of self-employed plan contributions in the saver's credit #10129 editssavers_credit_person.yaml.policyengine-core test policyengine_us/tests/policy/baseline/gov/irs/credits: 728 passed.pytest policyengine_us/tests/test_federal_credit_limit_order.py: 17 passed.Found by the engine differential in emmilco/us-tax-model.
🤖 Generated with Claude Code