Repository navigation
Conversation
- Switch on the senior and disabled medically needy flags for AR, IA, IL, NJ and ND. - Add medicaid_medically_needy_income_limit, which applies a share of the poverty guideline (IL, MN, ND, NY, UT, WI) or of the SSI federal benefit rate (KS, WA) in place of a dollar limit; Washington applies its one-person limit to couples. - Update dollar limits in CT, DC, NH, RI and NY (2022), and asset limits in CA, IL and NY. Closes PolicyEngine#10357 Closes PolicyEngine#10358 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rences - Year-keyed cases pin every dated CT, DC, NH, RI, NY, MN, ND and WI income limit; cases sit exactly at the IL, ND, CA and NY limits, with CA one dollar over, CA 2024 without a limit, and couples at the NY, CA and IL couple asset limits. - NJ and CA cases use incomes above the optional ABD pathway. - Disabled adults in AR, IA, IL, ND and NJ are in a medically needy category. - Arkansas spend down in cents (108.33 / 216.66, DHS quick reference). - Fix NY GIS 22 MA/11 and RI 210-RICR-40-00-3 titles, the RI section, the KS F-8 page; cite 305 ILCS 5/5-2 and Welf. & Inst. Code 14005.62. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PIL outside Chittenden County, the same for one and two people, each January 1 (HBEE 8.06(b), 29.14; DCF B17-26; DVHA charts 2020-2026). No 2019 PIL was found, so 2018's value stays in force through 2019. The higher Chittenden PIL is not modeled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KFF 2018 and 2026 list no medically needy program for aged, blind or disabled people in these five states; the flags had been swapped with AR, IL, IA, NJ and ND. Their -inf limits meant no result changes. The NJ DMAHS fact sheet now 404s, so cite the 2026-05-14 Wayback copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Iowa 441-75.8(7) and (5)"a", the NJ fact sheet (archived) and SPA KS-25-0019 page 7 for the $475 standard, alongside KFF. - HBEE 29.14 cited from file page 50. - Number the two category cases 3 and 4, after PR 10370's Cases 1-2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in main's CI fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review
PR #10374, "Update Medicaid medically needy limits and switch on AR, IA, IL, NJ and ND" (hua7450). Round 1, full review.
IDs: C = critical, SA = should address, G = suggestion.
Paths: VAR/ = policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medically_needy/, V = VAR/medicaid_medically_needy_income_limit.py, E = VAR/is_medically_needy_for_medicaid.py, MN/ = policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/medically_needy/, INC/ = MN/limit/income/, AST/ = MN/limit/assets/, CAT/ = MN/categories/, T/ = policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/. Line numbers refer to the reviewed head. Every PDF link uses the file page number.
Source Documents
- Reviewed head SHA: 15059d9
- Mode: full
- Scope: 16 files, +1,424 / -53 against the merge base
4a1a3cdeb7. The analysis ran atc1b120a6ed; the only later commit mergesmainand changes none of the 16 files. Decisive probes and all fix runs were repeated at the head. - Federal: 42 CFR 435.811, 435.602, 435.831, 435.1007; KFF 2018 (Table 3) and 2026 (Appendix Table 4).
- New York: PDF GIS 22 MA/11 (pages 1-2); attachments of 22 MA/01, 23 MA/02, 24 MA/01, 25 MA/03 (image) and 26 MA/05 (page 2 each); PDF SPA NY-23-0001.
- North Dakota: 510-05-85-40 and its ML 3896 archive; PDF ML 3702 (page 6), ML 3776 (page 1, image), SPA ND-23-0034 (pages 2, 5; images), NDAC 75-02-02.1 (page 40).
- Illinois: WAG 25-03-02(2) (live, and Wayback 2023-06-08, 2024-07-15, 2025-05-15); 305 ILCS 5/5-2; PM 15-06-02-a, 15-06-02-c, 15-08-00, 07-02-01; 89 IAC 120.20.
- WI, DC, NJ: PDF WI Ops Memo 19-26 (Wayback, page 2, image), MEH 39.4.1; PDF 29 DCMR 901.1 (image), DHCF notice and fact sheet (page 2), SPA DC-22-0014 (pages 15-17); PDF NJ fact sheet (Wayback), N.J.A.C. 10:70-1.2 and 10:70-5.1.
- Other states: every other reference in the PR's files (74 links) was opened at its cited file page (SPA pages as images). A fix carries the links it adds.
- Repository:
policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medicaid_optional_senior_or_disabled_income_limit.py:46(Missourinp.ceil); #9561 and #9563. - Year: target 2026. Values checked 2018-2026.
Branch Status
- 8 commits ahead and 6 behind
main(8ea43422e6); basemain; MERGEABLE. CI at the head: 33 pass, 0 fail. - Merge after #10370, as the body says. Both PRs edit
Eon different lines, and the Python merges cleanly. At this head the test mixes units (SA1); after #10370 it uses the marital unit throughout. - #10370 has its own open critical item. PavelMakarchuk's review found that #10370 drops the parents' medical expenses from a child's spend-down (42 CFR 435.831(d)). This PR does not cause or fix it, and its limit (a child is a unit of one) stays right after #10370's fix, which must come first.
- Test-file conflicts with #10370. Two test files conflict at the end. Resolved as the body says, the medically needy folder passed 47 of 47. Renumber the new C1 and SA4 cases then.
- #10375 is stacked on this PR (its commits plus California's 2027 asset limits). Rebase it after this PR changes.
- Other overlaps. Draft #10394 (G3). #10240 also appends to
T/is_medically_needy_for_medicaid.yaml. #10378 merges after this PR. #10361 and #10386 change the optional ABD pathway, but the new tests setis_optional_senior_or_disabled_for_medicaid: false.
What the PR gets right
- All 10 flag changes are right, and after the PR the senior and disabled flags of all 51 jurisdictions match KFF 2026. The switch-offs change no result, because those limits were
-.inf. - All 112 dated values checked, in 17 states and DC, match their sources.
- The rate encodings follow the law, with exact dates: MN 80%, 81% and 100%; KS at the SSI rate from 2025-07-01; WA at the one-person rate for sizes 1 and 2; UT 100%; NY 138% from 2023. The updated KS medical-expenses case is right.
- The new variable has no hard-coded amounts, is vectorized, and sizes the unit by marital unit (42 CFR 435.602). The year-keyed tests pin every dated CT, DC, NH, RI and VT value.
- The body states its limits and merge steps clearly. No partner test is edited; the changelog fragment is correct.
Critical (Must Fix)
C1. Rate-based limits are not rounded to the whole-dollar monthly levels that NY, ND and IL publish.
- Where:
V:34-41. The rate branch returnsfpg_rate * unit_fpgwith no rounding. - Evidence: NY and ND round up to the next dollar, and IL drops the cents.
- NY (GIS attachments, page 2): 2025 $1,800 / $2,433 for 138% FPL of $1,799.75 / $2,432.25 (so not nearest-dollar); 2026 $1,836 / $2,489 for $1,835.40 / $2,488.60.
- ND (ML 3702 page 6; ML 3896): 2023 $1,009 for $1,008.45; April 2024 $1,130 for $1,129.50.
- IL (WAG 25-03-02(2)): $1,803 for two in 2026, for $1,803.33; 2023-2025 also drop the cents.
- WI keeps the cents (MEH 39.4.1, $1,803.33), so WI stays unrounded.
- A probe at the head flips eligibility at the published level. A NY senior at $22,032 in 2026 (12 × $1,836) is ineligible (model limit $22,024.80), as are NY at $21,600 in 2025 and ND at $13,560 in 2024. An IL couple at $21,640 in 2026 is eligible, above the published $21,636. The PR's tests pin the unrounded amounts (
T/medicaid_medically_needy_income_limit.yaml:173,:294,:337,:400). - Why C: missing rounding, with a probe that flips eligibility at a published standard. The body mentions the gap, but that does not override a clear published standard. The repo's whole-dollar ceiling (#9561) leaves this pathway out (#9563), but that choice predates rate-based limits, and Missouri's rate limit is already rounded up (
medicaid_optional_senior_or_disabled_income_limit.py:46). The band is under $1 a month. - Fix (ran at the head with the SA fixes; results in the Validation Summary).
New INC/rounds_up_monthly.yaml:
description: States round the monthly medically needy income limit up to the next whole dollar under the Medicaid program, if this is true.
metadata:
unit: bool
period: year
label: Medicaid medically needy income limit rounded up to a whole dollar
breakdown:
- state_code
reference:
- title: New York DOH GIS 26 MA/05, Attachment I, SSI-Related Medicaid Income Level $1,836 / $2,489 (138% FPL)
href: https://www.health.ny.gov/health_care/medicaid/publications/docs/gis/26ma05_att1.pdf#page=2
- title: New York DOH GIS 25 MA/03, Attachment I, SSI-Related Medicaid Income Level $1,800 / $2,433 (138% FPL)
href: https://www.health.ny.gov/health_care/medicaid/publications/docs/gis/25ma03_att1.pdf#page=2
- title: North Dakota Manual Letter 3702, medically needy income levels $1,009 / $1,364 (83% FPL)
href: https://www.nd.gov/dhs/policymanuals/51003/Content/ML/2023/ML%203702%20Federal%20Poverty%20Level%20Updates%2004-01-2023.pdf#page=6
- title: North Dakota Non-ACA Medicaid Manual 510-05-85-40 (archived, ML 3896), medically needy income level $1,130 (90% FPL)
href: https://www.nd.gov/dhs/policymanuals/51005/Archived%20Documents/2025/3896/510_05_85_40.htm
ND:
2018-01-01: true
NY:
2018-01-01: trueNew INC/rounds_down_monthly.yaml:
description: States round the monthly medically needy income limit down to a whole dollar under the Medicaid program, if this is true.
metadata:
unit: bool
period: year
label: Medicaid medically needy income limit rounded down to a whole dollar
breakdown:
- state_code
reference:
- title: Illinois DHS Workers' Action Guide WAG 25-03-02(2), AABD 100% FPL monthly income standards ($1,803 for two in 2026)
href: https://www.dhs.state.il.us/page.aspx?item=21741
IL:
# IDHS tables drop the cents for one and two people from 2023; KFF 2018 does not.
2018-01-01: false
2023-01-01: trueV, insert above line 34, then use fpg_limit in place of fpg_rate * unit_fpg at line 37:
fpg_limit = fpg_rate * unit_fpg
# Some states publish the monthly level in whole dollars. Fix the
# monthly amount at cent precision first, so floating-point noise
# cannot move an exact whole dollar (as in medicaid_income_level).
fpg_monthly = np.round(fpg_limit / MONTHS_IN_YEAR, 2)
fpg_limit = select(
[
p.rounds_up_monthly[state].astype(bool),
p.rounds_down_monthly[state].astype(bool),
],
[
np.ceil(fpg_monthly) * MONTHS_IN_YEAR,
np.floor(fpg_monthly) * MONTHS_IN_YEAR,
],
default=fpg_limit,
)The cent-precision step keeps ND 2026 (exactly $1,197.00) at $14,364.
In T/medicaid_medically_needy_income_limit.yaml, change four expectations (and comments): line 173 (Case 7) to [29_868, 29_868]; line 294 (Case 12) to [21_636, 21_636]; line 337 (Case 14) to [27_216, 27_216, 20_124]; line 400 (Case 16) to [16_368, 16_368, 12_108].
Append three cases to T/is_medically_needy_for_medicaid.yaml after the SA4 case. Case 18 is Case 17 named "New York senior one dollar a year above the published level does not qualify in 2026.", with ssi_countable_income: 22_033 and output false. All pass with the fix.
- name: Case 17, New York senior at the published 1,836 monthly level qualifies in 2026.
period: 2026
input:
age: 70
is_adult_for_medicaid: false
is_optional_senior_or_disabled_for_medicaid: false
is_ssi_recipient_for_medicaid: false
ssi_countable_income: 22_032
medicaid_medically_needy_medical_expenses: 0
ssi_countable_resources: 1_000
state_code: NY
output:
# GIS 26 MA/05: 1,836 x 12 = 22,032 (138% FPL is 1,835.40, rounded up).
is_medically_needy_for_medicaid: true
- name: Case 19, Illinois couple above the published 1,803 monthly level does not qualify in 2026.
period: 2026
input:
people:
person1: {age: 70, is_tax_unit_head: true, is_adult_for_medicaid: false, is_optional_senior_or_disabled_for_medicaid: false, is_ssi_recipient_for_medicaid: false, ssi_countable_income: 21_640, medicaid_medically_needy_medical_expenses: 0, ssi_countable_resources: 1_000}
person2: {age: 68, is_tax_unit_spouse: true, is_adult_for_medicaid: false, is_optional_senior_or_disabled_for_medicaid: false, is_ssi_recipient_for_medicaid: false, ssi_countable_income: 0, medicaid_medically_needy_medical_expenses: 0, ssi_countable_resources: 0}
marital_units:
marital_unit: {members: [person1, person2]}
tax_units:
tax_unit: {members: [person1, person2]}
households:
household: {members: [person1, person2], state_code: IL}
output:
# WAG 25-03-02(2): 1,803 x 12 = 21,636 (21,640 / 12 = 1,803.33, cents dropped).
is_medically_needy_for_medicaid: [false, false]Should Address
SA1. At this head, the test compares tax-unit income with a marital-unit limit.
- Where:
E:26-28(income and assets summed over the tax unit),E:31(asset limit bytax_unit_is_joint),E:33(income limit fromV, sized by marital unit atV:23). - Evidence: a NY 2026 married couple filing separately, each with $24,000 of countable income, is eligible at the head. Under either consistent unit it fails ($48,000 against $29,863.20; $24,000 against $22,024.80). The merge base and a tree merged with #10370 both give ineligible.
- Why SA: an entity mismatch that the declared dependency removes, so not critical; but nothing enforces the order on a MERGEABLE, green PR.
- Fix: retarget the base to #10370's branch (
medicaid-medically-needy-blind-unit), or hold the merge until #10370 lands and rebase.
SA2. DC limits for 2019-2022 stay at $652, against 29 DCMR 901.1.
- Where:
INC/individual.yaml:105-107andINC/couple.yaml:105-107. - Evidence: 29 DCMR 901.1 bases the levels on "50% of the respective amounts of the Federal poverty guidelines published each year", with one person at 95% of two (2003 table). The PR uses it for 2023-2026, and it reproduces KFF 2018's $652 and DHCF's 2023 and 2024 figures. But 2019-2022 stay at $652; in 2022 that is $72.77 a month low for one person and $110.92 for a couple.
- Why SA: the PR extends the DC series by a stated rule and leaves the rule unapplied for four years. Not critical: the 2018 line is unchanged context, and the body lists the gap.
- Fix (ran):
# INC/individual.yaml, DC, after 2018-01-01: 652
2019-01-01: 669.35
2020-01-01: 682.42
2021-01-01: 689.54
2022-01-01: 724.77
# INC/couple.yaml, DC, after 2018-01-01: 652
# NOTE: KFF 2018 reports DC's own $652 for couples; the 29 DCMR 901.1 method applies from 2019.
2019-01-01: 704.58
2020-01-01: 718.33
2021-01-01: 725.83
2022-01-01: 762.92Append to T/medicaid_medically_needy_income_limit.yaml (passes), and update the body's DC limitation line:
- name: Case 22, District of Columbia couple and individual limits from 2019 to 2022 follow 29 DCMR 901.1.
period: 2022
absolute_error_margin: 0.01
input:
people:
person1: {age: 70}
person2: {age: 68}
person3: {age: 74}
marital_units:
marital_unit1: {members: [person1, person2]}
marital_unit2: {members: [person3]}
tax_units:
tax_unit1: {members: [person1, person2]}
tax_unit2: {members: [person3]}
households:
household:
members: [person1, person2, person3]
state_code: {2019: DC, 2020: DC, 2021: DC, 2022: DC}
output:
# Couple: 50% of the two-person guideline / 12; individual: 95% of that.
medicaid_medically_needy_income_limit:
2019: [8_454.96, 8_454.96, 8_032.2]
2020: [8_619.96, 8_619.96, 8_189.04]
2021: [8_709.96, 8_709.96, 8_274.48]
2022: [9_155.04, 9_155.04, 8_697.24]SA3. The only source for Wisconsin's 2019-09-01 date is a dead link.
- Where:
INC/fpg_rate.yaml:43-44, which supportsINC/fpg_rate.yaml:62-64. - Evidence: the live Ops Memo 19-26 URL returns HTTP 404. The Wayback capture of 2025-10-31 returns the memo; page 2 gives 100 percent of the FPL "Effective September 1, 2019". The other WI references give no date.
- Why SA: the document exists and corroborates the value, so this is a broken link, not a missing source.
- Fix (ran; files load), at
INC/fpg_rate.yaml:44:
href: https://web.archive.org/web/20251031224345id_/https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2019-26.pdf#page=2SA4. The tests do not pin several values and dates that the PR adds or makes live, or the marital-unit rule.
- Where: AR, IA and NJ at lines 90-91, 119-120 and 154-155 of
INC/individual.yamlandINC/couple.yaml;INC/fpg_rate.yaml:53, 56;AST/individual.yaml:67-69andAST/couple.yaml:67-69;CAT/senior.yaml:55-56;V:21-23. - Evidence: each change passes all 41 cases: AR $108.33 back to $108 (this PR's own change); other AR, NJ and IA values; the ND 90% and MN 100% dates moved a year; the IL asset date and senior flag moved to 2025;
is_couplefromtax_unit_is_joint(every existing case has marital unit = tax unit). - Why SA: missing edge cases for variables that already have tests.
- Fix (ran: each case passes and fails on the change it targets). Values include C1; without it, Case 20's ND values are
12_101.4and13_554, and Case 21 is[29_863.2, 29_863.2, 22_024.8]. Append toT/medicaid_medically_needy_income_limit.yaml:
- name: Case 19, Arkansas, Iowa and New Jersey couple and individual dollar limits in 2026.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1: {age: 70}
person2: {age: 68}
person3: {age: 74}
person4: {age: 70}
person5: {age: 68}
person6: {age: 74}
person7: {age: 70}
person8: {age: 68}
person9: {age: 74}
marital_units:
marital_unit1: {members: [person1, person2]}
marital_unit2: {members: [person3]}
marital_unit3: {members: [person4, person5]}
marital_unit4: {members: [person6]}
marital_unit5: {members: [person7, person8]}
marital_unit6: {members: [person9]}
tax_units:
tax_unit1: {members: [person1, person2]}
tax_unit2: {members: [person3]}
tax_unit3: {members: [person4, person5]}
tax_unit4: {members: [person6]}
tax_unit5: {members: [person7, person8]}
tax_unit6: {members: [person9]}
households:
household1: {members: [person1, person2, person3], state_code: AR}
household2: {members: [person4, person5, person6], state_code: IA}
household3: {members: [person7, person8, person9], state_code: NJ}
output:
# AR: 216.66 / 108.33 x 12; IA: 483 / 483 x 12; NJ: 434 / 367 x 12.
medicaid_medically_needy_income_limit: [2_599.92, 2_599.92, 1_299.96, 5_796, 5_796, 5_796, 5_208, 5_208, 4_404]
- name: Case 20, North Dakota uses 90 percent of the poverty guideline from 2024 and Minnesota 100 percent from 2023.
period: 2024
absolute_error_margin: 0.01
input:
people:
person1: {age: 70}
person2: {age: 70}
marital_units:
marital_unit1: {members: [person1]}
marital_unit2: {members: [person2]}
tax_units:
tax_unit1: {members: [person1]}
tax_unit2: {members: [person2]}
households:
household1: {members: [person1], state_code: {2023: MN, 2024: MN}}
household2: {members: [person2], state_code: {2023: ND, 2024: ND}}
output:
# [MN, ND]. 2023: 100% and 83% of 14,580 (ND 1,008.45 rounds up to 1,009 a month).
# 2024: 100% and 90% of 15,060 (ND 1,129.50 rounds up to 1,130, ML 3896).
medicaid_medically_needy_income_limit:
2023: [14_580, 12_108]
2024: [15_060, 13_560]
- name: Case 21, aged parent claimed as a dependent on a married child's joint return uses the individual limit.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1: {age: 50, is_tax_unit_head: true}
person2: {age: 48, is_tax_unit_spouse: true}
person3: {age: 78, is_tax_unit_dependent: true}
marital_units:
marital_unit1: {members: [person1, person2]}
marital_unit2: {members: [person3]}
tax_units:
tax_unit: {members: [person1, person2, person3]}
households:
household: {members: [person1, person2, person3], state_code: NY}
output:
# 42 CFR 435.602: the unit is the individual or married couple, not the tax unit.
# person3 is unmarried: 1.38 x 15,960 / 12 = 1,835.40, rounded up to 1,836, x 12.
medicaid_medically_needy_income_limit: [29_868, 29_868, 22_032]Append to T/is_medically_needy_for_medicaid.yaml:
- name: Case 16, Illinois senior with assets at the 17,500 limit qualifies in 2024.
period: 2024
input:
age: 70
is_adult_for_medicaid: false
is_optional_senior_or_disabled_for_medicaid: false
is_ssi_recipient_for_medicaid: false
ssi_countable_income: 20_000
medicaid_medically_needy_medical_expenses: 6_000
ssi_countable_resources: 17_500
state_code: IL
output:
# Limit 15,060 (100% FPG, 2024). 20,000 - 6,000 = 14,000; assets 17,500 equal
# the limit from 2023-05-12, first read in 2024 (PM 07-02-01).
is_in_medicaid_medically_needy_category: true
is_medically_needy_for_medicaid: trueSA5. Four new parameter descriptions do not follow the one-sentence format.
- Where:
INC/fpg_rate.yaml:1andINC/ssi_rate.yaml:1(two sentences);INC/individual.yaml:1andINC/couple.yaml:1(end with formula mechanics). - Evidence: the repo's parameter rule asks for one sentence that ends "under the [program name] program".
- Why SA: formatting.
- Fix (ran; files load):
# INC/fpg_rate.yaml
description: States set the medically needy income limit at this share of the federal poverty guideline for a household of one or two under the Medicaid program.
# NOTE: States not listed, or with a share of zero, use the dollar limits in individual.yaml and couple.yaml.
# INC/ssi_rate.yaml: the same, with "the Supplemental Security Income federal benefit rate" in place of the guideline phrase.
# INC/individual.yaml (couple.yaml: "for a couple")
description: States limit monthly income for an individual to this amount under the Medicaid medically needy program.
# NOTE: From the date a state's fpg_rate or ssi_rate is positive, the formula uses that rate instead of this amount.Suggestions
G1. Minnesota and Utah rounding is not confirmed; correct the body's claim.
- Where: the body's Limitations ("MN, NY and ND round up");
INC/fpg_rate.yaml:50-53and:60-61. - Evidence: MN's DHS-3461A could not be retrieved, and UT's policy gives "100% of the Federal Poverty Level" with no table. Only KFF 2026 shows UT at $1,804 for two ($1,803.33 at 100%).
- Why G: inconclusive; no flip is proved for MN or UT.
- Fix: keep MN and UT unrounded (C1 lists only ND, NY and IL). Change the body line to "NY and ND round up; IL drops cents; WI keeps cents; MN and UT are not confirmed." Add a state to
rounds_up_monthly.yamlonly with a primary table.
G2. Cite the North Dakota documents that carry the 90% date.
- Where:
INC/fpg_rate.yaml:31-32(SPA ND-23-0034), which supportsINC/fpg_rate.yaml:56. - Evidence: SPA ND-23-0034 page 5 sets 90% for "AFDC-related medically needy groups" only. ML 3776 page 1 (effective January 1, 2024) makes ACA medically needy the same as Non-ACA at 90%, so ABD was 90% by then.
- Why G: the date is right and corroborated; this improves the trail.
- Fix (not run; both links resolve):
- title: North Dakota Manual Letter 3776, ACA Medically Needy (effective January 1, 2024)
href: https://www.nd.gov/dhs/policymanuals/51003/Content/ML/2023/ML%203776%20-ACA%20Med%20Needy.pdf#page=1
- title: North Dakota Non-ACA Medicaid Manual 510-05-85-40 (archived, ML 3896), 90% of poverty from April 1, 2024
href: https://www.nd.gov/dhs/policymanuals/51005/Archived%20Documents/2025/3896/510_05_85_40.htmG3. Name draft #10394 in the body, and agree on the North Dakota encoding.
- Where: the body's "Merge after #10370" paragraph.
- Evidence: #10394 edits the same four parameter files and adds ND dollars from 2025-04-01 ($1,174 / $1,587) and 2026-04-01 that this PR replaces with 90% FPL. Its tests expect calendar 2026 at $1,174, but this PR gives $1,197, so a case fails after a rebase.
- Why G: coordination only.
- Fix: add one line to the body, and agree on one ND encoding with #10394.
G4. Document the Illinois rules that the switch-on does not model.
- Where:
CAT/senior.yaml:55-56andCAT/disabled.yaml:55-56;E:39. - Evidence: PM 15-08-00 starts spenddown when income "and/or nonexempt resources" exceed the limits; the model applies a hard asset test. PM 15-06-02-c (
INC/fpg_rate.yaml:13-14) counts everyone in the home when the client has children under 18; the model caps the unit at two. Both understate IL eligibility. - Why G: the one-or-two unit is a model-wide limit, and the body can document both gaps.
- Fix: add both to the body's Limitations, or to follow-up issue #10472.
G5. Cite N.J.A.C. 10:70 for New Jersey, and note the narrower benefit package.
- Where: the NJ references at
CAT/senior.yaml:18-19,CAT/disabled.yaml:18-19, and lines 11-12 of the fourAST/andINC/dollar files. - Evidence: the only NJ source is an undated fact sheet (values match KFF). N.J.A.C. 10:70-1.2 and 10:70-5.1 set up the program and its resource limits. The fact sheet's package excludes inpatient hospital care and prescribed drugs, but
medicaidvalues these enrollees at the full per-capita cost. - Why G: the values are corroborated; this adds the rule and one limitation.
- Fix (not run; links resolve), and add the benefit-package line to the body's Limitations:
- title: N.J.A.C. 10:70-1.2 - Purpose of the Medically Needy Manual
href: https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-10-70-1-2
- title: N.J.A.C. 10:70-5.1 - Resource eligibility limits
href: https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-10-70-5-1G6. Cite GIS 22 MA/01 for New York's 2022 values.
- Where:
INC/individual.yaml:160-162,INC/couple.yaml:160-162,AST/individual.yaml:108-110andAST/couple.yaml:108-110. - Evidence: GIS 22 MA/01 attachment page 2 lists $934 / $1,367 and $16,800 / $24,600 effective January 1, 2022; GIS 22 MA/11 refers to them only after the fact.
- Why G: the values are right; this is a better source.
- Fix (not run; link resolves):
- title: New York DOH GIS 22 MA/01, Attachment I, 2022 SSI-Related Medicaid Income and Resource Levels
href: https://www.health.ny.gov/health_care/medicaid/publications/docs/gis/22ma01_att1.pdf#page=2G7. The five new switches start in 2015, but the limits they gate start in 2018.
- Where: AR, IA, IL, ND and NJ at
CAT/senior.yaml:29-30, 50-51, 55-56, 84-85, 90-91and the same lines ofCAT/disabled.yaml. - Evidence: 2015-2017 use the 2018 values (AR $1,300 a year; IL 100% FPG; ND 83% FPG).
- Why G: every other state has the same pattern, and AR's program text is dated 01/01/14.
- Fix: add a one-line NOTE, or date the five new flags 2018-01-01.
G8. The dollar fallback for IL, MN, ND, UT and WA is now $0.
- Where:
INC/individual.yamlandINC/couple.yaml, which no longer list these states. - Evidence: an unlisted state reads 0, so a reform that sets one of these states' rate to 0 gives a $0 limit.
- Why G: baseline results do not change.
- Fix: keep the 2018 dollar entries, or say in the SA5 NOTE that these states have none.
G9. Readability.
V:24names Washington in generic code. Use# Some states apply the one-person limit to a couple.T/medicaid_medically_needy_income_limit.yamlhas double blank lines after several cases (for example lines 81-82, 174-175, 295-296). Use one.- Why G: style only.
Investigated and cleared
- DC 2018 couple. The 29 DCMR 901.1 method gives $685.83, but KFF 2018, the file's original source, records DC's own $652 / $652. The sources conflict, so 2018 stays.
- The ND 90% date as a reference defect. Partly right: the cited SPA amends only AFDC-related groups, but ML 3776 and ML 3896 carry the date (G2).
- An earlier rounding fix (round up MN, ND, NY, UT; not IL, WI). Partly right: IL drops cents; MN and UT lack a primary table. C1 replaces it.
- SA1 as critical. It lasts only until the declared prerequisite merges, so SA.
- Rate limits above the federal cap. KS, NY, UT and WA use a 1902(r)(2) disregard; encoding the effective limit gives the same result.
- Missing keys and branch order. Unlisted states read 0, and no state has both rates, so both are safe.
- A child's spend-down.
E:26-28still sums over the tax unit, as onmain; that is #10370's scope.
Out of scope / follow-up
- Named in the body: MA (KFF 2026: 100% FPL, against $522 / $650), MI (#8453), LA and VA regional limits, VT's Chittenden PIL, #10472, #10473, #10375 and #10378.
- Documented simplifications: mid-year dates apply from the next January; MN's July COLA disregard; NY 2019-2021 and VT 2019 keep the 2018 values.
Validation Summary
| Check | Result |
|---|---|
| CI and local tests | CI 33 pass, 0 fail. Medically needy folder 41/41 at both heads; Medicaid folder 728 at c1b120a6ed |
| Fix runs at the head | C1 and SA2-SA5 together: medically needy 49/49, boundary probe 5/5, Medicaid 753/753, partner healthcare 70/70 (read-only; no partner file edited) |
| References and law | 74 links, 73 resolve (WI dead, SA3); 112 values match; rounding (C1); DC 2019-2022 (SA2) |
| Code and mutation | No hard-coded values; vectorized. 22 mutations: 9 killed, SA4 kills 10 more, 3 left immaterial |
| Merge trials | #10370: Python clean, two test files conflict, resolved tree 47/47, SA1 correct after merge |
Microsimulation (2026, at c1b120a6ed) |
Medically needy eligible +517,100 (to 919,635); NY +359,286 (not re-checked); switch-ons +34,600; switch-offs 0 |
| Branch | 8 ahead / 6 behind main; MERGEABLE |
| PR body, other reviews | Accurate, apart from G1 and G3. axiom: line present (process note, not counted). No other reviews |
Review Severity: REQUEST_CHANGES
One critical item (C1: missing rounding that flips eligibility at the published NY, ND and IL limits) and five should-address items are open.
Next Steps
To auto-fix issues: run the fix-pr workflow for this PR.
- Apply C1: the two rounding flags, the formula change, four updated expectations and three boundary cases.
- Apply SA2 (DC 2019-2022 and its test), SA3 (WI link), SA4 (four test cases) and SA5 (descriptions).
- Take the suggestions you agree with, and update the body for G1, G3, G4 and G5.
- Run
make format, then the medically needy and Medicaid test folders. - Merge after #10370 has its fix (SA1), resolve the two test files as the body says, then rebase #10375.
…needy-limits # Conflicts: # policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/is_in_medicaid_medically_needy_category.yaml # policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/is_medically_needy_for_medicaid.yaml
…and references Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, Pavel. Round 1 is applied at 33d10a5. That head also merges Paths as in your review:
The changelog fragment now covers the rounding and DC. TheAxiomFoundation/rulespec-us#1938 is updated to this head. |
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review
PR #10374, "Update Medicaid medically needy limits and switch on AR, IA, IL, NJ and ND" (hua7450). Round 2, incremental review of 15059d9cd2..33d10a5f09.
IDs: C = critical, SA = should address, G = suggestion. New items continue the numbering after the highest prior ID in each class.
Paths as in round 1: VAR/ = policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medically_needy/, V = VAR/medicaid_medically_needy_income_limit.py, E = VAR/is_medically_needy_for_medicaid.py, MN/ = policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/medically_needy/, INC/ = MN/limit/income/, AST/ = MN/limit/assets/, CAT/ = MN/categories/, T/ = policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/. Line numbers refer to the reviewed head.
Source Documents
- Reviewed head SHA: 33d10a5
- Mode: incremental (round 2)
- Scope: two commits since my last review (6:41pm EDT, October 27).
3a8bf04ebdmergesmainatb210b45a6c, which brings #10370 intoEand adds main's cases to two test files.33d10a5f09(2:33pm EDT, October 29) applies round 1: 14 files, +292 / -24. It addsINC/rounds_up_monthly.yamlandINC/rounds_down_monthly.yaml, changesV:34-49, adds DC 2019-2022, adds references and NOTE lines to nine parameter files, changes four test expectations and adds eight cases, and updates the changelog and the body. - New York: PDF GIS 22 MA/01, Attachment I (page 2: $934 / $1,367; $16,800 / $24,600); PDF GIS 25 MA/03, Attachment I (page 2: $1,800 / $2,433); PDF GIS 26 MA/05, Attachment I (page 2: $1,836 / $2,489). All three return 200 to a browser User-Agent.
- North Dakota: PDF ML 3702 (page 6: $1,009 / $1,364); PDF ML 3776 (page 1: effective January 1, 2024, "ACA Med Needy to be the same as Non-ACA Med Needy"); 510-05-85-40, ML 3896 archive ("90% of the poverty level", $1,130 / $1,533, "Effective April 1, 2024").
- Illinois: WAG 25-03-02(2) (AABD 100% FPL: $1,330 for one, $1,803 for two).
- New Jersey: N.J.A.C. 10:70-1.2 (purpose: "Set forth eligibility for the Medically Needy Program"); N.J.A.C. 10:70-5.1 ($4,000 for one, $6,000 for two, which match
AST/). - DC: 29 DCMR 901.1 method (50% of the two-person guideline, 95% of that for one), against the HHS guidelines for 2019-2022.
- Wisconsin: the Wayback capture of Ops Memo 19-26 refused my connections this round (HTTP 429). The href at
INC/fpg_rate.yaml:49is the same capture I read in round 1. - CI: run 40931994172, logs of jobs 123653103433 and 123670824228.
- Repository:
policyengine_us/tests/test_parameter_files.py:61-155(breakdown guard, onmainsince commite281f7eef5, May 2026);CONTRIBUTING.md:78.
Branch Status
- 10 commits ahead and 29 behind
mainat 3:45pm EDT; merge baseb210b45a6c; MERGEABLE.mainchanged none of this PR's files after the merge base. - SA1's prerequisite is in. #10370 merged at 1:34pm EDT, and this branch merges it.
Enow uses the marital unit throughout. - CI at the head: 2 fail, 30 pass, 1 pending (Contrib other-shard-1, still running at 3:45pm EDT; pending is not a failure).
- "Python tests / Full Suite - Rest (Python shard 2)": a real test failure. The job ended at 3:07pm EDT with "1 failed, 3118 passed, 11 skipped". The failing test is
policyengine_us/tests/test_parameter_files.py::test_enum_breakdown_parameters_do_not_have_single_member_tables: "INC/rounds_down_monthly.yamlhas metadata.breakdown=['state_code'] but only one top-level member 'IL'. Use a scalar parameter under a member-specific path instead." I reproduced it at the snapshot. This is not an infrastructure failure and not a partner test. It is CRITICAL (C2). - "Python tests / Check Rest Python shards": a gate job. It ran for 3 seconds and fails because shard 2 failed ("Rest jobs did not all succeed: plan=success, shards=failure"). It has no failure of its own and clears when C2 is fixed.
- "Household API Partners" passes. The PR changes no file in
tests/policy/baseline/partners/.
- "Python tests / Full Suite - Rest (Python shard 2)": a real test failure. The job ended at 3:07pm EDT with "1 failed, 3118 passed, 11 skipped". The failing test is
- Other PRs. #10375 is stacked on this PR; rebase it after C2. Draft #10394 is now based on
stack/pr-10373; the body names it (G3).
Round 1 items
| ID | Status | Evidence |
|---|---|---|
| C1 | RESOLVED | V:34-49 rounds the rate limit at cent precision, then up for ND and NY (INC/rounds_up_monthly.yaml) and down for IL from 2023 (INC/rounds_down_monthly.yaml). The four expectations read [29_868, 29_868] (T/medicaid_medically_needy_income_limit.yaml:171), [21_636, 21_636] (:289), [27_216, 27_216, 20_124] (:332) and [16_368, 16_368, 12_108] (:397), and match the published $2,489, $1,803, $2,268 / $1,677 and $1,364 / $1,009. Cases 25-27 (T/is_medically_needy_for_medicaid.yaml:658, 673, 688) pass. Mutations: no NY rounding fails 4 cases, no ND rounding 2, no IL rounding 2, ceiling and floor swapped 8. The behaviour is right. But the IL flag file that I wrote in round 1 fails the repo's breakdown guard: see C2. |
| SA1 | RESOLVED | The merge brings #10370: income and assets sum over the marital unit (E:57-60), the asset limit uses the marital-unit size (E:63), and the income limit comes from V (E:65). My round-1 probe (NY 2026, married filing separately, $24,000 each) now gives [False, False]. A couple at $14,934 each (2 x 14,934 = 29,868, the published couple level) is eligible, and at $14,934.50 each it is not. |
| SA2 | RESOLVED | DC 2019-2022 at INC/individual.yaml:114-117 and INC/couple.yaml:115-118, with the 2018 NOTE at INC/couple.yaml:114. Each value is 50% of that year's two-person guideline / 12 (16,910, 17,240, 17,420, 18,310), and 95% of that for one person. Case 22 (T/medicaid_medically_needy_income_limit.yaml:550) pins all eight values, and a changed 2021 couple value fails it. The body's DC lines are updated. |
| SA3 | RESOLVED | INC/fpg_rate.yaml:49 uses the Wayback capture 20251031224345id_, the one I read in round 1 (page 2: "Effective September 1, 2019"). The body links the same capture. |
| SA4 | RESOLVED | Cases 19-21 (T/medicaid_medically_needy_income_limit.yaml:471, 507, 530) and Case 24 (T/is_medically_needy_for_medicaid.yaml:641) are as I wrote them; I re-checked the arithmetic (below). |
| SA5 | RESOLVED | One-sentence descriptions at line 1 of INC/individual.yaml, INC/couple.yaml, INC/fpg_rate.yaml and INC/ssi_rate.yaml; the mechanics are in NOTE lines at line 2. |
| G1 | RESOLVED | MN and UT stay unrounded. The body's "How the model applies them" and Limitations say NY and ND round up, IL drops cents, WI keeps cents, and MN and UT are not confirmed. |
| G2 | RESOLVED | INC/fpg_rate.yaml:34-37 cite ML 3776 and the ML 3896 archive. Both links resolve and support the 2024 date. |
| G3 | RESOLVED | The body's Out of scope names #10394 and the ND encoding conflict ($1,174 / $1,587 against $1,197 / $1,623 in 2026). |
| G4 | RESOLVED | The body's Limitations cover PM 15-08-00 (resource spend-down) and PM 15-06-02-c (children under 18). |
| G5 | RESOLVED | N.J.A.C. 10:70-1.2 and 10:70-5.1 are on all six NJ files (CAT/senior.yaml:21-24, CAT/disabled.yaml:21-24, INC/individual.yaml:14-17, INC/couple.yaml:14-17, AST/individual.yaml:13-16, AST/couple.yaml:13-16). The body has the benefit-package limitation. |
| G6 | RESOLVED | GIS 22 MA/01 Attachment I is on the four NY files (for example INC/individual.yaml:52-53). Page 2 lists $934 / $1,367 and $16,800 / $24,600. |
| G7 | RESOLVED | NOTE at CAT/senior.yaml:2 and CAT/disabled.yaml:2. |
| G8 | RESOLVED | The NOTE at line 2 of INC/individual.yaml and INC/couple.yaml names IL, MN, ND, UT and WA. |
| G9 | RESOLVED | V:24 reads "Some states apply the one-person limit to a couple." No test file in T/ has a double blank line. |
New findings
Critical
C2. CI fails: the IL rounding flag is a single-member state_code table, which the repo's parameter guard rejects.
- Where:
INC/rounds_down_monthly.yaml(the only member is IL); read atV:42. - Evidence: CI job "Python tests / Full Suite - Rest (Python shard 2)" fails
test_parameter_files.py::test_enum_breakdown_parameters_do_not_have_single_member_tableson this file, and the gate job "Check Rest Python shards" fails with it.CONTRIBUTING.md:78gives the rule: "If a parameter only applies to one enum member, make it a scalar under a member-specific path".INC/rounds_up_monthly.yamlhas two members (ND, NY) and passes. - This file is my own fix from round 1. The author copied it exactly. The fault is in my suggestion, not in the author's work.
- Why C: a CI failure on a real test, not infrastructure. The model results are right.
- Fix (ran in a copy: the guard passes 8 of 8, the medically needy folder passes 60 of 60, and the new case fails if IL rounding starts in 2018).
- Delete
INC/rounds_down_monthly.yaml. - Add
INC/il/rounds_down_monthly.yaml:
- Delete
description: Illinois rounds the monthly medically needy income limit down to a whole dollar under the Medicaid program, if this is true.
values:
# IDHS tables drop the cents for one and two people from 2023; KFF 2018 does not.
2018-01-01: false
2023-01-01: true
metadata:
unit: bool
period: year
label: Illinois Medicaid medically needy income limit rounded down to a whole dollar
reference:
- title: Illinois DHS Workers' Action Guide WAG 25-03-02(2), AABD 100% FPL monthly income standards ($1,803 for two in 2026)
href: https://www.dhs.state.il.us/page.aspx?item=21741- In
V, insert above line 39, and replace line 42 withrounds_down,:
# Illinois is the only state that drops the cents.
rounds_down = (state == "IL") & p.il.rounds_down_monthly- Append to
T/medicaid_medically_needy_income_limit.yaml. No current case pins the IL dates: a mutation that rounds IL from 2018 passes all 59 cases. This case pins both dates.
- name: Case 23, Illinois keeps the cents in 2022 and drops them from 2023.
period: 2023
absolute_error_margin: 0.01
input:
people:
person1: {age: 70}
person2: {age: 68}
person3: {age: 74}
marital_units:
marital_unit1: {members: [person1, person2]}
marital_unit2: {members: [person3]}
tax_units:
tax_unit1: {members: [person1, person2]}
tax_unit2: {members: [person3]}
households:
household:
members: [person1, person2, person3]
state_code: {2022: IL, 2023: IL}
output:
# Outputs are [couple, couple, individual]. 2022: 18,310 and 13,590 (1,132.50 a
# month, not rounded). 2023: 19,720 / 12 = 1,643.33, cents dropped, 1,643 x 12;
# 14,580 / 12 = 1,215 exactly.
medicaid_medically_needy_income_limit:
2022: [18_310, 18_310, 13_590]
2023: [19_716, 19_716, 14_580]- In the body's "How the model applies them", change
limit.income.rounds_down_monthlytolimit.income.il.rounds_down_monthly.
- Do not add a filler
falsemember (for example WI) to make the table pass the guard. The CONTRIBUTING rule asks for a real table.
Should address
None.
Suggestions
G10. Four comments in the eligibility tests still quote the unrounded NY and IL limits.
- Where:
T/is_medically_needy_for_medicaid.yaml:448(Case 17, "1.38 x 15,960 = 22,024.80"),:502(Case 20, "20,120.40, 20,782.80, 21,597, 22,024.80"),:605and:607(Case 21, "29,863.20" and "21,640"). - Evidence: the limits are now 22,032; 20,124, 20,784, 21,600 and 22,032; 29,868; and 21,636. Each test input is far below the limit, so all four cases still pass.
- Why G: comments only.
- Fix (not run; comments only):
# Limit 1,836 x 12 = 22,032 (GIS 26 MA/05). 25,000 - 5,000 = 20,000; assets 33,038 equal
# 2023-2026: 20,000 <= 12 x 1,677, 1,732, 1,800 and 1,836 (20,124, 20,784, 21,600, 22,032).
# NY: 40,000 - 12,000 = 28,000 <= 2,489 x 12 = 29,868; assets 44,796.
# IL: 28,000 - 7,000 = 21,000 <= 1,803 x 12 = 21,636; assets 17,500 (PM 07-02-01).Investigated and cleared
- My round-1 note on the cent-precision step was wrong. I wrote that the step "keeps ND 2026 (exactly $1,197.00) at $14,364". In float64, 0.9 x 15,960 / 12 is exactly 1,197.0 without it, and so are ND's 2026 couple and 2024 couple levels. A mutation that removes the step passes all 59 cases. The step does no harm and matches
medicaid_income_level, so keep it. No change is needed. - New hunks of
V. No hard-coded amounts. The code is vectorized, and the rounding applies only to the poverty-guideline branch. No state has both flags, so theselectorder does not matter. - The merged
E. In this PR's diff, the only change toEis line 65 (the income limit fromV). The rest comes from #10370, which other reviewers checked before it merged. That includes the round-1 Branch Status note on a child's spend-down:E:43-56now deducts the ineligible parents' expenses (42 CFR 435.831(d)), and main's Case 9 tests it. - Case renumbering after the merge.
T/is_medically_needy_for_medicaid.yamlruns from Case 1 to Case 27 after its first, unnumbered case.T/is_in_medicaid_medically_needy_category.yamlhas main's Cases 1-2, then this PR's Cases 3-4. The body describes both. - Changelog. The fragment is still one top-level file and now names DC and the rounding.
- Partner tests. The PR changes no partner file, and "Household API Partners" passes.
Tests run
policyengine-core test T/ -c policyengine_usat the snapshot: 59 passed (6 + 28 + 22 + 3 cases).pytest policyengine_us/tests/test_parameter_files.pyat the snapshot: 1 failed, 7 passed. This reproduces the CI failure (C2).- New-case arithmetic, checked by hand: Case 19 (AR 216.66 / 108.33, IA 483, NJ 434 / 367, each x 12); Case 20 (MN 14,580 and 15,060; ND 1,008.45 to 1,009 and 1,129.50 to 1,130, x 12); Case 21 (2,489 and 1,836 x 12); Case 22 (DC, eight values); Case 24 (14,000 <= 15,060; assets 17,500 <= 17,500); Cases 25-27 (22,032 <= 22,032; 22,033 > 22,032; 21,640 > 21,636). All match the sources.
- Seven mutations in a scratch copy (since deleted): no NY rounding (4 fail), no ND rounding (2), no IL rounding (2), ceiling and floor swapped (8), DC 2021 couple changed (1), IL rounded from 2018 (0, fixed by the C2 test), no cent-precision step (0, immaterial).
- SA1 probe at the snapshot: three NY couples, results in the SA1 row.
- C2 fix in a scratch copy (since deleted): guard 8 of 8 pass; medically needy folder 60 of 60 pass; the IL-from-2018 mutation fails the new Case 23.
- References: 9 of the 10 new or changed links returned 200 and support their values. The WI Wayback capture refused connections this round (HTTP 429).
Verdict
REQUEST_CHANGES: All 15 round-1 items are resolved. One new critical item is open: C2, a CI failure caused by the single-member IL table that I proposed in round 1. The fix is a file move, two formula lines and one test case. G10 is optional.
…d comments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, Pavel. Round 2 is applied at 0f8b603. That head also merges
TheAxiomFoundation/rulespec-us#1938 is updated to this head. |
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review
PR #10374, "Update Medicaid medically needy limits and switch on AR, IA, IL, NJ and ND" (hua7450). Round 3, incremental review of 33d10a5f09..0f8b603643.
IDs: C = critical, SA = should address, G = suggestion. New items continue the numbering after the highest prior ID in each class.
Paths as in rounds 1 and 2: VAR/ = policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medically_needy/, V = VAR/medicaid_medically_needy_income_limit.py, MN/ = policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/medically_needy/, INC/ = MN/limit/income/, T/ = policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medically_needy/. Line numbers refer to the reviewed head.
Source Documents
- Reviewed head SHA: 0f8b603
- Mode: incremental (round 3)
- Scope: two commits since my last review (4:09pm EDT, October 29).
7dbef95a91mergesmainat40f6990eda; it changes none of this PR's files.0f8b603643(5:42pm EDT) applies round 2: 4 files, +39 / -14. It movesINC/rounds_down_monthly.yamlto the scalarINC/il/rounds_down_monthly.yaml, changesV:39-44, adds Case 23 toT/medicaid_medically_needy_income_limit.yaml:576-600, and rewrites four comments inT/is_medically_needy_for_medicaid.yaml. The body now nameslimit.income.il.rounds_down_monthly. - Illinois, IDHS WAG 25-03-02(2), AABD 100% FPL monthly standards (the table that
INC/il/rounds_down_monthly.yamlcites). Live page (2026) and Wayback captures, one for each year: - KFF 2018, Appendix Table 3, Medically Needy Pathway, 2018: Illinois "$1,012", "$1,372", "100%".
- HHS poverty guidelines (48 states, one and two people): 2018 $12,140 / $16,460; 2019 $12,490 / $16,910; 2020 $12,760 / $17,240; 2021 $12,880 / $17,420; 2022 $13,590 / $18,310; 2023 $14,580 / $19,720; 2024 $15,060 / $20,440; 2025 $15,650 / $21,150; 2026 $15,960 / $21,640.
- Repository:
policyengine_us/tests/test_parameter_files.py:61-155(the breakdown guard; it is at this path, not undertests/code_health/);CONTRIBUTING.md:78.
Branch Status
- 12 commits ahead and 4 behind
main; merge base40f6990eda; MERGEABLE. The 4maincommits (#10360, #10363, #10364 and a version bump) change none of this PR's 19 files. - CI at the head: 34 pass, 0 fail. The C2 failure ("Full Suite - Rest (Python shard 2)" and its gate job) is gone.
- "Household API Partners" passes. The PR changes no file in
tests/policy/baseline/partners/. - Stacked PRs. #10375 (head
753c6082c8) contains this head (37 ahead, 0 behind) and carriesINC/il/rounds_down_monthly.yamlandV. If C3 changes those files, #10375 must merge this branch again. #10378 changes no medically needy file. Merge order: #10374, then #10375 and #10378.
Round 2 items
| ID | Status | Evidence |
|---|---|---|
| C1, SA1-SA5, G1-G9 | RESOLVED (round 2) | This round changes only V:39-44, the IL flag, Case 23 and four comments. The other files that these items rest on are unchanged. The NY, ND and IL rounding from 2023 still matches every published level that C1 named. C3 below is a new gap for IL 2018-2022. It does not reopen C1 for NY or ND. |
| C2 | RESOLVED | INC/rounds_down_monthly.yaml is deleted. INC/il/rounds_down_monthly.yaml:1-12 is a scalar with values: (false 2018-01-01, true 2023-01-01) and no breakdown. V:40 reads rounds_down = (state == "IL") & p.il.rounds_down_monthly, and V:44 uses it. The guard test passes at the snapshot (8 of 8), and CI passes. git grep rounds_down_monthly at the head finds only V:40, so no other file reads the old path. Case 23 pins both dates: IL true from 2018 fails only Case 23, and IL true from 2024 fails only Case 23. The body names limit.income.il.rounds_down_monthly. The author applied my fix exactly. But my fix was wrong about IL before 2023: see C3. |
| G10 | RESOLVED | T/is_medically_needy_for_medicaid.yaml:448 "1,836 x 12 = 22,032 (GIS 26 MA/05)"; :502 "12 x 1,677, 1,732, 1,800 and 1,836 (20,124, 20,784, 21,600, 22,032)"; :605 "2,489 x 12 = 29,868"; :607 "1,803 x 12 = 21,636". Each product is right and each monthly level is the published one. |
New findings
Critical
C3. Illinois limits for 2018-2022 keep the cents, but KFF 2018 and the IDHS tables round them to the nearest dollar.
- Where:
INC/il/rounds_down_monthly.yaml:3-4(false from 2018, with the comment "KFF 2018 does not");V:39-51(no rounding for IL before 2023); Case 23 atT/medicaid_medically_needy_income_limit.yaml:576, which expects "2022: 18,310 and 13,590 (1,132.50 a month, not rounded)" (:596-599). - Evidence: the published one- and two-person levels for 2018-2022 are whole dollars, rounded to the nearest dollar:
| Year | 100% FPL a month (1 / 2) | Published (1 / 2) | Model at head (1 / 2) |
|---|---|---|---|
| 2018 | 1,011.67 / 1,371.67 | KFF $1,012 / $1,372 | 1,011.67 / 1,371.67 |
| 2019 | 1,040.83 / 1,409.17 | IDHS $1,041 / $1,409 | 1,040.83 / 1,409.17 |
| 2020 | 1,063.33 / 1,436.67 | IDHS $1,063 / $1,437 | 1,063.33 / 1,436.67 |
| 2021 | 1,073.33 / 1,451.67 | IDHS $1,073 / $1,452 | 1,073.33 / 1,451.67 |
| 2022 | 1,132.50 / 1,525.83 | IDHS $1,133 / $1,526 | 1,132.50 / 1,525.83 |
- A probe at the snapshot puts a senior or couple at 12 times each published level. 7 of the 10 cases (2018 both, 2019 one, 2020 two, 2021 two, 2022 both) are ineligible in the model and eligible at the IDHS level. In the other 3 cases, the model limit is above the published level, by $0.17 to $0.33 a month.
- From 2023 the head matches all 8 published levels. The floor rule gives the same result as the nearest dollar for one and two people in 2023 and 2024. The IDHS method changes in 2025: the 2023 and 2024 tables round three people up ($2,072 for $2,071.67; $2,152 for $2,151.67), and the 2025 and 2026 tables drop the cents ($1,762 for $1,762.50 for two; $2,220 for $2,220.83 and $2,276 for $2,276.67 for three).
- Before this PR, IL used the dollar files at $1,012 / $1,372 from 2018, which match KFF. The PR replaced them with 100% FPL, so 2018-2022 now sit up to $0.50 a month off the published level.
- My round-1 fix set IL to false before 2023 with the comment "KFF 2018 does not", and my round-2 Case 23 says 2022 is "not rounded". Both are wrong. KFF 2018 and IDHS 2019-2022 round to the nearest dollar. The fault is in my suggestion, not in the author's work. I withdraw that part of the round-1 and round-2 fix.
- Why C: a value mismatch against the cited agency table, confirmed on the code path. A probe shows that eligibility flips at the published level, as C1 did in round 1. The size is small: under $0.50 a month, in 2018-2022 only. 2023-2026 are correct.
- Fix (ran in a copy: the medically needy folder passes 60 of 60 with the new Case 23; the guard passes 8 of 8;
ruff formatmakes no change; the probe gives the published level for all 18 IL cases, 2018-2026). A mutation that usesnp.roundin place of the half-up step fails the new Case 23, becausenp.round(1132.5)is 1,132.- In
INC/il/rounds_down_monthly.yaml, replace lines 3-5 and add the 2025 capture underreference:
- In
# IDHS tables drop the cents from 2025 ($1,762 for $1,762.50 for two; $2,220 for $2,220.83 for three).
2018-01-01: false
2025-01-01: true - title: Illinois DHS WAG 25-03-02(2), 2025 Monthly Income Standards, AABD 100% FPL ($1,762 for two) (archived May 15, 2025)
href: https://web.archive.org/web/20250515155649/https://www.dhs.state.il.us/page.aspx?item=21741- Add
INC/il/rounds_to_nearest_monthly.yaml:
description: Illinois rounds the monthly medically needy income limit to the nearest whole dollar under the Medicaid program, if this is true.
values:
# KFF 2018 ($1,012 / $1,372) and IDHS 2019-2024 tables round to the nearest dollar
# ($1,133 / $1,526 in 2022; $2,072 for $2,071.67 for three in 2023).
2018-01-01: true
2025-01-01: false
metadata:
unit: bool
period: year
label: Illinois Medicaid medically needy income limit rounded to the nearest whole dollar
reference:
- title: "KFF, Medicaid Financial Eligibility for Seniors and People with Disabilities: Findings from a 50-State Survey, Appendix Table 3 (2018), Illinois $1,012 / $1,372"
href: https://www.kff.org/report-section/medicaid-financial-eligibility-for-seniors-and-people-with-disabilities-findings-from-a-50-state-survey-appendix-tables/
- title: Illinois DHS WAG 25-03-02(2), 2022 Income Standards, AABD 100% FPL ($1,133 / $1,526) (archived September 28, 2022)
href: https://web.archive.org/web/20220928154002/https://www.dhs.state.il.us/page.aspx?item=21741
- title: Illinois DHS WAG 25-03-02(2), 2024 Monthly Income Standards, AABD 100% FPL ($1,255 / $1,703) (archived July 15, 2024)
href: https://web.archive.org/web/20240715015033/https://www.dhs.state.il.us/page.aspx?item=21741- In
V, replace lines 39-51:
# Illinois rounds to the nearest dollar before 2025, then drops the cents.
in_il = state == "IL"
rounds_down = in_il & p.il.rounds_down_monthly
# Half a dollar rounds up ($1,132.50 to $1,133 in 2022); np.round
# would round it to the even dollar.
rounds_to_nearest = in_il & p.il.rounds_to_nearest_monthly
fpg_limit = select(
[
p.rounds_up_monthly[state].astype(bool),
rounds_down,
rounds_to_nearest,
],
[
np.ceil(fpg_monthly) * MONTHS_IN_YEAR,
np.floor(fpg_monthly) * MONTHS_IN_YEAR,
np.floor(fpg_monthly + 0.5) * MONTHS_IN_YEAR,
],
default=fpg_limit,
)The 0.5 is the rounding step, not a policy value.
4. Replace Case 23 (T/medicaid_medically_needy_income_limit.yaml:576-600). 2022 tests the half-dollar case, and 2025 tests the only one- or two-person case where the floor and the nearest dollar differ:
- name: Case 23, Illinois rounds to the nearest dollar in 2022 and drops the cents in 2025.
period: 2025
absolute_error_margin: 0.01
input:
people:
person1: {age: 70}
person2: {age: 68}
person3: {age: 74}
marital_units:
marital_unit1: {members: [person1, person2]}
marital_unit2: {members: [person3]}
tax_units:
tax_unit1: {members: [person1, person2]}
tax_unit2: {members: [person3]}
households:
household:
members: [person1, person2, person3]
state_code: {2022: IL, 2025: IL}
output:
# Outputs are [couple, couple, individual]. WAG 25-03-02(2), AABD 100% FPL.
# 2022: 18,310 / 12 = 1,525.83 to 1,526; 13,590 / 12 = 1,132.50 to 1,133.
# 2025: 21,150 / 12 = 1,762.50, cents dropped, 1,762; 15,650 / 12 = 1,304.17 to 1,304.
medicaid_medically_needy_income_limit:
2022: [18_312, 18_312, 13_596]
2025: [21_144, 21_144, 15_648]- In the body: in "How the model applies them" (the
fpg_ratebullet), change "down in IL from 2023 (limit.income.il.rounds_down_monthly...)" to "to the nearest dollar in IL through 2024 and down from 2025 (limit.income.il.rounds_to_nearest_monthlyandlimit.income.il.rounds_down_monthly, scalar parameters because Illinois is the only state)". In Limitations ("Rounding:"), change "IL drops the cents" to "IL rounds to the nearest dollar through 2024 and drops the cents from 2025". In the tests list, change the Case 23 line to "IL rounds to the nearest dollar in 2022 and drops the cents in 2025 ($21,144 for a couple)".
- A 2023-01-01 date for both IL files gives the same results for one and two people. I used 2025 because the IDHS method changes in 2025.
Should address
None.
Suggestions
None.
Investigated and cleared
V:40,(state == "IL") & p.il.rounds_down_monthly. A string-array test and a scalar bool make a vectorized bool array. There is no hard-coded value. This is theCONTRIBUTING.md:78pattern ("make it a scalar under a member-specific path"), andmedicaid_slcsp_family_tier_category.py:29uses the samestate == "NY"form. Thep.ilnode does not clash with theILkeys inINC/individual.yamlorINC/couple.yaml.- The other enum tables.
INC/rounds_up_monthly.yamlhas two members (ND, NY), and the guard passes on every parameter file at the head. - Case 23 arithmetic at the head. 2023: 19,720 / 12 = 1,643.33, floor 1,643, x 12 = 19,716; 14,580 / 12 = 1,215, x 12 = 14,580. Both match IDHS 2023 ($1,643 / $1,215). The 2022 values are right for the encoded rule, but that rule is wrong (C3).
T/is_medically_needy_for_medicaid.yaml:430(Case 16) still says "138% FPL, 22,024.80". That figure is California's Aged and Disabled FPL limit, not New York's level, and the case's input is far above it either way. No change is needed.- Merge
7dbef95a91. No conflict, and no PR file changed. - Partner tests. No change; "Household API Partners" passes.
- Body. "this PR's cases ... are now Cases 11-23 (Cases 24-27 are new in this round)" refers to round 2. That wording is harmless. The
axiom:line isqueued(process note only).
Tests run
pytest -q policyengine_us/tests/test_parameter_files.pyat the snapshot: 8 passed (the guard istest_enum_breakdown_parameters_do_not_have_single_member_tables).policyengine-core test T/ -c policyengine_usat the snapshot: 60 passed (6 + 28 + 23 + 3 cases).git grep -n rounds_down_monthly HEAD: one hit,V:40.- Mutations in scratch copies (since deleted): IL true from 2018 (1 fail, Case 23); IL true from 2024 (1 fail, Case 23).
- IL probe at the snapshot: 18 cases (one and two people, 2018-2026) at 12 times the published level. 2023-2026: model limit equals the published level, 8 of 8. 2018-2022: 0 of 10 equal; 7 of 10 are ineligible at the published level (C3).
- C3 fix in a scratch copy (since deleted): medically needy folder 60 of 60; guard 8 of 8;
ruff format --checkclean; probe 18 of 18 at the published level; thenp.roundmutation fails the new Case 23. - References: the live WAG page and the three Wayback captures in the fix return 200 and show the quoted values. I read the KFF 2018 table through Wayback; kff.org returns no body to curl.
Verdict
REQUEST_CHANGES: C2 and G10 are resolved, and CI passes. One new critical item is open: C3. IL 2018-2022 keep the cents, but KFF and IDHS publish whole dollars rounded to the nearest dollar. The error comes from my own round-1 fix. The fix adds one scalar file, three formula lines and a revised Case 23.
KFF 2018 and the IDHS 2019-2024 tables round the monthly level to the nearest dollar; the 2025 and 2026 tables drop the cents. Add the scalar il/rounds_to_nearest_monthly flag and move il/rounds_down_monthly to 2025. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, Pavel. Round 3 is applied at bdb48a7. Before that, f3b38b0 merges
I hand-checked Case 23: 18,310 / 12 = 1,525.83, which rounds to 1,526 (x 12 = 18,312); 13,590 / 12 = 1,132.50, which rounds to 1,133 (13,596); 21,150 / 12 = 1,762.50, which drops to 1,762 (21,144); 15,650 / 12 = 1,304.17, which drops to 1,304 (15,648). The other Illinois Medicaid cases outside the medically needy folder are all in 2026, which this change leaves as it was. For one and two people in 2023 and 2024, the nearest dollar and the floor give the same level, so 2023-2026 results do not change. The body has your three edits: the |
Takes PolicyEngine#10374's Illinois nearest-dollar rounding fix (Pavel's C3 there, C2 here) and its main merge at 7f736e8. The aged, blind and disabled asset test keeps main's 53 cases and appends this PR's 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #10357
Closes #10358
What and why
PolicyEngine's medically needy pathway for aged, blind and disabled people (
is_medically_needy_for_medicaid) had two problems. Five states that run the pathway had it switched off, and most limits still held 2018 values. This PR switches the five states on and updates the limits in 14 states. Where a state ties its limit to the poverty guideline or the SSI federal benefit rate, the PR encodes that rate in place of a dollar amount.Pathway switched on (senior and disabled flags)
Pathway switched off (senior and disabled flags)
AZ, ID, IN, NM and NV had the senior and disabled flags on, swapped with AR, IL, IA, NJ and ND. KFF's 2018 and 2026 tables, already cited in the flag files, list no medically needy program for aged, blind or disabled people in these five states. They are now off from 2015. Their limits were
-.inf, so no result changes.Limits tied to a federal amount
Dollar limits updated
Asset limits updated
How the model applies them
medicaid_medically_needy_income_limit(person, annual). It returns one of three amounts:fpg_ratetimes the poverty guideline for one or two people, when the state'sfpg_rateis above zero. The monthly amount is fixed at cents, then rounded up to the dollar in NY and ND (limit.income.rounds_up_monthly) and to the nearest dollar in IL through 2024 and down from 2025 (limit.income.il.rounds_to_nearest_monthlyandlimit.income.il.rounds_down_monthly, scalar parameters because Illinois is the only state), as their published tables do: NY $1,836 / $2,489 in 2026 for 138% FPL of $1,835.40 / $2,488.60; ND $1,009 in 2023 and $1,130 in 2024; IL $1,133 for one in 2022 ($1,132.50) and $1,803 for two in 2026. WI keeps cents; MN and UT are not confirmed and stay unrounded;ssi_ratetimes the SSI federal benefit rate (individual or couple rate), when the state'sssi_rateis above zero;medicaid_optional_senior_or_disabled_income_limit(42 CFR 435.602).mainafter Count blind people and use the individual or couple in the Medicaid medically needy test #10370 (3a8bf04, at b210b45; main merged again at 40f6990 in 7dbef95, with no conflict). The spend-down test now uses the marital unit throughout, from Count blind people and use the individual or couple in the Medicaid medically needy test #10370, with this PR's income limit. The two conflicting test files kept main's cases first: this PR's cases inis_medically_needy_for_medicaid.yamlare now Cases 11-23 (Cases 24-27 are new in this round), andis_in_medicaid_medically_needy_category.yamlkeeps main's Cases 1-2, then this PR's Cases 3-4.limit.income.fpg_rate(IL, MN, ND, NY, UT, WI) andlimit.income.ssi_rate(KS, WA). These files list only the states that use them. NY, WI and KS carry a zero share before their switch dates.limit.income.couple_uses_individual_limit, true for Washington only. Washington's MNIL chart gives the one-person benefit rate to households of one and two people. Kansas's F-8 table gives couples the couple rate.Not confirmed against a primary source
DC: DHCF publishes only the one-person level ($780.58 for 2023 and $809.08 for 2024). The couple levels and the 2025–2026 values follow the method in 29 DCMR 901.1 and its table: the two-person level is 50% of the two-person guideline, and the one-person level is 95% of that. This method reproduces both DHCF figures and KFF's 2026 figures, which KFF rounds to $857 / $902. Sources give values by year only, so the parameter dates them January 1.
ND: no North Dakota document says when 90% replaced 83%. The manual shows 83% in April 2023 and 90% in April 2024. SPA ND-23-0034 (effective 2024-01-01) aligns the medically needy standards at 90%. Manual letter 3776 (1/1/2024) and the table in ML 3790 point to the same date, so the parameter uses 2024-01-01.
NH: KFF 2026 lists $926 / $1,073. The CMS-approved SPA NH-25-0019 and NH's current manual tables show $939 / $1,093 from 2025-07-01, and the PR uses those.
VT 2019: no 2019 PIL was found (DVHA's 2019 chart is not online or archived), so 2018's $1,041 stays in force through 2019.
IL: IDHS does not state when it applies each year's new guideline. Illinois's Department on Aging says the figures post in early April.
DC state plan: CMS-approved SPA DC-22-0014 (effective 10/1/2022, pp. 15–17) still lists the 1994 six-month levels, $2,262 / $2,382, or $377 / $397 a month. The PR follows 29 DCMR 901.1 and DHCF's notices. No statute is involved.
Limitations
medicaidvalues these enrollees at the full per-capita cost.Out of scope
parent.yamlhas more differences. Follow-up issue Medicaid medically needy: fix the pregnant, child and parent category flags against KFF and state sources #10473.Test plan
medicaid_medically_needy_income_limit.yaml(23 cases, including Vermont's PIL for every year from 2018 to 2026):is_medically_needy_for_medicaid.yaml:is_in_medicaid_medically_needy_category.yaml: disabled adults in AR, IA, IL, ND and NJ are in a medically needy category; a senior and a disabled adult in AZ are not.medicaid_medically_needy_medical_expenses.yaml. Under the 2026 limit ($11,928) the old income passed both ways. The case now uses countable income of $15,000, so it still distinguishes deducting pretax premiums once from deducting them twice.make format(ruff)changelog.d/No file in
tests/policy/baseline/partners/changes. By static reading, the partner Medicaid cases in these states are seniors who already qualify through the aged, blind and disabled pathway, and the medically needy pathway applies only to people outside every other pathway. CI will confirm once the PR is ready.axiom: TheAxiomFoundation/rulespec-us#1938 queued
🤖 Generated with Claude Code