Skip to content

Fix SNAP rounding for income limits and minimum allotment - #9162

Merged
hua7450 merged 4 commits into
mainfrom
fix-snap-rounding
Jul 28, 2026
Merged

Fix SNAP rounding for income limits and minimum allotment#9162
hua7450 merged 4 commits into
mainfrom
fix-snap-rounding

Conversation

@hua7450

@hua7450 hua7450 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

PolicyEngine compared unrounded income-to-poverty ratios against 1.3 / 1.0 and paid an unrounded minimum allotment. USDA rounds both: monthly income eligibility standards round up to the next whole dollar, and the minimum allotment rounds to the nearest whole dollar. Households at exactly the published limit therefore failed the tests in PolicyEngine and received $0 instead of a positive benefit.

Legal basis (verified against statute and regulation text)

Change Authority Verbatim rule
Gross income limit: ceil(1.3 × monthly FPG) 7 CFR 273.9(a)(3)(i) "130 percent of the annual income poverty guidelines shall be divided by 12 to determine the monthly gross income standards, rounding the results upwards as necessary."
Net income limit: ceil(monthly FPG) 7 CFR 273.9(a)(3)(ii) "The annual income poverty guidelines shall be divided by 12 to determine the monthly net income eligibility standards, rounding the results upward as necessary."
Minimum allotment: round(0.08 × one-person max) 7 CFR 273.10(e)(2)(ii)(C); 7 U.S.C. 2017(a) "The minimum benefit is 8 percent of the maximum allotment for a household of one, rounded to the nearest whole dollar."

The statute (7 U.S.C. 2014(c)) contains no rounding rule for the income standards; the regulation supplies it.

Verification against USDA published values

  • FY 2026, household of 3, 48 states: gross limit $2,888 (from $2,887.08), net limit $2,221 (from $2,220.83) — both now reproduced exactly.
  • Minimum allotment: FY 2025 $23 (8% × $292 = $23.36 rounds down) and FY 2026 $24 (8% × $298 = $23.84 rounds up) — pinning "nearest" in both directions; ceiling or flooring would each fail one year.
  • np.round half-to-even is safe here: 8% of an integer allotment always has a fractional part that is a multiple of $0.04, so an exact 50-cent tie cannot occur.
  • The limits pre-round to 4 decimals before the ceiling so float error on an exact whole-dollar standard (e.g., $2,600 for a household of 4 in FY 2025) cannot add a dollar.

Implementation notes

  • The income tests now compare monthly income against a rounded dollar limit instead of comparing unrounded ratios. snap_fpg stays unrounded because rounding does not commute with the 130% multiplication and snap_fpg also feeds BBCE.
  • The gross-test exemption for households with an elderly or disabled member is unchanged.
  • State minimum-allotment overrides (DC, MD, NJ) are unchanged.

Known limitations (documented, not fixed here)

  • FY 2023 minimum allotment is $22 in PolicyEngine vs USDA's published $23. USDA applies the statutory 8% to the unrounded thrifty food plan cost ($281.70 → $22.54 → $23), while this implementation applies the regulation's paraphrase to the rounded published maximum ($281 → $22.48 → $22). FY 2023 is the only year in FY 2019–2026 where the two bases diverge; matching it would require storing unrounded TFP costs.
  • Households of 9+: the regulation rounds the per-person increment separately before adding it to the eight-person standard; this implementation ceilings the total, which can be $1 stricter (e.g., 10-person FY 2026 gross limit $7,032 vs USDA $7,033).
  • BBCE (meets_tanf_non_cash_*) still compares unrounded ratios — same class of issue, left for a follow-up.

Test plan

  • Rewrote meets_snap_net_income_test.yaml to drive the formula through snap_net_income and snap_fpg (the ratio variable is no longer read by the formula but remains for BBCE).
  • Added boundary tests at the published FY 2026 limits for a 3-person Missouri household (non-BBCE state, monthly period), passing at the limit and failing $1 above.
  • Added synthetic round-up cases and the FY 2025/FY 2026 minimum-allotment nearest-dollar cases.
  • Changelog fragment included.

🤖 Generated with Claude Code

hua7450 and others added 2 commits July 27, 2026 23:06
Compare gross and net test income against the published whole-dollar
standards (130%/100% of the monthly poverty guideline, rounded up per
7 CFR 273.9(a)(3)) instead of unrounded FPG ratios, so households at
the published limits (e.g. $2,888/$2,221 for size 3 in FY2026) are
eligible. Round the minimum allotment (8% of the one-person maximum)
to the nearest whole dollar per 7 CFR 273.10(e)(2)(ii)(C), $23.84 ->
$24 in FY2026.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rewrite the net income test YAML to drive the formula through
snap_net_income and snap_fpg, add round-up boundary cases at the
published FY 2026 limits in a non-BBCE state (MO), and pin the
nearest-dollar minimum allotment in both directions (FY 2025 $23.36
down to $23, FY 2026 $23.84 up to $24).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (4c6ac7e) to head (74f045a).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9162   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            3         3           
  Lines           49        63   +14     
  Branches         0         3    +3     
=========================================
+ Hits            49        63   +14     
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 Harness.
📢 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.

The minimum allotment now rounds to the nearest whole dollar, so the
calendar-2026 stream for a 1-person unit is 9 x $24 + 3 x $25 = $291
instead of the unrounded $288.61. Update the work-requirement Case 2
pin and the two partner edge-case pins accordingly, and rewrite the
abolish_snap_net_income_test contrib test to drive the formula through
snap_net_income and snap_fpg instead of the retired ratio input.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hua7450
hua7450 marked this pull request as ready for review July 28, 2026 04:12
The md in_effect guard never evaluated False in any tested period,
leaving a partial branch in coverage. Pin the FY 2016 federal minimum
($15.52 rounding to $16) for a Maryland household before the state
supplement took effect on 2016-10-01.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hua7450
hua7450 merged commit 3c41c31 into main Jul 28, 2026
34 checks passed
@hua7450
hua7450 deleted the fix-snap-rounding branch July 28, 2026 16:39
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