Repository navigation
Conversation
… limits - California: $20 any-income deduction from 2020-12-01 (ACWDL 20-24). - Connecticut: $562 / $1,124 unearned income disregard from 2026-01-01. - South Carolina: $50 general income disregard. - Missouri: July 1 asset limits for 2023 through 2026. - Arkansas, Oklahoma and South Carolina: asset limit equals the Medicare Savings Program resource limit, read from that parameter. Closes PolicyEngine#10356 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review
PR #10364 updates the optional Medicaid pathway for aged, blind and disabled people (is_optional_senior_or_disabled_for_medicaid) in CA, CT, MO, AR, OK and SC. IDs: C = critical, SA = should address, G = suggestion.
Paths: P/ = policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/, V/ = policyengine_us/variables/gov/hhs/medicaid/, T/ = policyengine_us/tests/policy/baseline/gov/hhs/medicaid/. Line numbers refer to the reviewed head.
Source Documents
- PDF: CA DHCS ACWDL 20-24, Income Disregard for the ABD FPL Program (9 pages; pages 1-8 read)
- PDF: CA DHCS ACWDL 00-57 (4 pages) and ACWDL 02-38 (5 pages)
- PDF: CT CHOICES Benefits Quick Guide, modified 5/29/2026 (9 pages) and CT DSS Program Standards Chart as of 1/1/2026 (1 page)
- PDF: SC Medicaid State Plan, Attachment 2.6-A (99 pages; pages 41, 42, 61, 70 and 71 read)
- PDF: MO MHABD Appendix J, 10/2026 edition (4 pages), with the archived 07-2025, 07/2024 and 10/2022 editions
- PDF: 13 CSR 40-8.020 (2 pages)
- PDF: AR DHS Medical Quick Reference Chart 2026 (6 pages)
- PDF: OKDHS Appendix C-1, 7/1/2026 edition (8 pages), plus 19 archived editions from 12/1/2015 to 4/1/2023
- Web: RSMo 208.010.2(7); MO DHSS notices (2023, 2024, 2025); MO FSD memos IM-70 (2021), IM-77 (2022), IM-57 (2023); Ark. Code R. 016.20.10-001, MS 23110 (Cornell); OAC 317:35-7-40 (current and 2001 text); SC MPPM Sections 100 and 300 (.docx); CT UPM 5030.15 (.doc); 42 USC 1396a(m), 1396d(p), 1395w-114
- Year: 2026. Every date that the PR adds or changes (2015-01-01 to 2026-07-01) was checked. Tests run for 2025-2027.
- Scope: PR changes (9 files), plus the pre-existing values in the MO and CA blocks that the PR edits
- Reviewed head SHA: d42beea
- Mode: full
Branch Status
The branch is 1 commit ahead and 35 commits behind main (12b899c11a). GitHub reports it as MERGEABLE. Rebase before merge. The staleness did not affect any finding.
What is correct
Every value and date that the PR adds or changes matches its source. CA is $20 / $20 from 2020-12-01. CT is $562 / $1,124 from 2026-01-01. SC is $50 / $50 from 2015, given once per couple. MO steps from 5,726 / 11,452 to 6,220.50 / 12,441 on each July 1 from 2023 to 2026. AR, OK and SC are tied to the federal MSP resource limit for 2015-2026. The PDF audit found 36 matches and no mismatch in a changed value. Reading the federal MSP parameter instead of copying dollar values is the right design, and it follows the uses_ssi_federal_benefit_rate pattern. The new flag lists all 51 keys. No legal value is hard-coded. The changelog fragment is correct. The PR body documents the Missouri July 1 dates and the January 1 read. Seven of the eight #page= anchors are correct. The PR touches no partner contract file, and the 70 healthcare partner contract tests pass.
Critical (Must Fix)
C1. CI failure: the Missouri at-limit couple test fails because the resources are float32.
- Test:
T/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.yaml:124-147, "Missouri couple at the couple resource limit is ineligible" (2026). It expects[false, false]and gets[true, true]. This breaks "Quick Feedback (Selective Tests + Coverage)" and "Full Suite - Baseline (contrib-hhs)". The local run gives the same failure. - Cause (probe
probe_mo_couple_float32.out):ssi_countable_resourcesis float32. The input 6,137.55 (line 133) is stored as 6,137.5498046875. The couple total is therefore 12,137.5498046875. The limit2025-07-01: 12_137.55(P/assets/limit/couple.yaml:85, read on 2026-01-01) is the float64 value 12,137.55. Soreturn assets < asset_limit(V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:36) returns true. The old case passed because its limit (11,452) was a whole dollar. - The expected
falsefollows 13 CSR 40-8.020(4)(B), which makes a household ineligible with countable assets "at or in excess of" the limit (FILE #page=2). The reviewers read the statute and the rule together as strict. Do not change the operator to<=for every state. See Next Steps item 5 for the repo's "statute governs" rule. - The same noise affects the 2026 individual limit 6,068.80 (stored as 6,068.7998). A 2025 couple at 11,818.45 is ineligible only by accident. The values 5,909.25, 6,220.50, 12,441 and all MSP limits are exact in float32.
- Fix: choose one option (probe
probe_fix_options.out). The C2 fix does not change the MO branch, so C1 needs its own fix.- Test only (recommended). Move the at-limit case to 2027, where the couple limit is the whole-dollar 12,441. Replace lines 124-147 with:
- name: Missouri couple at the July 2026 couple resource limit is ineligible
period: 2027
input:
people:
person1:
age: 70
ssi_countable_resources: 6_000
person2:
age: 68
ssi_countable_resources: 6_441
tax_units:
tax_unit:
members: [person1, person2]
tax_unit_is_joint: true
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: MO
output:
# 13 CSR 40-8.020(4)(B): ineligible "at or in excess of" the limit.
# 12,441 combined is not under the 12,441 couple limit effective July 1, 2026.
is_optional_senior_or_disabled_asset_eligible: [false, false] To keep the 2026 limit tested, add the same household with `period: 2026` and person2 at `6_200`. The output is `[false, false]`, because 12,200 is over 12,137.55.
- Test only. Keep 2026 and test one cent over the limit (person2
6_137.56, output[false, false]). Rename the case "Missouri couple one cent over the couple resource limit is ineligible". - Formula. Compare in whole cents, so that every decimal limit gives a fixed result. Change line 16 to
assets = np.round(person.marital_unit.sum(personal_assets), 2). With this change, the current 2026 case gives[false, false]under<. A precedent ispolicyengine_us/variables/gov/local/ca/sbd/general_relief/eligibility/ca_sbd_general_relief_income_eligible.py:20.
C2. Regulatory mismatch: the new MSP branch makes AR, OK and SC applicants with resources equal to the limit ineligible.
- Code:
V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:31-36. The PR ties AR, OK and SC to the federal MSP resource limit. It then tests that limit with strict<. The cited rules allow resources equal to the limit:- OK Appendix C-1, Schedule VI: resources "must be equal to or less than" $9,950 / $14,910 (FILE #page=2, visually verified). OAC 317:35-7-40(1): resources "do not exceed" Schedule VI.
- AR MS 23110(6): resources "equal to but not exceeding three times the SSI resource standard" (Cornell).
- SC MPPM 303.06.02 (eff. 01/01/26): countable resources "must be at or below" $9,950 / $14,910 (Section_300.docx). The State Plan uses "Same as QMB resource standards" (FILE #page=41), and the QMB rule is "do not exceed" (42 USC 1396d(p)(1)(C)).
- Probe (
v1/probe_at_limit.head.out): an AR or SC individual with $9,950 in 2026, and an OK couple with 7,455 + 7,455 = $14,910, fail the asset test. They also loseis_optional_senior_or_disabled_for_medicaid. The same people passmsp_asset_eligible, which uses<=on the same parameter (policyengine_us/variables/gov/hhs/medicare/savings_programs/eligibility/msp_asset_eligible.py:32). Three at-limit YAML cases fail at head and pass with the fix. - The strict operator is older than this PR (#5891). But this PR moves these states onto it, and the PR body says that the tests are "at the MSP limit". The new cases at lines 159, 169 and 194 are $50, $10 and $60 under the limit.
- Fix: keep Missouri strict (see C1) and make only the MSP branch inclusive. Replace lines 34-36 with the code below. Verified: the 11 proposed cases (below and in SA3) pass, and the Medicaid and Medicare suites give 995 passed and 1 failed, the C1 case only.
# The MSP resource standard (42 USC 1396d(p)(1)(C)) and the AR, OK
# and SC rules allow resources equal to the limit.
within_msp_limit = assets <= msp_limit
below_state_limit = assets < state_limit
return where(uses_msp_limit, within_msp_limit, below_state_limit)- Append these cases to
T/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.yaml:
- name: Arkansas applicant at the 2026 Medicare Savings Program individual resource limit is eligible.
period: 2026
input:
age: 70
ssi_countable_resources: 9_950
state_code: AR
output:
# MS 23110(6): resources "equal to but not exceeding" the MSP standard.
is_optional_senior_or_disabled_asset_eligible: true
- name: Arkansas applicant one dollar over the 2026 Medicare Savings Program individual resource limit is ineligible.
period: 2026
input:
age: 70
ssi_countable_resources: 9_951
state_code: AR
output:
is_optional_senior_or_disabled_asset_eligible: false
- name: South Carolina applicant at the 2026 Medicare Savings Program individual resource limit is eligible.
period: 2026
input:
age: 70
ssi_countable_resources: 9_950
state_code: SC
output:
# MPPM 303.06.02: countable resources "must be at or below" 9,950.
is_optional_senior_or_disabled_asset_eligible: true
- name: Oklahoma couple at the 2026 Medicare Savings Program couple resource limit is eligible.
period: 2026
input:
people:
person1:
age: 70
ssi_countable_resources: 7_455
person2:
age: 68
ssi_countable_resources: 7_455
tax_units:
tax_unit:
members: [person1, person2]
tax_unit_is_joint: true
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: OK
output:
# C-1 Schedule VI: resources "equal to or less than" 14,910.
is_optional_senior_or_disabled_asset_eligible: [true, true]C3. Regulatory mismatch: California now deducts only $20, but ACWDL 20-24 also deducts the Medicare Part B premium and health insurance premiums.
- Code:
P/income/disregard/individual.yaml:40andcouple.yaml:40(CA2020-12-01: 20). CA uses the default SSI path atV/income/_apply_medicaid_optional_senior_or_disabled_exclusions.py:73-79, which has no premium step. No variable in the ABD income chain reads a premium. - Source: ACWDL 20-24 FILE #page=3 says "Apply all applicable program deductions and disregards, including: the $20.00 Any Income deduction, health insurance premiums, and ...". The same page adds "A new disregard for Medicare Part B premiums", deducted "regardless of how the premium is paid". Example 1 (FILE #page=4) gives $1,350 - $20 - $144.60 (Part B) = $1,185. Examples 2-5 (FILE pages 5-8) also deduct Part B. The PR cites this page in its reference title ("#page 2-3").
- Effect (probe
v2/v2_probe_ca_partb.out): the old $230 was close to $20 + Part B ($222.90 in 2026). With only $20, a CA Medicare enrollee aged 70 with Social Security of $1,855.41 to $2,058.30 a month (139.5%-154.8% FPL) now fails the income test in 2026. That person also has no other Medicaid category. In 2021 the band is $1,501.21 to $1,649.70. Most ABD FPL enrollees are 65 or older and have Part B. - The new test asserts the gap. In
T/income/medicaid_optional_senior_or_disabled_countable_income.yaml:109-118the person (age 70) ismedicare_enrolledby default. Under ACWDL 20-24 the countable income is (1,000 - 20 - 202.90) x 12 = 9,325.20, not 11,760. - Fix (sketch, not run; check it against ACWDL 20-24 Examples 1-5):
- Add
P/income/deducts_health_insurance_premiums.yaml. List every other state as false, as inuses_msp_limit.yaml:
- Add
description: The state deducts Medicare Part B and other health insurance premiums from countable income under the optional senior or disabled pathway, if this is true.
metadata:
unit: bool
period: year
label: Medicaid senior or disabled pathway deducts health insurance premiums
breakdown:
- state_code
reference:
- title: "California DHCS All County Welfare Directors Letter 20-24, Aged and Disabled Federal Poverty Level program #page 3-4"
href: https://www.dhcs.ca.gov/services/medi-cal/eligibility/letters/Documents/20-24.pdf#page=3
CA:
2015-01-01: false
2020-12-01: true- In
V/income/medicaid_optional_senior_or_disabled_countable_income.py, insert this after line 59. Use the base premium, not the netmedicare_part_b_premium. The net premium is $0 when the MSP pays it, and it would create a Medicaid -> buy-in -> premium dependency.
# ACWDL 20-24: Part B is deducted "regardless of how the premium is
# paid", so use the base premium, not the net premium after MSP.
own_premiums = person("base_part_b_premium", period) * person(
"medicare_enrolled", period
) + person("health_insurance_premiums_without_medicare_part_b", period)
premiums = where(
couple_computation,
person.marital_unit.sum(own_premiums),
own_premiums,
)
p_income = parameters(
period
).gov.hhs.medicaid.eligibility.categories.senior_or_disabled.income
deducts_premiums = p_income.deducts_health_insurance_premiums[state]
personal_countable = max_(
personal_countable - where(deducts_premiums, premiums, 0), 0
)- Example 5 (FILE #page=8) also deducts the premium of a non-applicant spouse. Decide whether the spousal deeming path needs the same step.
- Change the CA test at lines 109-118. Assert 9,325.20 for the Medicare enrollee, or add
medicare_enrolled: falseto keep a $20-only case. Add a Part B case for 2021 or later (the Part B base premium parameter starts on 2021-01-01).
- Partner impact: the CA partner case (
partners/analytics_coverage/edge_cases/federal/healthcare/medicaid/ca.yaml) asserts eligibility, not countable income. With Part B deducted, its countable income is $1,110.10 a month, so the case stays eligible.
C4. Missing reference: no cited source shows the Missouri couple limits 11,452 (2023), 11,818.45 (2024) or 12,137.55 (2025).
- Code:
P/assets/limit/couple.yaml:83-85, with the references atcouple.yaml:15-26. The same reference block is inindividual.yaml:15-26. - The cited Appendix J URL is a living file. Today it is the 10/2026 edition, which shows only 6,220.50 / 12,441 (#page=1). The DHSS notices give individual amounts only. RSMo and 13 CSR give only the method.
- The values are correct (verified at 600 dpi). The 07/2024 edition, page 1, shows 11,818.45. The 07-2025 edition, page 1, shows 12,137.55. DSS memo IM-57 (June 8, 2023) shows "Couple Resource Limit: $11,452" from July 1, 2023. IM-57 is the only source for 11,452, so this item is critical. The 2024 and 2025 parts alone would be should-address items.
- Fix: in both files, add the edition to the title of the existing Appendix J entry. Then add the three entries below it:
- title: Missouri DSS MO HealthNet for the Aged, Blind and Disabled Appendix J - Eligibility Standards for Non-MAGI Programs (10/2026 edition; spend down resource maximum effective July 1, 2026)
href: https://dssmanuals.mo.gov/wp-content/uploads/2022/07/mhabd-appendix-j.pdf#page=1
- title: Missouri DSS Family Support Division, IM-57 July 2023 Annual Non-MAGI Program Adjustments (individual $5,726, couple $11,452 effective July 1, 2023)
href: https://web.archive.org/web/20230925041524/https://dssmanuals.mo.gov/2023/06/08/im-57-4/
- title: Missouri DSS MHABD Appendix J - Eligibility Standards for Non-MAGI Programs (07/2024 edition; spend down resource maximum effective July 1, 2024)
href: https://web.archive.org/web/20240612134513/https://dssmanuals.mo.gov/wp-content/uploads/2022/07/mhabd-appendix-j.pdf#page=1
- title: Missouri DSS MHABD Appendix J - Eligibility Standards for Non-MAGI Programs (07-2025 edition; spend down resource maximum effective July 1, 2025)
href: https://web.archive.org/web/20250831223642/https://dssmanuals.mo.gov/wp-content/uploads/2022/07/mhabd-appendix-j.pdf#page=1C5. Missing reference: the Oklahoma limits that the PR changes for 2015-2025 have no corroborating source.
- Code:
P/assets/limit/uses_msp_limit.yaml:13-16(OK references) and lines 94-95 (OKtruefrom 2015-01-01). Before the PR, OK was 2,000 / 3,000 for 2015-2023. The cited C-1 is the 7/1/2026 edition. The cited OAC page is "Revised 09-14-20" and has no dollar values. The PR body says that every C-1 edition back to 2014 shows the MSP figure, but it cites none of them. - The value is correct. Nineteen archived C-1 editions from 12/1/2015 to 4/1/2023 show that Schedule VI equals the federal MSP limit in each year (7,280 / 10,930 in 2015 to 9,090 / 13,630 in 2023). The old 2,000 / 3,000 came from Schedule VIII (SSI-related ABD), not Schedule VI.
- Fix: add these entries to the OK references in
uses_msp_limit.yaml. The 2015 edition is an XFA form, so it has no usable page anchor. It opens in Adobe Reader or Firefox.
- title: Oklahoma Human Services Appendix C-1 (edition 12/1/2015), Schedule VI (QMB Plus)
href: https://web.archive.org/web/20151216003834/http://www.okdhs.org/okdhs%20form%20library/C-1.pdf
- title: Oklahoma Human Services Appendix C-1 (edition 4/1/2023), Schedule VI (QMB Plus)
href: https://web.archive.org/web/20230420231329/https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-1.pdf#page=2
- title: Oklahoma Administrative Code 317:35-7-40(a)(1) (revised 05-11-01)
href: https://web.archive.org/web/20151029121301/http://www.okdhs.org/library/policy/oac317/035/07/0040000.htmShould Address
SA1. Wrong page anchor: the 13 CSR 40-8.020(4) href opens the table of contents.
- Code:
P/assets/limit/individual.yaml:20andcouple.yaml:20(13c40-8.pdf#page=1). FILE page 1 is the cover and the table of contents. Section (4) is on FILE page 2 (printed page 3). It contains the (4)(B) "at or in excess of" text and the (4)(C) CPI rule. - Fix in both files:
- title: 13 Missouri Code of State Regulations 40-8.020(4)(A)-(C)
href: https://www.sos.mo.gov/CMSImages/AdRules/csr/current/13csr/13c40-8.pdf#page=2SA2. Value mismatch (pre-existing, rated for this PR): Missouri's 3,000 / 6,000 from 2015 contradicts the statute and the rule that the PR now cites.
- Code:
P/assets/limit/individual.yaml:82andcouple.yaml:82. Annual calculations read the value on January 1, so 3,000 / 6,000 applies to every year from 2015 to 2023. - The law gives these values (13 CSR 40-8.020(4)(A)-(B), FILE #page=2, read at 600 dpi):
- before 7/1/2017: 1,000 / 2,000 (aged or disabled);
- then 2,000 / 4,000, 3,000 / 6,000, 4,000 / 8,000 and 5,000 / 10,000 on each July 1 from 2017 to 2020;
- 5,035 / 10,070 from 7/1/2021 (IM-70);
- 5,301.85 / 10,603.70 from 7/1/2022 (IM-77; Appendix J 10/2022, page 1).
- Only 2019 is right. For example, the model uses 3,000 for 2023, but the law gives 5,301.85.
- Why this is rated for this PR: the PR rewrites this MO block. It also attaches RSMo 208.010.2(7) and 13 CSR 40-8.020(4), and both contradict the entry. Every step now has a primary source. The PR did not make any year wrong that was right before: base and PR give the same annual values for 2015-2024. No MO test uses a year before 2025, so the fix breaks no test.
- Fix: replace the MO blocks (individual first, then couple):
MO:
2015-01-01: 1_000
2017-07-01: 2_000
2018-07-01: 3_000
2019-07-01: 4_000
2020-07-01: 5_000
2021-07-01: 5_035
2022-07-01: 5_301.85
2023-07-01: 5_726
2024-07-01: 5_909.25
2025-07-01: 6_068.8
2026-07-01: 6_220.5MO:
2015-01-01: 2_000
2017-07-01: 4_000
2018-07-01: 6_000
2019-07-01: 8_000
2020-07-01: 10_000
2021-07-01: 10_070
2022-07-01: 10_603.7
2023-07-01: 11_452
2024-07-01: 11_818.45
2025-07-01: 12_137.55
2026-07-01: 12_441Add these references to both files, together with the SA1 fix:
- title: Missouri DSS Family Support Division, IM-70 Annual MO HealthNet for the Aged, Blind, and Disabled (MHABD) Asset Limit Increase (individual $5,035, couple $10,070 effective July 1, 2021)
href: https://web.archive.org/web/20210801111201/https://dssmanuals.mo.gov/2021/07/01/im-70-2/
- title: Missouri DSS Family Support Division, IM-77 Annual MHABD Asset Limit Increase (individual $5,301.85, couple $10,603.70 effective July 1, 2022)
href: https://web.archive.org/web/20220705011659/https://dssmanuals.mo.gov/2022/06/14/im-77-3/
- title: Missouri DSS MHABD Appendix J - Eligibility Standards for MHABD (10/2022 edition; spend down resource maximum effective July 1, 2022)
href: https://web.archive.org/web/20220927091025/https://dssmanuals.mo.gov/wp-content/uploads/2022/07/mhabd-appendix-j.pdf#page=1- Minimum fix: add the
2021-07-01and2022-07-01steps, which correct 2022 and 2023, and track the 2015-2021 steps in an issue. Note: this parameter has no blind split. Before 7/1/2017, the blind limit was 2,000 / 4,000.
SA3. Missing edge cases: no couple disregard case for CA, CT or SC, and no pre-2024 case for the retroactive MSP linkage.
T/income/medicaid_optional_senior_or_disabled_countable_income.yamlhas only individual cases for CA, CT and SC (lines 109-140). No test in the repo reachesp.couple[state](V/income/medicaid_optional_senior_or_disabled_countable_income.py:47-51) for a changed couple value. So no test pins SC's "given only once in couple cases" (MPPM 303.06.03C) or the single $20 in ACWDL 20-24 Example 3 (FILE #page=5).T/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.yamltests the MSP branch only in 2025 and 2026. Every MSP case would still pass ifuses_msp_limitstarted in 2025. But the PR changes OK, AR and SC values back to 2015.- The PR body says "asset tests for AR and SC at the MSP limit, an OK couple at the MSP couple limit". The cases are under the limit. Correct the body, or add the C2 cases.
- Fix: these cases were run. Each one detects the PR change, and all of them pass at head. Append to the asset test file:
- name: Oklahoma uses the 2023 Medicare Savings Program individual resource limit.
period: 2023
input:
age: 70
ssi_countable_resources: 5_000
state_code: OK
output:
# 5,000 is under the 2023 limit of 9,090.
is_optional_senior_or_disabled_asset_eligible: true
- name: Oklahoma uses the 2015 Medicare Savings Program couple resource limit.
period: 2015
input:
people:
person1:
age: 70
ssi_countable_resources: 5_000
person2:
age: 68
ssi_countable_resources: 5_000
tax_units:
tax_unit:
members: [person1, person2]
tax_unit_is_joint: true
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: OK
output:
# 10,000 combined is under the 2015 couple limit of 10,930.
is_optional_senior_or_disabled_asset_eligible: [true, true]
- name: Arkansas uses the 2016 Medicare Savings Program individual resource limit.
period: 2016
input:
age: 70
ssi_countable_resources: 7_400
state_code: AR
output:
# 7,400 is over the 2016 limit of 7,280.
is_optional_senior_or_disabled_asset_eligible: false
- name: South Carolina uses the 2023 Medicare Savings Program individual resource limit.
period: 2023
input:
age: 70
ssi_countable_resources: 9_000
state_code: SC
output:
# 9,000 is under the 2023 limit of 9,090.
is_optional_senior_or_disabled_asset_eligible: trueAppend to the countable income file. The same household also gives CT (1,950 - 1,124) x 12 / 2 = 4,956 each and SC (1,950 - 50) x 12 / 2 = 11,400 each. Copy the case with state_code: CT and state_code: SC and those outputs. A $50 disregard for each spouse would give 11,100 in SC, so the SC case pins "given only once".
- name: California applies one 20-dollar deduction to a couple's combined unearned income.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1:
age: 70
is_tax_unit_head: true
ssi_unearned_income: 15_600
person2:
age: 68
is_tax_unit_spouse: true
ssi_unearned_income: 7_800
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: CA
output:
ssi_couple_computation_applies: [true, true]
# ACWDL 20-24 Example 3: (1,950 - 20) x 12 / 2 = 11,580 each.
medicaid_optional_senior_or_disabled_countable_income: [11_580, 11_580]- The C3 fix changes the CA couple case. After C3, add
medicare_enrolled: falseto both people, or assert the Part B deduction for both spouses. By hand, under the C3 sketch: (1,950 - 20 - 2 x 202.90) x 12 / 2 = 9,145.20 each.
Suggestions
- G1. Document the January 1 read next to the dated entries.
P/assets/limit/individual.yaml:81-86,couple.yaml:81-86andP/income/disregard/{individual,couple}.yaml:38-40. The lag is documented only in the PR body and in one test name. Fix: underMO:add# Annual calculations read parameters on January 1, so each July 1 value first applies in the next calendar year.UnderCA:add# The 2020-12-01 value first applies in 2021 annual calculations. - G2. Describe the MSP linkage in the variable.
V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:9, 31-34. Fix: makereferencea tuple that addshttps://www.law.cornell.edu/uscode/text/42/1396d#p. Add a one-line comment above line 31 that the flagged states use the QMB/MSP resource standard, as inmedicaid_optional_senior_or_disabled_income_limit.py:44-53. - G3. The omitted AR, OK and SC keys resolve to $0. In
P/assets/limit/individual.yamlandcouple.yaml, homogenization fills the missing keys with 0. As a result, the parameter page shows $0 for these states. A reform that setsuses_msp_limit.ARto false also makes every AR applicant asset-ineligible. This follows theuses_ssi_federal_benefit_rateprecedent, so it is not a defect. Fix: add a YAML comment that names the omitted states. You can also move the second description sentence into that comment, because a description has one sentence. Note: the variable reads only the MSP dollar limits, notgov.hhs.medicare.savings_programs.eligibility.asset.applies. Todayappliesis true for all three states. - G4. The CT couple value 1,124 rests only on the ADS CHOICES guide.
P/income/disregard/couple.yaml:48. Fix: add# Couple = 2 x the individual standard (UPM 5030.15 A: subtracted from each unit member's unearned income); it rises each January 1.The CHOICES label "Effective 3/1/26" follows the March medically needy update. The DSS chart "As of 1/1/2026" supports the January date. - G5. Several hrefs point to living documents. Appendix J, C-1, the AR chart and the CHOICES guide are replaced each year, and Appendix J has already lost the 2023-2025 values. Fix: for each dated value, also cite an archived edition. C4 and C5 do this for MO and OK. Wayback has no capture of the 10/2026 Appendix J yet (the latest capture is 2026-03-04). Request one and cite it.
- G6. The CA couple reference does not point to the one-$20 example.
P/income/disregard/couple.yaml:17. Example 3 is on FILE page 5. Fix, in the repo's format for nonconsecutive pages:title: "California DHCS All County Welfare Directors Letter 20-24, Aged and Disabled Federal Poverty Level program #page 2-3,5". - G7. Add more MSP and MO test points. AR 2026 couple 7,400 + 7,400 gives
[true, true]. SC 2026 couple 7,500 + 7,500 gives[false, false]. OK 2026 individual 9,900 givestrue. SC 2025 individual 9,700 givesfalse, which pins the year that the name at line 194 claims. MO 2026 individual 6,200 givesfalse(the mirror of line 149). MO 2025 individual 5,800 givestrue. Use a MO individual at-limit case only in 2027 (6,220.50 is exact). Do not use at-limit cases at 6,068.80, 11,818.45 or 12,137.55 (C1). - G8. The CA date boundary is not tested, although the name at line 109 claims it.
T/income/medicaid_optional_senior_or_disabled_countable_income.yaml:109. Fix: add CA 2021 (12,000 gives 11,760 for a person without Medicare) and CA 2020 (gives 9,240, because 230 applies to all of 2020). Alternatively, rename the case. An optional SC 2015 case (11,400) pins the SC date. - G9. Use one test-name style in each file. In the asset file, the names at lines 149, 159, 169 and 194 end with a period, and the names at lines 99 and 124 do not.
- G10. Re-date the CA 138% FPL income limit to 2020-12-01.
P/income/limit/individual.yaml:29-31andcouple.yaml:29-31(outside the diff) have CA2021-01-01: 1.38. ACWDL 20-24 (FILE #page=1) says "effective December 1, 2020". This has no annual effect. The new date would match the PR's new 2020-12-01 disregard entry. - G11. Follow-up: the CA disregard before 12/2020 understates the total by $20.
P/income/disregard/individual.yaml:39andcouple.yaml:39. The ACWDL 00-57 MC 176 form (FILE #page=3) subtracts the $20 any-income deduction. It then subtracts the $230 / $310 disregard after the earned-income steps (line 16), and health insurance premiums (line 17). ACWDL 02-38 (FILE #page=1) agrees. The helper puts the state value in place of the $20. So for unearned income, 230 / 310 is $20 too low. In 2019, Social Security of $1,270.84 to $1,290.83 a month flips to ineligible. Fix in a follow-up issue: use 250 / 330 from 2015-01-01, or apply 230 / 310 after the earned-income steps. Optional in this PR: cite ACWDL 00-57#page=3for the 2015-01-01 entry.
Out of scope / follow-up (pre-existing, not caused by this PR):
- AR ARSeniors is aged-only (MS 23110(1); the chart on page 2 says "only for individuals aged 65 or older"). But
uses_msp_limitapplies the MSP test to blind and disabled people under 65 too. The PR lists this as out of scope. P/assets/limit/individual.yaml:4hasperiod: month, butcouple.yaml:5hasperiod: year. This has no numeric effect, and the fix is one line.- In
P/assets/limit/couple.yaml:9-10, the KFF title and href do not match. - A larger operator design: use inclusive
<=by default (42 USC 1396a(m)(1)(C), "do not exceed"), with a by-state strict switch for MO likeincome/limit/requires_income_below_limit.yaml. This changes every non-MSP state at the limit, so it needs a separate issue. - Before 2015-01-01, the variable raises
ParameterNotFoundErrorfor every state. - The CT
income/limitentries for 2023 (0.327 / 0.149) were not checked. - Issue #9734 and the CA asset limit change on 2027-07-01 (the PR lists both).
Investigated and cleared:
- Page lists at the end of reference titles ("#page 2-3", "#page 41-42"): this is the repo
CLAUDE.mdrule for several cited pages, not a violation. - OK linkage values for 2015-2023: all 19 archived editions show the MSP figure. The January editions show the prior year until the April update. The federal standard changes on January 1, so the model is correct. Only the reference gap (C5) remains.
- CT 2026 income limit (raised by the PDF audit): this was a false positive. For 2026 the model reads 0.64 x FPG = $851.20 a month of countable income. The CHOICES guide gives $1,413 gross - $562 = $851.
- MO strict
<: correct for MO (13 CSR 40-8.020(4)(B)). - CT date 2026-01-01 against the CHOICES label "Effective 3/1/26": the date is accepted (DSS chart "As of 1/1/2026"; UPM 5030.15 "each January 1st").
- MO 2023 couple value 11,452: correct (IM-57 and the CPI derivation).
- SC $50 once per couple, with the unused part applied to earned income: the code gives the right numbers (probe: 6,900 and 2,490).
PDF Audit Summary
| Category | Count |
|---|---|
| Confirmed correct | 38 (36 in the PDF audit, plus 2 from the verifiers: MO couple 11,452 from IM-57, and OK Schedule VI = MSP for 2015-2023) |
| Mismatches (code-path confirmed + visually verified) | 0 in the values that the PR adds or changes. 2 regulatory mismatches in how the values are applied (C2, C3) |
| Mismatches rejected (code-path cleared) | 2 (OK 2015-2023 linkage value; CT 2026 income limit) |
| Unmodeled items | 2 (CA Part B and health insurance premium deductions, C3; AR ARSeniors aged-only rule, out of scope) |
| Pre-existing issues | 4 (MO 2015-2023 limits, SA2; CA $20 before 12/2020, G11; CA 138% FPL date, G10; period metadata and KFF title, out of scope) |
References: 18 distinct references added (30 entries). Of the 8 #page= anchors, 7 are correct and 1 is wrong (SA1). Three values had no corroborating cited source: MO couple 2023-2025 (C4) and OK 2015-2025 (C5).
Validation Summary
| Check | Result |
|---|---|
| Regulatory Accuracy | 2 critical (C2, C3); 1 should address (SA2) |
| Reference Quality | 2 critical (C4, C5); 1 should address (SA1); 4 suggestions (G4-G6, G10) |
| Code Patterns | 0 blocking. 10 categories pass, with no hard-coded values. 3 suggestions (G1-G3) |
| Formatting (params & vars) | 0 issues |
| Test Coverage | 1 failing test (C1); at-limit gap (inside C2); 1 should address (SA3); 3 suggestions (G7-G9) |
| PDF Value Audit | 0 mismatches in changed values / 36 confirmed (+2 by verifiers); 2 pre-existing MO mismatches (SA2) |
| CI Status | Failing: 15 pass, 3 skipping, 3 fail. "Quick Feedback" and "Full Suite - Baseline (contrib-hhs)" fail on C1. "Package and compatibility" fails at python .github/release_lock.py --refresh (v2.56.0 -> v2.56.1rc1). The PR changes no uv.lock, pyproject.toml or .github file, and #10365 passes this job, so this failure does not come from the PR |
| Local tests | Medicaid eligibility/categories: 245 passed, 1 failed (C1). Medicaid income: 164 passed. With the C2 fix, the Medicaid and Medicare suites give 995 passed and 1 failed (C1) |
| Partner contract tests | No partner file touched. 70 healthcare partner contract tests pass |
| Branch | 1 ahead, 35 behind main; MERGEABLE |
| Other reviews | None |
Review Severity: REQUEST_CHANGES
Next Steps
- Suggested order: C1 and C2 first (one formula edit and test edits in the same two files). Then C3, then the references (C4, C5, SA1), then SA2 and SA3.
- Run
policyengine-core test policyengine_us/tests/policy/baseline/gov/hhs/medicaid -c policyengine_usbefore you push. The PR body says that the tests were not run locally. - C3 changes CA countable income. Run the partner tests under
policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/healthcareagain. The CA case should stay eligible. Do not edit a partner file without the partner review gate. - Not assessed by the review delegates: the PR body has no
axiom:line. The repoCLAUDE.mdsection "Axiom Parity (required for policy changes)" asks for one line on every policy change:axiom: <legal id> encoded-correct | <rulespec PR> encoded | <rulespec issue> queued | n/a: <reason>. An external contributor who cannot do the Axiom work usesaxiom: needed. Add the line when you update the body. - Not assessed by the review delegates: the repo
CLAUDE.mdrule "Statute governs (ruled 2026-10-19)" says that a statute wins over a conflicting regulation. RSMo 208.010.2(7) says that a couple "may own resources not to exceed" the couple amount. 13 CSR 40-8.020(4)(B) says "at or in excess of" is ineligible. The reviewers read the two together as strict, because the statute's wording is garbled for an individual and RSMo 208.010.2(4) uses "or more". If you or a maintainer read this as a conflict, the statute governs. MO then needs<=, and the C1 test expects[true, true]. Record that choice in the source-conflict register with a# Source conflict MO:<id>line (CONTRIBUTING.md#source-conflicts). The float32 fix in C1 is still needed in both readings. - To auto-fix issues: run the fix-pr workflow for this PR.
…tory
- California's aged, blind and disabled income test deducts the Medicare
Part B premium and other health insurance premiums from December 2020
(ACWDL 20-24), through a new state flag.
- Resources equal to the Medicare Savings Program limit qualify in AR, OK
and SC; Missouri stays strict ("at or in excess of").
- Compare assets in whole cents so decimal limits are not affected by
float32 storage (fixes the Missouri at-limit couple test).
- Encode Missouri's asset limits from 2015 (13 CSR 40-8.020(4), IM-70,
IM-77) and cite archived Missouri and Oklahoma editions.
- Fix the 13 CSR page anchor, re-date CA's 138% FPL limit to 2020-12-01,
and add comments on the January 1 read and the MSP-linked states.
- Add at-limit, earlier-year MSP, couple disregard, CA Part B and CA date
boundary tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review
This is round 2 of the review of PR #10364. It covers the author's round-2 commit cd33ee1a4e (13 files, +504 / -24) and every round-1 finding. The later merge of main changes no PR file. IDs: C = critical, SA = should address, G = suggestion. Round-1 IDs (C1-C5, SA1-SA3, G1-G11) keep their numbers. New findings start at C6, SA4 and G12.
Paths: P/ = policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/, V/ = policyengine_us/variables/gov/hhs/medicaid/, T/ = policyengine_us/tests/policy/baseline/gov/hhs/medicaid/. Line numbers refer to the reviewed head.
Source Documents
- PDF: CA DHCS ACWDL 20-24, ABD FPL program (9 pages; all read)
- PDF: CA DHCS ACWDL 20-18, Medicare Part B premium disregard (pages 1-2 read; new in this round)
- PDF: CA DHCS ACWDL 00-57, MC 176 form (4 pages)
- Web: 22 CCR 50555.2 (health insurance premiums); 20 CFR 416.1163 (deeming)
- PDF: 13 CSR 40-8.020 (2 pages)
- Web: RSMo 208.010 (current text, and the 1998, 2005, 2010 and 2013 versions); RSMo 536.014
- Web/PDF: MO DSS memos IM-70, IM-77 and IM-57; MHABD Appendix J editions 10/2022, 07/2024 and 07-2025 (Wayback) and 10/2026 (live), FILE page 1 of each
- PDF: OKDHS Appendix C-1 editions 12/1/2015 (XFA form), 4/1/2023 and 7/1/2026 (FILE page 2); OAC 317:35-7-40 (2001 and current text)
- Web: Ark. Code R. 016.20.10-001, MS 23110; SC MPPM Section 300 (303.06.02, 303.06.03C); CT UPM 5030.15 and 5045.10; CT CHOICES guide
- Web: KFF, Medicare beneficiaries by type of entitlement, California 2024; CMS 2026 Part B fact sheet ($202.90)
- Year: 2026. Tests and probes ran for 2015-2027. The microsimulation used 2026 and the default dataset.
- Scope: the author's round-2 changes (13 files), plus every round-1 finding
- Reviewed head SHA: 42ae4f4
- Mode: incremental from d42beea
Branch Status
The branch is 3 commits ahead and 31 commits behind main (0e7ced1747). GitHub reports it as MERGEABLE. The merge of main into the branch changes no PR file. The staleness did not affect any finding.
What round 2 fixed
The author applied almost every round-1 fix as proposed. Thank you.
- C1: the asset test compares whole cents. The marital-unit sum is float64, so the MO at-limit couple now fails for the right reason.
- C2:
<=for the MSP branch and<for Missouri, with at-limit cases for AR, SC and OK. - C3: the new CA flag and premium step deduct the base Part B premium and other premiums. At 2026 premiums, ACWDL 20-24 Examples 1, 3 and 4 match exactly. Three gaps remain (C6, C7, SA4).
- C4, C5, SA1: every proposed reference is in place and corroborates its value.
- SA2: the Missouri schedule from 2015 to 2026 matches the sources (22 dated values). Tests are still missing (SA7).
- SA3: every proposed couple case and back-year MSP case is present.
- References: 35 references and values checked. 34 are correct, and 1 is wrong (C6).
- G1-G4, G6, G8-G10: done.
- Tests: Medicaid
eligibility/categories255 passed, Medicaidincome178 passed, Medicare 301 passed, healthcare partner contract tests 70 passed. No partner file changes. CI: 32 of 32 checks pass.
Three new items (C6, C7, SA4) come from our round-1 C3 sketch, which the author followed exactly. They correct our sketch. They are not author errors.
Round-1 status
| ID | Status | Evidence |
|---|---|---|
| C1 | RESOLVED | Whole-cent comparison at V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:20. Without the rounding, T asset file line 124 fails. |
| C2 | RESOLVED | <= for the MSP branch and < for MO (lines 41-45). The at-limit cases at T asset file lines 204-259 fail with <. |
| C3 | RESOLVED | Flag and premium step at V/income/medicaid_optional_senior_or_disabled_countable_income.py:63-79. Examples 1, 3 and 4 are exact. New gaps: C6, C7, SA4. |
| C4 | RESOLVED | IM-57 and Appendix J 07/2024 and 07-2025 are cited, and each shows the MO couple value. |
| C5 | RESOLVED | OK C-1 12/1/2015, C-1 4/1/2023 and OAC 2001 are cited. Each Schedule VI equals that year's MSP limit. |
| SA1 | RESOLVED | The 13 CSR href is #page=2, and the title is "(4)(A)-(C)". |
| SA2 | RESOLVED (values) | All 22 MO dated values match the sources. No test pins them (SA7). |
| SA3 | RESOLVED | CA, CT and SC couple cases (T income file lines 157, 184, 208). OK 2015 and 2023, AR 2016 and SC 2023 cases (T asset file lines 261-315). The body is corrected. |
| G1 | RESOLVED | January 1 comments in the MO, CA and new flag blocks. |
| G2 | RESOLVED | The reference tuple adds 42 USC 1396d(p). MSP comments at lines 35-36 and 41-42. |
| G3 | RESOLVED | Comment on the omitted states at P/assets/limit/{individual,couple}.yaml:40-42. The second description sentence is removed. |
| G4 | RESOLVED | CT comment and the body's "Not confirmed" section. The comment describes a per-member rule that the code does not apply (see Out of scope). |
| G5 | PARTIAL | MO and OK editions are archived. The 10/2026 Appendix J, the AR 2026 chart, the CHOICES guide (5/29/2026) and the OK C-1 7/1/2026 are not. Only the live Appendix J supports MO 6,220.50 / 12,441. |
| G6 | RESOLVED | The CA couple title ends with "#page 2-3,5". |
| G7 | PARTIAL | SC 2025 9,700 was added. The MO part moves to SA7. The MSP part remains (below). |
| G8 | RESOLVED | CA 2020 (9,240) and CA 2021 (11,760) cases. The first year of the premium flag moves to SA7. |
| G9 | RESOLVED | The names of the PR's test cases end with a period. |
| G10 | RESOLVED | CA 1.38 is dated 2020-12-01, with ACWDL 20-24 #page=1. |
| G11 | DECLINED (defensible) | The body lists it under "Follow-up", with no issue number. C6 adds the premium deduction to the same pre-12/2020 gap. |
Round-1 Next Steps 5 (Missouri statute against the rule): DECLINED. The author kept the strict test and registered no conflict. This is now SA8.
G7 remainder (suggestion; each case passes at head): AR 2026 couple 7,455 + 7,455 gives [true, true]. SC 2026 couple 7,455 + 7,455 gives [true, true], and 7,500 + 7,500 gives [false, false]. OK 2026 individual 9,950 gives true.
Critical (Must Fix)
C6. Value mismatch: the new California flag turns off the health insurance premium deduction for 2015-2020, but California deducted these premiums from 2001.
- Code:
P/income/deducts_health_insurance_premiums.yaml:20-23(CA: 2015-01-01: false,2020-12-01: true). This file is new in round 2. One boolean gates both the base Part B premium andhealth_insurance_premiums_without_medicare_part_b(V/income/medicaid_optional_senior_or_disabled_countable_income.py:63-79). - Sources:
- ACWDL 00-57, MC 176 (10/00) form (FILE #page=3): line 16 subtracts the $230 / $310 disregard, and line 17 subtracts "HEALTH INSURANCE PREMIUMS". The program started on January 1, 2001.
- ACWDL 20-24, the letter that the flag cites (FILE #page=3): the deductions used before the expansion "will continue to apply", and the list includes health insurance premiums. Only the Part B disregard is new.
- 22 CCR 50555.2(a) and (c): premiums that a family member pays are deducted. Part B is deducted only in the months when the beneficiary pays it.
- ACWDL 20-18 (FILE #page=2): before December 1, 2020, counties deducted Part B only when the person paid it. From that date, the disregard applies whoever pays.
- The two rules have two start dates. One boolean cannot encode both.
- Probe at head: a CA person aged 70, not on Medicare, with $12,000 of unearned income and $1,800 a year of other premiums. The result is 9,240 in 2015, 2019 and 2020 (no deduction) and 9,960 in 2021. By MC 176, the 2015-2020 amount is (1,000 - 230 - 150) x 12 = 7,440.
- There is no regression against
main, which deducted no premium in any year. Our round-1 C3 sketch prescribed thisfalseentry, although round-1 G11 already cited MC 176. The error is ours. - Fix: split the flag. This fix also closes SA4 and adds the SA5 NOTE. It was run on a copy of head: Medicaid
income178 passed,eligibility/categories255 passed, Medicare 301 passed, partner healthcare 70 passed. The case below and the 3 cases in SA4 fail at head and pass with the fix.- In
P/income/deducts_health_insurance_premiums.yaml, replace the header and the CA block. Keep the other 50 keys.
- In
description: The state deducts health insurance premiums that the person pays from countable income under the optional Medicaid pathway for seniors or people with disabilities, if this is true.
metadata:
unit: bool
period: year
label: Medicaid senior or disabled pathway deducts health insurance premiums
breakdown:
- state_code
reference:
- title: Cal. Code Regs. Tit. 22, § 50555.2 (a), (c) Health Insurance Premiums
href: https://www.law.cornell.edu/regulations/california/22-CCR-50555.2
- title: California DHCS All County Welfare Directors Letter 00-57, MC 176 Aged and Disabled FPL Financial Eligibility Form, line 17
href: https://www.dhcs.ca.gov/services/medi-cal/eligibility/letters/Documents/c00-57.pdf#page=3
- title: "California DHCS All County Welfare Directors Letter 20-24, Aged and Disabled Federal Poverty Level program #page 2-3"
href: https://www.dhcs.ca.gov/services/medi-cal/eligibility/letters/Documents/20-24.pdf#page=2CA:
# The ABD FPL program deducted premiums from its start in 2001.
2015-01-01: true- Add
P/income/disregards_medicare_part_b_premium.yaml. Give all 51 keys2015-01-01: false, except CA:
description: The state disregards the full Medicare Part B premium, regardless of who pays it, from countable income under the optional Medicaid pathway for seniors or people with disabilities, if this is true.
metadata:
unit: bool
period: year
label: Medicaid senior or disabled pathway Medicare Part B premium disregard
breakdown:
- state_code
reference:
- title: "California DHCS All County Welfare Directors Letter 20-18, Medicare Part B premium disregard #page 1-2"
href: https://www.dhcs.ca.gov/services/medi-cal/eligibility/letters/Documents/20-18.pdf#page=1
- title: "California DHCS All County Welfare Directors Letter 20-24, Aged and Disabled Federal Poverty Level program #page 3-8"
href: https://www.dhcs.ca.gov/services/medi-cal/eligibility/letters/Documents/20-24.pdf#page=3
CA:
# Before this date Part B counted only when the person paid it
# (22 CCR 50555.2(c)); deducts_health_insurance_premiums covers that.
# The 2020-12-01 value first applies in 2021 annual calculations.
2015-01-01: false
2020-12-01: true- In
V/income/medicaid_optional_senior_or_disabled_countable_income.py, replace lines 63-75 with the code below. Keep lines 76-79, or apply C7. Add"https://www.law.cornell.edu/regulations/california/22-CCR-50555.2"and"https://www.dhcs.ca.gov/services/medi-cal/eligibility/letters/Documents/20-18.pdf#page=2"toreference.
# 22 CCR 50555.2 deducts person-paid premiums, Part B only when the
# person pays it. From 12/2020 (ACWDL 20-18, 20-24) CA disregards Part B
# "regardless of how the premium is paid": swap the person-paid Part B
# in the shared aggregate for the full base premium.
# NOTE: medicare_enrolled (Part A and/or Part B) stands in for Part B
# enrollment, as in medical_expense_health_insurance_premiums.
medicare_enrolled = person("medicare_enrolled", period)
paid_premiums = person("medical_expense_health_insurance_premiums", period)
paid_part_b = person("medicare_part_b_premium", period) * medicare_enrolled
base_part_b = person("base_part_b_premium", period) * medicare_enrolled
disregards_part_b = p.disregards_medicare_part_b_premium[state].astype(bool)
own_premiums = where(
disregards_part_b,
max_(paid_premiums - paid_part_b, 0) + base_part_b,
paid_premiums,
)
premiums = where(
couple_computation,
person.marital_unit.sum(own_premiums),
own_premiums,
)- Append to
T/income/medicaid_optional_senior_or_disabled_countable_income.yaml:
- name: California deducted other health insurance premiums before 12/2020.
period: 2019
absolute_error_margin: 0.01
input:
age: 70
medicare_enrolled: false
ssi_marital_unearned_income: 12_000
health_insurance_premiums_without_medicare_part_b: 1_800
state_code: CA
output:
# ACWDL 00-57 MC 176 lines 16-17: (1,000 - 230 - 150) x 12 = 7,440.
medicaid_optional_senior_or_disabled_countable_income: 7_440- The CA 2020 case (T income file lines 255-257) keeps 9,240. Change its comment to: "2020 reads January 1, 2020: the 230 disregard applies, the Part B disregard does not, and the MSP pays Part B, so no person-paid premium is deducted."
- A simpler variant is acceptable: deduct other premiums from 2015 and no Part B before 12/2020, with a NOTE. Below the pre-12/2020 limit, the MSP pays Part B for almost everyone.
- The new titles also fix the page range of the current title, which stops at page 5. Examples 4 and 5 are on FILE pages 6-8.
C7. Incorrect formula: the zero floor comes before the deemed spouse income is added, so the applicant's excess premium is lost and eligibility flips.
- Code:
V/income/medicaid_optional_senior_or_disabled_countable_income.py:77-79floors the applicant's own countable income minus premiums at 0. Lines 89-96 then addspousal_deemed. When the premiums are more than the applicant's own countable income, the excess does not reduce the deemed income. - Sources:
- ACWDL 20-24 Example 2 (FILE #page=4, continued on page 5): the spouses' gross income "is combined, and then the deductions are applied".
- ACWDL 20-24 Example 5 (FILE #page=7, pages 7-8): the letter combines the incomes, then subtracts Part B and the premiums.
- 20 CFR 416.1163(d)(2): the deemed income is combined with the applicant's own income before the exclusions.
- Repo
CLAUDE.md:145: "Follow the exact order of operations specified in regulations".
- The test proves a flip. CA 2026: the applicant is 70, a Medicare enrollee, with $100 a month of unearned income. The spouse is 60, not aged, blind or disabled, with $2,520 a month. The limit is 29,863.20.
- Head: countable income
[30,240, 0],is_optional_senior_or_disabled_income_eligible[false, false],is_optional_senior_or_disabled_for_medicaid[false, false]. - Fix:
[28,765.20, 0],[true, true],[true, false]. Monthly: 100 + 2,520 - 20 - 202.90 = 2,397.10. - The letter's own method also gives "eligible": 100 + 2,520 - 20 - 202.90 - 600 (Maintenance Need Allowance) = 1,797.10, which is under the 1-person limit of 1,835.40. So head is wrong under the model's method and under the letter's method.
- Head: countable income
- Our round-1 C3 sketch put the floor in this position. This item corrects our sketch.
- Fix: replace lines 76-97 with the code below. Run on a copy of head: the two PR test files 41 passed, Medicaid
income178,eligibility/categories255, partner healthcare 70.ruff formatreports no change.
deducts_premiums = p.deducts_health_insurance_premiums[state].astype(bool)
deducted_premiums = where(deducts_premiums, premiums, 0)
spousal_deemed = person(
"medicaid_optional_senior_or_disabled_income_deemed_from_ineligible_spouse",
period,
)
is_eligible_individual = person("is_ssi_eligible_individual", period)
is_eligible_spouse = person("is_ssi_eligible_spouse", period)
is_eligible = is_eligible_individual | is_eligible_spouse
# ACWDL 20-24 Examples 2 and 5 combine the non-applicant spouse's
# income with the applicant's income before the deductions, as
# 20 CFR 416.1163(d)(2) does, so subtract the premiums from the
# combined income and floor the result.
countable = where(
couple_computation,
max_(personal_countable - deducted_premiums, 0) / 2,
max_(personal_countable + spousal_deemed - deducted_premiums, 0),
)
return where(is_eligible, countable, 0)- Append this case. It fails at head (30,240 and false) and passes with the fix:
- name: California deducts the applicant's Part B premium from income that includes deemed spouse income.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1:
age: 70
is_tax_unit_head: true
medicare_enrolled: true
ssi_unearned_income: 1_200
person2:
age: 60
is_tax_unit_spouse: true
ssi_unearned_income: 30_240
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: CA
output:
# ACWDL 20-24 Examples 2 and 5 deduct premiums from the combined income.
# Monthly, 100 + 2,520 - 20 - 202.90 = 2,397.10, so 28,765.20 a year,
# under the 29,863.20 limit. Flooring the applicant's own income first
# would lose 122.90 a month and give 30,240.
medicaid_optional_senior_or_disabled_countable_income: [28_765.2, 0]
is_optional_senior_or_disabled_income_eligible: [true, true]To keep the boolean output free of a margin, move the last output line into a copy of the case without absolute_error_margin.
- The C6 edit (lines 63-75) and the C7 edit (lines 76-97) do not overlap. Each edit ran alone on a copy. Run the suites again after you apply both.
Should Address
SA4. Pattern violation: the premium step ignores the direct health_insurance_premiums input.
- Code:
V/income/medicaid_optional_senior_or_disabled_countable_income.py:67-70reads onlyhealth_insurance_premiums_without_medicare_part_b. - The repo defines
health_insurance_premiumsas "an alternative to the applicable decomposed non-pretax inputs" (policyengine_us/variables/household/expense/health/health_insurance_premiums.py:14-22). The shared aggregatemedical_expense_health_insurance_premiums.py:20-28uses the direct input when it is nonzero. SNAP, medically needy, HUD and the itemized deduction read that aggregate. This variable is the only consumer that reads the decomposed input alone. - Probe: CA 2026, no Medicare, $12,000 of unearned income,
health_insurance_premiums: 1_200. Head gives 11,760. ACWDL 20-24 gives (1,000 - 20 - 100) x 12 = 10,560. With Social Security of $1,856 to $2,005 a month and $150 a month of premiums, the person is pathway-eligible with the decomposed input and ineligible with the direct input. - Exposure: in the default dataset, no CA aged, blind or disabled person has a nonzero direct input, so the microsimulation effect is zero. Household and API users who use the common field get the wrong result. The CA partner signature sends this field (0 today).
- Do not use
where(direct != 0, direct, part_b + other). For an enrollee whose Part B the MSP pays, it drops the base Part B: it gives 10,560, where the rule gives 8,125.20 and head gives 9,325.20. The other order counts a self-paid Part B twice. - Fix: apply the C6 code. It takes the shared aggregate, removes the person-paid Part B, and adds the base Part B. With decomposed inputs it gives the head result. Append these cases (they fail at head and pass with the C6 code):
- name: California deducts premiums entered as total health insurance premiums.
period: 2026
absolute_error_margin: 0.01
input:
age: 70
medicare_enrolled: false
ssi_marital_unearned_income: 12_000
health_insurance_premiums: 1_200
state_code: CA
output:
# ACWDL 20-24: (1,000 - 20 - 100) x 12 = 10,560.
medicaid_optional_senior_or_disabled_countable_income: 10_560
- name: California keeps the Part B disregard when the MSP pays Part B and other premiums are entered as a total.
period: 2026
absolute_error_margin: 0.01
input:
age: 70
medicare_enrolled: true
social_security_retirement: 12_000
health_insurance_premiums: 1_200
state_code: CA
output:
msp_part_b_premium_coverage: 2_434.80
# ACWDL 20-24: (1,000 - 20 - 202.90 - 100) x 12 = 8,125.20.
medicaid_optional_senior_or_disabled_countable_income: 8_125.20
- name: California does not count a self-paid Part B premium twice when it is part of the total premium input.
period: 2026
absolute_error_margin: 0.01
input:
age: 70
medicare_enrolled: true
social_security_retirement: 22_200
health_insurance_premiums: 3_634.80
state_code: CA
output:
medicare_part_b_premium: 2_434.80
# ACWDL 20-24: (1,850 - 20 - 202.90 - 100) x 12 = 18,325.20.
medicaid_optional_senior_or_disabled_countable_income: 18_325.20- Our round-1 C3 sketch read only the decomposed input. C3 stays RESOLVED.
SA5. Microsimulation default: medicare_enrolled (Part A and/or Part B) stands in for Part B enrollment, so Part A-only enrollees get the Part B disregard.
- Code:
V/income/medicaid_optional_senior_or_disabled_countable_income.py:65-66.medicare_enrolledis computed (adds = ["takes_up_medicare_if_eligible"], documented as "Part A and/or Part B"). In the default dataset, take-up is a data column (94.3% of CA people aged 65 or older). The model has no Part B enrollment variable. The repo's Part B chain uses the same gate (medicare_part_b_premium,msp_part_b_premium_coverage,medical_expense_health_insurance_premiums), so the PR follows the convention. - Direction: the model gives the $2,434.80 Part B disregard (2026) to Part A-only enrollees. This overstates the deduction and therefore CA pathway eligibility.
- Magnitude (2026, default dataset; a second run sets the base Part B premium to 0):
- CA pathway eligibles: 2.20 million (weighted). Of these, 143,209 (11 records, 6.5%) depend on the Part B deduction, and 70,058 of them have no other Medicaid category.
- KFF / CMS 2024: about 10% of CA Medicare beneficiaries have Part A only.
- Estimated overstatement: about 14,000 people (about 0.65% of CA pathway eligibles), of whom about 7,000 have no other Medicaid. The base is 11 records, so the estimate can be off by a factor of about 2.
- Offsetting bias (older than the PR): the dataset has no
months_receiving_social_security_disability, so the microsimulation reachesis_medicare_eligibleonly at age 65. About 518,500 CA disabled beneficiaries under 65 get no Part B disregard, which understates about 12,000 people at the same rate. The net effect is close to zero, and its sign is uncertain.
- The bias does not flip eligibility for a meaningful share of the population, so it is not critical. No code change is needed in this PR.
- Fix:
- Keep the
# NOTE:in the C6 code. If you do not apply C6, put the same NOTE above line 63. - Open a tracked issue: a Part B enrollment input (or a take-up split), and an imputation of
months_receiving_social_security_disabilityso that enrollees under 65 reachis_medicare_eligible. Cite the issue number in the PR body.
- Keep the
SA6. Missing edge case: no test pins the new zero floor.
- Code:
V/income/medicaid_optional_senior_or_disabled_countable_income.py:77-79. A mutation that removesmax_(..., 0)passes all 41 cases in the two PR test files. - Fix: append this case to the income file. It passes at head and after C7. Without the floor it gives -4,474.80. The floor binds with either premium source alone, so the case stays a floor test after C6, SA4 and SA5. The C7 case does not detect a removed floor, so add both.
- name: California countable income does not go below zero when premiums exceed income.
period: 2026
absolute_error_margin: 0.01
input:
age: 70
medicare_enrolled: true
health_insurance_premiums_without_medicare_part_b: 3_000
ssi_marital_unearned_income: 1_200
state_code: CA
output:
# (100 - 20) x 12 = 960, less 2,434.80 Part B and 3,000 premiums, floored at 0.
medicaid_optional_senior_or_disabled_countable_income: 0SA7. Missing edge cases: no test pins the dated values that the PR wrote for MO (2015-2025), AR (2015-2016) and CA (2020-12-01).
- MO:
P/assets/limit/individual.yaml:101-111andcouple.yaml:101-111. The only MO cases are for 2026 and 2027. These mutations pass all 41 PR cases: the round-1 schedule (3,000 / 6,000 from 2015, so the SA2 fix undone); the 2017-07 step one year early; and the 2018-07, 2019-07, 2020-07, 2021-07, 2022-07 and 2025-07 steps one year late. The 2026 limit is not pinned at all. - AR:
P/assets/limit/uses_msp_limit.yaml, AR2015-01-01: true. A linkage that starts in 2016 or 2017 passes. The AR 2016 case (T asset file line 296) is a "false" case, and the omitted AR key resolves to 0 (G3). - CA: the flag's
2020-12-01date. A flag that starts on 2022-01-01 passes, because the 2021 case (T income file line 233) has no Medicare. - Effect of each mutation: every AR applicant fails in 2015-2016; CA 2021 countable income changes by 1,782; a MO limit is wrong by a full step.
- Fix: append to
T/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.yaml. Each case passes at head and fails on the mutation that it pins.
- name: Missouri applies the 1,000-dollar individual resource limit in 2017.
period: 2017
input:
age: 70
ssi_countable_resources: 1_500
state_code: MO
output:
# 13 CSR 40-8.020(4)(A): 1,000 before July 1, 2017. 1,500 is over it.
is_optional_senior_or_disabled_asset_eligible: false
- name: Missouri couple at the 2018 couple resource limit is ineligible.
period: 2018
input:
people:
person1:
age: 70
ssi_countable_resources: 2_000
person2:
age: 68
ssi_countable_resources: 2_000
tax_units:
tax_unit:
members: [person1, person2]
tax_unit_is_joint: true
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: MO
output:
# 13 CSR 40-8.020(4)(B): ineligible "at or in excess of" the limit.
# 4,000 combined is not under the 4,000 couple limit effective July 1, 2017.
is_optional_senior_or_disabled_asset_eligible: [false, false]
- name: Missouri applies the July 2018 individual resource limit in 2019.
period: 2019
input:
age: 70
ssi_countable_resources: 2_500
state_code: MO
output:
# 2,500 is under the 3,000 limit effective July 1, 2018.
is_optional_senior_or_disabled_asset_eligible: true
- name: Missouri applies the July 2019 individual resource limit in 2020.
period: 2020
input:
age: 70
ssi_countable_resources: 3_500
state_code: MO
output:
# 3,500 is under the 4,000 limit effective July 1, 2019.
is_optional_senior_or_disabled_asset_eligible: true
- name: Missouri applies the July 2020 individual resource limit in 2021.
period: 2021
input:
age: 70
ssi_countable_resources: 4_500
state_code: MO
output:
# 4,500 is under the 5,000 limit effective July 1, 2020.
is_optional_senior_or_disabled_asset_eligible: true
- name: Missouri applies the July 2021 individual resource limit in 2022.
period: 2022
input:
age: 70
ssi_countable_resources: 5_020
state_code: MO
output:
# 5,020 is under the 5,035 limit effective July 1, 2021 (IM-70).
is_optional_senior_or_disabled_asset_eligible: true
- name: Missouri applies the July 2022 individual resource limit in 2023.
period: 2023
input:
age: 70
ssi_countable_resources: 5_200
state_code: MO
output:
# 5,200 is under the 5,301.85 limit effective July 1, 2022 (IM-77).
is_optional_senior_or_disabled_asset_eligible: true
- name: Missouri applies the July 2024 individual resource limit in 2025.
period: 2025
input:
age: 70
ssi_countable_resources: 5_800
state_code: MO
output:
# 5,800 is under the 5,909.25 limit effective July 1, 2024.
is_optional_senior_or_disabled_asset_eligible: true
- name: Missouri applies the July 2025 individual resource limit in 2026.
period: 2026
input:
age: 70
ssi_countable_resources: 6_000
state_code: MO
output:
# 6,000 is under the 6,068.80 limit effective July 1, 2025.
is_optional_senior_or_disabled_asset_eligible: true
- name: Arkansas applicant under the 2015 Medicare Savings Program individual resource limit is eligible.
period: 2015
input:
age: 70
ssi_countable_resources: 7_000
state_code: AR
output:
# 7,000 is under the 2015 Medicare Savings Program limit of 7,280.
is_optional_senior_or_disabled_asset_eligible: trueAppend to the income file:
- name: California deducts the 2021 Medicare Part B premium.
period: 2021
absolute_error_margin: 0.01
input:
age: 70
medicare_enrolled: true
ssi_marital_unearned_income: 12_000
state_code: CA
output:
# The December 2020 premium deduction first applies in 2021 annual
# calculations. The 2021 base premium is 148.50 a month.
# (1,000 - 20 - 148.50) x 12 = 9,978.
medicaid_optional_senior_or_disabled_countable_income: 9_978- After C6, the 2020-12-01 date moves to
disregards_medicare_part_b_premium. The CA 2021 case reads that date. - These cases close the MO part of G7. Use 6,000 (true) for 2026, not 6,200. Optional, not run: a 2024 case under 5,726 would also pin the 2023-07 step.
SA8. Source conflict not registered: for a Missouri couple at exactly the limit, RSMo 208.010.2(7) and 13 CSR 40-8.020(4)(B) disagree.
- Code: the deciding line is
V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:44(below_state_limit = assets < state_limit). The test isT/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.yaml:124-147. The PR cites both texts inP/assets/limit/couple.yaml:17-20. - RSMo 208.010.2(7): a married couple "may own resources not to exceed" the couple amount, so the limit itself qualifies. Subdivision 2(4) has had the same couple wording since 1998. 13 CSR 40-8.020(4)(B) (FILE #page=2) makes a household ineligible "at or in excess of" the limit. For a couple at the limit, no reading makes both texts true. RSMo 536.014(2) says that a rule in conflict with state law is not valid.
- Round 1 read the statute as strict because 2(4) says "or more". That wording applies to individuals only. For individuals, the agency's strict reading is a defensible tie-break.
- Repo rule (
CLAUDE.md:148,CONTRIBUTING.md"Source conflicts", refined after round 1): a regulation that flatly contradicts its statute goes to the project lead, who decides it, and the ruling goes in the register. Every such choice is recorded and the deciding line is marked. The PR body says "Source conflicts: none registered". - Precedent:
us-co:premium-assistance-ptc-recipients(a state statute against a state regulation) was ruled in October 2026 to follow the statute. - Probe: MO 2026 couple at 12,137.55 gives
[false, false]at head and[true, true]with<=for MO couples. One cent over gives[false, false]in both. Individuals do not change. With<=, only the T:124 case fails. - Effect: only couples whose resources equal the limit to the cent. The microsimulation effect is about zero.
- This is should-address now. It becomes critical if the project lead rules for the statute and the PR does not change.
- Fix:
- Ask the project lead for a ruling. Add this entry to
source_conflicts/candidates.yaml, betweenus-mo:medicaid-published-dollar-limit-roundingandus-mo:negative-federal-agi-combined-return. It passespolicyengine_us/tests/code_health/test_source_conflicts.pyon a copy. Change the PR body line to "Source conflicts: open,us-mo:mhabd-couple-resource-limit-boundary(project lead ruling requested)".
- Ask the project lead for a ruling. Add this entry to
- id: us-mo:mhabd-couple-resource-limit-boundary
program: medicaid
years:
from: 2015
type: calendar
question: Is a Missouri aged, blind or disabled couple whose countable resources equal the couple limit eligible,
as the statute's "not to exceed" says, or ineligible, as the rule's "at or in excess of" says?
sources:
- kind: statute
citation: RSMo 208.010.2(7) (208.010.2(4) before fiscal year 2018)
url: https://revisor.mo.gov/main/OneSection.aspx?section=208.010
- kind: regulation
citation: 13 CSR 40-8.020(4)(A)1.B and (4)(B)
url: https://www.sos.mo.gov/CMSImages/AdRules/csr/current/13csr/13c40-8.pdf#page=2
readings:
statute: A married couple living together "may own resources not to exceed" the couple amount, so resources
equal to the limit qualify.
other: A household with countable assets "at or in excess of" the limit is ineligible.
example: A 2026 Missouri couple with $12,137.55 of countable resources is eligible under the statute and ineligible
under the rule.
pe_us:
follows: conflicting-source
code:
- policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py
prs:
- https://github.com/PolicyEngine/policyengine-us/pull/10364
state: open
note: The project lead decides whether the rule's strict test, which contradicts the statute's couple wording,
is followed (RSMo 536.014 voids a rule in conflict with state law).- If the lead rules for the statute: add
P/assets/limit/couple_limit_inclusive.yaml(bool by state, all 51 keys2015-01-01: falseexceptMO: 2015-01-01: true, reference RSMo 208.010.2(7)), as inP/income/limit/requires_income_below_limit.yaml. Replace lines 44-45 with the code below. Rename T:124 to "Missouri couple at the couple resource limit is eligible.", set the output to[true, true], and add the same household at6_137.56with[false, false].
# RSMo 208.010.2(7): a married couple "may own resources not to
# exceed" the couple amount.
couple_may_equal_limit = is_couple & p.assets.limit.couple_limit_inclusive[
state
].astype(bool)
within_state_limit = where(
couple_may_equal_limit, assets <= state_limit, assets < state_limit
)
return where(uses_msp_limit, within_msp_limit, within_state_limit)- If the lead keeps the rule: no code change. In rulespec-us, add the entry with
followsset to the regulation, underproposeduntil the PR merges. - In both cases, after the entry is on rulespec-us
main: runpython scripts/update_source_conflicts.py --commit <sha>, put# Source conflict us-mo:mhabd-couple-resource-limit-boundaryalone on the line directly above the deciding line, and delete the backlog entry. A marker added earlier fails the guard. Round 1 suggested the formMO:<id>; the guard needsus-mo:<id>.
Suggestions
- G12. The base Part B premium has no value before 2021.
policyengine_us/parameters/gov/hhs/medicare/part_b/base_premium.yamlstarts on 2021-01-01, so core returns $148.50 for 2015-2020. At baseline the flag masks this. After C6, a person-paid Part B before 12/2020 readsmedicare_part_b_premium, which uses this value. That affects only MSP-ineligible enrollees, whose income is already over the pre-12/2020 limit. A reform that turns on the CA Part B disregard for 2020 deducts 1,782 a year, but ACWDL 20-24 Example 1 uses $144.60 a month. Fix: add the 2020 value to the federal file with the CMS 2020 fact sheet, or add a comment to the flag. - G13. Document the Example 5 decline in the code. The PR body says that the non-applicant spouse's premium is "Not modeled", but the code has no note. Add above line 63:
# NOTE: ACWDL 20-24 Example 5 also deducts a non-applicant spouse's premiums. Spousal income here follows SSI deeming (20 CFR 416.1163), so that premium is not modeled.Optional: pin Example 5 at 2026 premiums. Applicant 70 with Medicare andssi_unearned_income: 18_000; spouse 60 withssi_unearned_income: 12_000,employment_income: 8_400andhealth_insurance_premiums_without_medicare_part_b: 1_200. The model gives deemed income[15_810, 0], countable income[31_135.2, 0]andis_optional_senior_or_disabled_income_eligible[false, false], which is the letter's result. The case passes at head and after C7. - G14. Show that a state other than CA deducts no premium. The non-CA cases detect a premium step that runs for every state only because people aged 65 or older are Medicare enrollees by default. Append this case (it passes at head; with the step on for every state it gives 8,125.20):
- name: North Carolina does not deduct Medicare Part B or other health insurance premiums.
period: 2026
absolute_error_margin: 0.01
input:
age: 70
medicare_enrolled: true
health_insurance_premiums_without_medicare_part_b: 1_200
ssi_marital_unearned_income: 12_000
state_code: NC
output:
# Only California deducts premiums: (1,000 - 20) x 12 = 11,760.
medicaid_optional_senior_or_disabled_countable_income: 11_760Out of scope / follow-up (pre-existing, not caused by this PR):
- CT couple disregard: the model pools it, but UPM 5030.15 A applies it to each member. UPM 5030.15 A subtracts the disregard from "the unit member's" own unearned income, and UPM 5045.10 E sums the members' results. The model subtracts 2 x 562 = 1,124 once from the couple's combined unearned income (
V/income/_apply_medicaid_optional_senior_or_disabled_exclusions.py:18-21). It deducts up to $562 a month too much when one spouse has less than $562. Probe, CT 2026 couple: 21,400 + 0 gives 3,956 each and eligible in the model, but 7,328 each and ineligible under the UPM. The formula is older than the PR, and the PR's 1,124 is correct. But the comment atP/income/disregard/couple.yaml:45-47(our round-1 G4 text) and the test name at T income file line 184 describe a per-member rule that the code does not apply.CONTRIBUTING.md:126requires a fix or an issue. Fix: open an issue, then replace the comment with:
# UPM 5030.15 A subtracts the individual disregard from each unit member's
# own unearned income. The model subtracts this couple value (2 x the
# individual standard from 2024) from the couple's combined unearned income,
# so it deducts too much when a spouse has less unearned income than the
# individual disregard (issue #NNNN). It rises each January 1.Rename the T:184 case to "Connecticut couple with each spouse above the individual disregard gets the full 2026 couple disregard." A per-member fix (the sum over members of min(own monthly unearned income, 562)) ran on a copy: 433 Medicaid tests pass, and 18,000 + 3,600 gives 5,628 each. Use a by-state bool parameter, not a state string.
- Carried from round 1: AR ARSeniors is aged-only; the asset files have different
periodmetadata; the KFF titles inP/assets/limit/couple.yaml:9-10andP/income/limit/{individual,couple}.yaml:9; an inclusive default operator with a strict switch for MO;ParameterNotFoundErrorbefore 2015-01-01; the CT 2023 income limits were not checked; the CT couple values before 2024 (PR body); issue #9734; the CA asset limit change on 2027-07-01. - The PR body lists as "Not modeled": CA's whole-dollar rounding of countable income (at most $0.50 a month) and CA's Maintenance Need Allowance method for spouses.
Investigated and cleared:
- Whole-cent rounding: legally neutral. It changes a result only within half a cent of a fractional limit, which only MO has. The readers
is_optional_senior_or_disabled_for_medicaidandis_209b_ssi_recipient_for_medicaidpass. - Premium step outside CA: a 51-state comparison with and without the step differs only in CA rows from 2021. The cost is negligible, and there is no dependency cycle.
- ACWDL 20-24 Examples 2 and 5: the model gives the letter's eligibility result.
- CA partner case: $1,110 a month in 2026, still eligible.
pre_tax_health_insurance_premiums: already removed from SSI wages, so adding them would count them twice.- CPS premiums do not appear to include Part B, so the step does not count Part B twice.
PDF Audit Summary
| Category | Count |
|---|---|
| Confirmed correct | 34 of 35 references and values checked (22 MO dated values, OK C-1 2015 and 2023, OAC 2001, ACWDL 20-24 anchors, 42 USC 1396d(p), quotes in tests) |
| Mismatches (code-path confirmed + visually verified) | 1: CA flag 2015-01-01: false (C6) |
| Not checked | 1: the 50 other keys of the new flag (no source cited; outside the six PR states) |
| Unmodeled items | 2: ACWDL 20-24 Example 5 spouse premium (G13); CA whole-dollar rounding |
| Pre-existing issues | 2: CA $20 before 12/2020 (G11); CT pooled couple disregard (follow-up) |
Validation Summary
| Check | Result |
|---|---|
| Regulatory Accuracy | 2 critical (C6, C7); 1 should address (SA8) |
| Reference Quality | 34 of 35 correct (the wrong one is C6). 1 suggestion (G5, partial) |
| Code Patterns | 2 should address (SA4; SA5, microsimulation default); 1 suggestion (G12). No hard-coded values |
| Formatting (params & vars) | 0 issues |
| Test Coverage | 2 should address (SA6, SA7); 2 suggestions (G13, G14) and the G7 remainder. The PR tests kill 7 of 14 mutations; the proposed cases kill the other 7 |
| PDF Value Audit | 1 mismatch (C6); 34 confirmed |
| CI Status | Passing: 32 of 32 checks |
| Local tests | Medicaid eligibility/categories 255 passed; Medicaid income 178 passed; Medicare 301 passed |
| Partner contract tests | No partner file touched. 70 healthcare partner tests pass at head and on the C6 and C7 fix copies |
| Branch | 3 ahead, 31 behind main; MERGEABLE |
| Other reviews | None |
Review Severity: REQUEST_CHANGES
Next Steps
- Suggested order: C6 with SA4 (one code edit at lines 63-75, the flag split and 5 cases). Then C7 (lines 76-97) and SA6. Then SA7. Ask the project lead about SA8 now, because the ruling can come in parallel. SA5 needs only the NOTE (already in the C6 code) and an issue.
- The C6 and C7 edits were each verified alone. After you apply both, run
policyengine-core test policyengine_us/tests/policy/baseline/gov/hhs/medicaid -c policyengine_usand the Medicare tests. - C6 and C7 change CA countable income for some households. Run the partner tests under
policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/healthcareagain. Do not edit a partner file without the partner review gate. - Open the follow-up issues and cite their numbers in the PR body: the CA rules before 12/2020 (G11, and Part B if you take the simpler C6 variant); Part B enrollment and SSDI months (SA5); the CT per-member disregard (Out of scope).
- Process note, not counted: the PR body still has no
axiom:line (round-1 Next Steps 4). The repoCLAUDE.mdsection "Axiom Parity (required for policy changes)" asks for one line on every policy change:axiom: <legal id> encoded-correct | <rulespec PR> encoded | <rulespec issue> queued | n/a: <reason>. An external contributor who cannot do the Axiom work usesaxiom: needed. - To auto-fix issues: run the fix-pr workflow for this PR.
…-2020 CA disregard, MO couple limit - Split the CA flag: person-paid health insurance premiums from 2015 (22 CCR 50555.2, MC 176 line 17); full Part B disregard from 2020-12-01 (ACWDL 20-18, 20-24), read from the shared premium aggregate. - Floor countable income after adding deemed spouse income. - Before 12/2020, CA applies the $20 deduction and then the $230/$310 disregard (ACWDL 00-57, MC 176 lines 8 and 16). - Missouri couples at the couple limit qualify (RSMo 208.010.2(7)); candidate us-mo:mhabd-couple-resource-limit-boundary, ruling pending. - Tests pinning MO 2017-2026, AR 2015, CA 2020/2021 dates, the floor, direct premium input and an NC no-deduction case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@MaxGhenis, as project lead, could you rule on a statute-against-regulation conflict? Under CONTRIBUTING.md#source-conflicts, a regulation that flatly contradicts its statute goes to you. Question. A Missouri aged, blind or disabled couple's countable resources equal the couple limit exactly. Are they eligible?
Example. In 2026, a couple with $12,137.55 of countable resources is eligible under the statute and ineligible under the rule. What the PR does now. It follows the statute for couples ( Precedent. After your ruling, the entry goes into the rulespec-us register, and the |
|
Thanks, @PavelMakarchuk. Round 2 is applied in d038f14. Item by item: Critical
Should address
Suggestions
Out of scope
Not run locally, per our practice. CI will run the suites. Partner case: the California partner senior is still $1,110 a month in 2026. The pre-2021 changes do not reach it, and no partner file changes. Axiom line: the |
|
@PavelMakarchuk Since you're handling these Medicaid PRs, could you sign off on the Missouri reading in SA8 (
A one-word answer is enough: "statute" or "regulation". This replaces the ruling request above. |
…y-values # Conflicts: # source_conflicts/candidates.yaml
- New by-state flag individual_limit_inclusive (CA) and CA true in couple_limit_inclusive: resources may not exceed the limit (22 CCR 50420(a), WIC 14005.40(c)(5), 42 USC 1396a(m)(1)(C)). - CA asset limit $130,000 / $195,000 from 2022-07-01 (ACWDL 21-31), which the ABD pathway lacked. - Tests: CA 2026 single at and one cent over the limit, a couple at $195,000, and 2023 at $130,000. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@PavelMakarchuk, one more fix since your re-review, in e3bc1ef:
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PolicyEngine#10364 adds the same California 2022-07-01 rows, ACWDL 21-31 reference and 2023 case to the senior_or_disabled asset files. Remove them here to avoid duplicate edits; keep the 2027 January 1 case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Minn. Stat. 256B.056, subd. 1b (since 2001): the SSI $20 general income disregard "is included in the standard and shall not be allowed as a deduction from income" for aged, blind and disabled people. MN disregard is 0 from 2015, so none moves to earned income; the $65 and one-half earned exclusions still apply. Tests at and $1 over the 2026 limit, and an earned-income case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@PavelMakarchuk, one more small addition in 60ef70c: Minnesota's ABD disregard is now $0, because Minn. Stat. 256B.056, subd. 1b says the SSI $20 "is included in the standard and shall not be allowed as a deduction from income". It has cases at and $1 over the 2026 limit, plus an earned-income case. No re-review needed beyond your current pass. |
|
Ruling on
The candidate will record this comment as the ruling. The register entry and the code marker follow the merge. |
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
This is round 3 of the review of PR #10364 (author hua7450). It covers the author's five commits since round 2 (d038f14d37, e3bc1ef97a, d3314169a7, 60ef70cb9c, 216aa268a1) and every round-2 finding. The merges of main change no PR variable, parameter or test file. IDs: C = critical, SA = should address, G = suggestion. Round-2 IDs (C1-C7, SA1-SA8, G1-G14) keep their numbers. New findings start at C8, SA9 and G15.
Paths: P/ = policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/, V/ = policyengine_us/variables/gov/hhs/medicaid/, T/ = policyengine_us/tests/policy/baseline/gov/hhs/medicaid/. "T asset file" = T/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.yaml; "T income file" = T/income/medicaid_optional_senior_or_disabled_countable_income.yaml. Line numbers refer to the reviewed head.
Source Documents
- PDF: CA DHCS ACWDL 20-18 (FILE pages 1-3), ACWDL 20-24 (9 pages), ACWDL 00-57 (MC 176 on FILE page 3), all read as page images from Wayback copies with the round-2 checksums
- PDF: ACWDL 21-31 (4 pages, new), ACWDL 02-38 and 01-18 (the program's question-and-answer letters, new), ACWDL 25-14 (limit table)
- Web: WIC 14005.40 (2017, 2020, 2022 and current text), 14005.62, 14005.401; 22 CCR 50420; 22 CCR 50555.2; 42 USC 1396a(m); 42 USC 1395r(i) (IRMAA); 20 CFR 416.1163
- Web: RSMo 208.010 (current text and its version list; the 2013 version); H.B. 1565 (2016), truly agreed (FILE pages 3-4); RSMo 536.014; Mo. Const. art. IV, sec. 23
- PDF: 13 CSR 40-8.020 (FILE page 2); 13 CSR 40-2.030(12), 11/30/15 edition (FILE pages 9-10), the 1/29/14 pages and the current edition
- Web: Minn. Stat. 256B.056 (current, 2014, 2000 and 2002 text) and 256B.055; MN DHS EPM 2.3.3.3.1, 2.3.3.3.2.2 and 2.3.3.2.1; KFF 2018 appendix tables
- PDF: OKDHS Appendix C-1, 7/1/2026 (Wayback, FILE page 2)
- Year: 2026. Tests and probes ran for 2015-2027.
- Scope: the author's changes since round 2 (18 PR files), plus every round-2 finding. The law and code checks ran at
60ef70cb9c. The only author change since then,216aa268a1, edits onlysource_conflicts/candidates.yaml. The proposed cases were run again at the reviewed head. - Reviewed head SHA: 45120fa
- Mode: incremental from 42ae4f4
Branch Status
The branch is 11 commits ahead and 6 behind main. GitHub reports it as MERGEABLE, blocked only by the requested changes. The merges of main since round 2 change no PR variable, parameter or test file. At 60ef70cb9c, a test merge with main was clean, and 482 Medicaid cases passed on it. The staleness did not affect any finding.
What round 3 fixed
The author applied the round-2 fixes as proposed, apart from two defensible declines (G5, G7 remainder), and added three correct changes. Thank you.
- C6, C7, SA4, SA6: the flag split, the shared premium aggregate with the Part B swap, and the floor after the deemed income are in, with all proposed cases. The 2019 case expects 7,200, not our 7,440. That is right: MC 176 line 8 takes the $20 first, and our sketch left line 8 out.
- SA5, G12, G13: the three NOTEs are in. Issue #10457 tracks Part B enrollment and SSDI months.
- SA7, G14: one Missouri case for each dated value from 2017 to 2027, plus the AR 2015, CA 2021 and NC cases.
- G11: now encoded, in the MC 176 order. The side effect that the author flagged (an applicant whose spouse is not aged or disabled gets $230, not $310) is correct.
- California assets: resources equal to the limit qualify (22 CCR 50420(a), WIC 14005.40(c)(5)), and the $130,000 / $195,000 step of 2022-07-01 is in (ACWDL 21-31). Both are correct.
- Minnesota: the $0 disregard follows Minn. Stat. 256B.056, subd. 1b and the DHS manual.
- SA8: couples follow the statute. The candidate is in the backlog and records the ruling for couples.
- References: 16 values and 15 parameter references checked from page images. All are correct, except the Missouri items in C8.
- CI: 33 of 33 checks pass. The PR's three test files hold 105 cases.
Two new critical items come from our own round-2 text. C9 is a gap in our round-2 C6 code, which the author applied word for word. C8 follows our round-2 note that the strict test for Missouri individuals was "a defensible tie-break". That note was wrong from fiscal year 2018. Neither item is an author error.
Round-2 status
| ID | Status | Evidence |
|---|---|---|
| C1 | RESOLVED (code); pin lost | Whole-cent rounding at V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:22. With <= for MO couples, no case detects its removal (SA9a). |
| C2 | RESOLVED | <= for the MSP branch (line 45). The AR, OK and SC at-limit cases are unchanged. |
| C3 | RESOLVED | Replaced by the C6 and C7 code. |
| C4 | RESOLVED | The MO references and dated values are unchanged. |
| C5 | RESOLVED | The OK C-1 2015 and 2023 editions and OAC 2001 are unchanged. |
| C6 | RESOLVED | P/income/deducts_health_insurance_premiums.yaml:24-26 (CA true from 2015) and P/income/disregards_medicare_part_b_premium.yaml:22-27 (CA from 2020-12-01). All five references corroborate. Probe: 7,200 in 2015, 2019 and 2020, and 9,960 in 2021, as MC 176 gives. New gap in the same code: C9. |
| C7 | RESOLVED | Floor after the deemed income at V/income/medicaid_optional_senior_or_disabled_countable_income.py:119-123. Cases at T income file lines 398 and 426 give [28,765.20, 0] and eligible. A floor before the deemed income fails them. |
| SA1 | RESOLVED | The 13 CSR href is still #page=2. |
| SA2 | RESOLVED | Values unchanged, and SA7 now pins them. |
| SA3 | RESOLVED | The couple and back-year MSP cases are unchanged. |
| SA4 | RESOLVED | The shared aggregate at line 80. Cases at T income file lines 357, 370 and 384 give 10,560, 8,125.20 and 18,325.20. The direct and decomposed inputs now give the same result in the round-2 flip window. |
| SA5 | RESOLVED | NOTE at lines 72-73. Issue #10457 is open and cited in the body. |
| SA6 | RESOLVED | Floor case at T income file line 450. The couple-branch floor is not pinned (G15). |
| SA7 | RESOLVED | MO cases at T asset file lines 352-458, AR 2015 at line 468, CA 2021 at T income file line 343. Every round-2 date mutation now fails a case. The 2018 couple at $4,000 now expects eligible, as the ruling requires. |
| SA8 | PARTIAL | Couples use <= through P/assets/limit/couple_limit_inclusive.yaml. The candidate at source_conflicts/candidates.yaml:3732 has state: ruled. Open: individuals (C8), the candidate text and the register steps (SA8 below). |
| G1 | RESOLVED | The January 1 comments are kept, also in the new files. |
| G2 | RESOLVED | No change. |
| G3 | RESOLVED | No change. |
| G4 | RESOLVED | The CT comment now matches the code and cites issue #10458. |
| G5 | PARTIAL (defensible) | The OK C-1 7/1/2026 now cites a Wayback copy, which is byte-identical to the copy we read. The 10/2026 Appendix J, the AR 2026 chart and the CHOICES guide of 5/29/2026 still have no capture, and the body says so. Anyone can request a capture with Save Page Now, so this stays a suggestion. |
| G6 | RESOLVED | No change. |
| G7 | RESOLVED; remainder DECLINED (defensible) | SC couple at $14,911 (T asset file line 478). The declined cases repeat classes that the AR and SC individuals at $9,950 and the OK couple at $14,910 already pin. |
| G8 | RESOLVED | No change. |
| G9 | RESOLVED | Every new case name ends with a period. |
| G10 | RESOLVED | No change. |
| G11 | RESOLVED | CA disregard is 20 in all years (MC 176 line 8). additional_disregard is 230 / 310 until 2020-12-01 and comes off after the exclusions and after deeming (MC 176 line 16; lines 97-105). Probes give 9,000, 2,730 and 10,020 each, as MC 176 does. The $230 for an applicant with an ineligible spouse is correct; its pin is SA10b. |
| G12 | RESOLVED (comment option, as offered) | NOTE at lines 74-75. The pre-2021 read is $13.00 a month too high in 2019 and $3.90 in 2020, only for enrollees who pay their own Part B. |
| G13 | RESOLVED | NOTE at lines 76-78. Example 5 case at T income file line 463 (deemed 15,810; countable 31,135.20). It asserts no eligibility (G16). |
| G14 | RESOLVED | NC case at T income file line 494. |
| CT per member (round-2 out of scope) | RESOLVED (tracked) | Issue #10458 matches our analysis. The comment at P/income/disregard/couple.yaml and the case name at T income file line 184 are corrected. |
| Round-2 Next Steps 5 | RESOLVED (process note) | The body has axiom: TheAxiomFoundation/rulespec-us#1933 queued, and the issue is open. |
Ruling on SA8
Ruling: statute. RSMo 208.010.2(7) "not to exceed" governs. Couples are inclusive from 2015; individuals are inclusive from July 1, 2017 (fiscal year 2018). Record this comment as the ruling in the register.
The basis:
- 208.010.2(7), enacted by H.B. 1565 (2016), applies to MO HealthNet aged, blind and disabled claimants "starting in fiscal year 2018". An individual "owns or possesses resources not to exceed" the individual amount, and a couple "may own resources not to exceed" the couple amount. The section calls both "These resource limits", so both have one boundary.
- H.B. 1565 also added these claimants to the exception in 208.010.2(4): "the provision of this subsection shall not apply". So the "or more" individual clause in (4) does not reach them after August 28, 2016.
- Fiscal year 2018 began July 1, 2017 (Mo. Const. art. IV, sec. 23). 13 CSR 40-8.020 took effect the same day. RSMo 536.014(2) says a rule "in conflict with state law" is not valid.
- Before July 1, 2017 there was no conflict. 208.010.2(4) (to August 27, 2016) and 13 CSR 40-2.030(12), 11/30/15 edition (to June 30, 2017), made a single person ineligible at "one thousand dollars ($1000) or more" and a couple only when resources "exceeds a value of two thousand dollars". The head already gives that result for 2015-2017.
- This matches the Colorado ruling,
us-co:premium-assistance-ptc-recipients.
The ruling commit 216aa268a1. It edits only source_conflicts/candidates.yaml:3732-3765. For couples it matches the ruling: follows: statute, couples inclusive from 2015, state: ruled, the couple flag file in pe_us.code, and no personal name in the note. For individuals it does not: the note says "Individuals keep the strict test" and "the model needs no change". The note and the PR body also cite comment 6451309562 as the ruling record. That comment was posted from the author's account and covers couples only. This review is the ruling record. Still missing: the individual flag from 2017-07-01 and its cases (C8), the Missouri references on both flags (C8), the candidate text, the rulespec-us entry under proposed, and, after the merge, the markers (SA8).
Verified YAML. It ran on a copy of head with the C8 variable comment: the C8 cases and the three PR test files pass, the 750 Medicaid baseline cases pass, and the parameter-key and reference-URL code-health tests pass (114). A # after a space starts a YAML comment, so the titles with #page are quoted, as in the PR's other files.
In P/assets/limit/individual_limit_inclusive.yaml, put these four entries first in reference, and replace the MO block (lines 65-66):
- title: Missouri Revised Statutes 208.010.2(7)
href: https://revisor.mo.gov/main/OneSection.aspx?section=208.010
- title: Missouri Revised Statutes 208.010.2(4) (version effective October 11, 2013 to August 28, 2016)
href: https://revisor.mo.gov/main/OneSection.aspx?section=208.010&bid=10947
- title: "Missouri H.B. 1565 (2016), truly agreed and finally passed, section 208.010.2(4) and (7) #page 3-4"
href: https://house.mo.gov/billtracking/bills161/billpdf/truly/HB1565T.PDF#page=3
- title: "13 Missouri Code of State Regulations 40-2.030(12) (11/30/15 edition) #page 9-10"
href: https://web.archive.org/web/20170107023023/http://s1.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-2.pdf#page=9MO:
# Before fiscal year 2018, a single claimant with resources of 1,000 "or
# more" is ineligible: RSMo 208.010.2(4) before August 28, 2016, and
# 13 CSR 40-2.030(12) (11/30/15 edition) until June 30, 2017.
2015-01-01: false
# From fiscal year 2018 (July 1, 2017), a claimant "owns or possesses
# resources not to exceed" the individual amount (RSMo 208.010.2(7)).
# Annual calculations read January 1, so this value first applies in 2018.
2017-07-01: trueIn P/assets/limit/couple_limit_inclusive.yaml, insert the last three entries above (2013 version, H.B. 1565, 13 CSR 40-2.030(12)) after the existing 208.010.2(7) entry at lines 9-10, and replace the MO block (lines 67-70):
MO:
# A married claimant living with a spouse "may own resources not to exceed"
# the couple amount: RSMo 208.010.2(4) before August 28, 2016, and
# 208.010.2(7) from fiscal year 2018 (July 1, 2017). In between,
# 13 CSR 40-2.030(12) (11/30/15 edition) made a couple ineligible only when
# resources "exceed[] a value of two thousand dollars".
2015-01-01: trueCritical (Must Fix)
C8. Regulatory mismatch: from fiscal year 2018, Missouri individuals keep the strict test, but RSMo 208.010.2(7) lets an individual's resources equal the limit. The Missouri flags also lack references for 2015-2017.
- Code:
P/assets/limit/individual_limit_inclusive.yaml:65-66: MO2015-01-01: false, with no comment and no Missouri reference.V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:49-56then usesassets < state_limitfor a Missouri individual.P/assets/limit/couple_limit_inclusive.yaml:9-10, 67-70: the only Missouri reference is 208.010.2(7) at the current page, which supports 2018 on. The comment "(208.010.2(4) before fiscal year 2018)" is wrong from August 28, 2016 to June 30, 2017, when only 13 CSR 40-2.030(12) applied.
- Sources: see "Ruling on SA8".
- The test proves a flip. At head, a 2018 individual with $2,000 and a 2026 individual with $6,068.80 are ineligible. Under the ruled reading, both are eligible.
- Why critical: the head value contradicts the ruled source, and a test shows the flip. Round 2 said that SA8 "becomes critical if the project lead rules for the statute and the PR does not change". A non-default dated value also needs a reference that supports it.
- Effect: only individuals whose resources equal the limit to the cent. The microsimulation effect is about zero.
- Fix:
- Apply the two flag blocks and the references in "Ruling on SA8".
- Replace the comment at
V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:46-48:
# RSMo 208.010.2(7): a Missouri claimant "owns or possesses resources
# not to exceed" the individual amount, and a married couple "may own
# resources not to exceed" the couple amount. California resources may
# not exceed the limit (22 CCR 50420(a); WIC 14005.40(c)(5)).- Append these cases to the T asset file. At head, the two "eligible" individual cases fail. With the fix, all five pass. The 2017 cases pin the years before the conflict: "inclusive from 2015" fails the first, and "couples strict in 2017" fails the second.
- name: Missouri individual at the 1,000-dollar limit is ineligible in 2017.
period: 2017
input:
age: 70
ssi_countable_resources: 1_000
state_code: MO
output:
# 13 CSR 40-2.030(12) (11/30/15 edition): resources of 1,000 "or more"
# make a single person ineligible before July 1, 2017.
is_optional_senior_or_disabled_asset_eligible: false
- name: Missouri couple at the 2,000-dollar couple limit is eligible in 2017.
period: 2017
input:
people:
person1:
age: 70
ssi_countable_resources: 1_000
person2:
age: 68
ssi_countable_resources: 1_000
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: MO
output:
# 13 CSR 40-2.030(12) (11/30/15 edition): a couple is ineligible only when
# resources "exceed[] a value of two thousand dollars".
is_optional_senior_or_disabled_asset_eligible: [true, true]
- name: Missouri individual at the July 2017 individual resource limit is eligible in 2018.
period: 2018
input:
age: 70
ssi_countable_resources: 2_000
state_code: MO
output:
# RSMo 208.010.2(7), from fiscal year 2018: resources "not to exceed"
# 2,000.
is_optional_senior_or_disabled_asset_eligible: true
- name: Missouri individual at the 2026 individual resource limit is eligible.
period: 2026
input:
age: 70
ssi_countable_resources: 6_068.8
state_code: MO
output:
# RSMo 208.010.2(7): resources "not to exceed" the individual amount.
is_optional_senior_or_disabled_asset_eligible: true
- name: Missouri individual one cent over the 2026 individual resource limit is ineligible.
period: 2026
input:
age: 70
ssi_countable_resources: 6_068.81
state_code: MO
output:
is_optional_senior_or_disabled_asset_eligible: false- Correct the PR body and issue #10466 (SA8, step 4).
C9. Regulatory mismatch: from 12/2020, the Part B swap drops the income-related amount (IRMAA) that the person pays, so eligibility can flip.
- Code:
V/income/medicaid_optional_senior_or_disabled_countable_income.py:81-88.paid_part_bis the netmedicare_part_b_premium, which includes IRMAA. The swapmax_(paid_premiums - paid_part_b, 0) + base_part_bremoves all of it and adds back only the base premium. - Sources:
- ACWDL 20-18 (FILE #page=2): counties disregard "the amount of the individual's Medicare Part B premium ... regardless of the state's payment of the premium". The letter removes the payment condition. It does not cap the amount at the standard premium. Its examples use $144.60 because those people have no IRMAA.
- ACWDL 20-24 (FILE #page=3): "All deductions used in the ABD FPL program prior to the expansion will continue to apply", including health insurance premiums under 22 CCR 50555.2. 50555.2(c) deducts Part B in the months that the beneficiary pays it.
- 42 USC 1395r(i)(1): for income over the threshold, "the monthly premium shall be increased" by the adjustment amount. So IRMAA is part of the individual's Part B premium.
- The test proves a flip. CA 2026, Social Security of $2,100 a month,
medicare_irmaa_magiof $150,000 (Part B 202.90 + 202.90 IRMAA). Head: 2,100 - 20 - 202.90 = 1,877.10 a month, over the 1,835.40 limit, so ineligible. Fix: 2,100 - 20 - 405.80 = 1,674.20, so eligible. - Not a regression against
main, which deducts no premium for CA. The round-2 head gives the same wrong result. This is our round-2 C6 code, not an author error. - Reach: in the microsimulation, an IRMAA payer's current income is far above the CA limit, so the effect is about zero. The flip needs a household or API user who enters prior-year income, such as a recent retiree.
- Fix: replace the comment at lines 70-71 and the code at lines 82-88. Optional: add
"https://www.law.cornell.edu/uscode/text/42/1395r#i"toreference.ruff formatreports no change.
# "regardless of how the premium is paid": swap the person-paid Part B
# in the shared aggregate for the individual's full Part B premium, the
# base premium plus any IRMAA (42 USC 1395r(i)), whoever pays it. full_part_b = (
person("gross_medicare_part_b_premium", period) * medicare_enrolled
)
disregards_part_b = p.disregards_medicare_part_b_premium[state].astype(bool)
own_premiums = where(
disregards_part_b,
max_(paid_premiums - paid_part_b, 0) + full_part_b,
paid_premiums,
)- The one-token variant
max_(base_part_b, paid_part_b)is not enough: when the MSP pays the base and the person pays the IRMAA, it disregards 202.90 instead of 405.80 (the second case below). - Run on a copy with the fix: the three cases below, the three PR test files, the Medicaid baseline folder, and the healthcare, CA signature and amplifi partner tests (853) pass. Each case fails at head.
- Append the first two cases to the T income file, and the third to
T/eligibility/categories/is_optional_senior_or_disabled_income_eligible.yaml:
- name: California deducts the full Part B premium, IRMAA included, that the person pays in 2026.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1:
age: 70
medicare_enrolled: true
social_security_retirement: 22_200
health_insurance_premiums_without_medicare_part_b: 1_200
tax_units:
tax_unit:
members: [person1]
medicare_irmaa_magi: 150_000
households:
household:
members: [person1]
state_code: CA
output:
# Part B is 202.90 base plus 202.90 IRMAA a month (42 USC 1395r(i)).
# ACWDL 20-18 p2 disregards "the amount of the individual's Medicare
# Part B premium": (1,850 - 20 - 100 - 405.80) x 12 = 15,890.40.
medicare_part_b_premium: 4_869.6
medicaid_optional_senior_or_disabled_countable_income: 15_890.4
- name: California disregards the full Part B premium when an MSP pays the base and the person pays the IRMAA in 2026.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1:
age: 70
medicare_enrolled: true
social_security_retirement: 14_400
tax_units:
tax_unit:
members: [person1]
medicare_irmaa_magi: 150_000
households:
household:
members: [person1]
state_code: CA
output:
# The MSP pays the 202.90 base; the person pays the 202.90 IRMAA.
# The disregard applies "regardless of the state's payment" (ACWDL 20-18
# p2): (1,200 - 20 - 405.80) x 12 = 9,290.40.
msp_part_b_premium_coverage: 2_434.8
medicare_part_b_premium: 2_434.8
medicaid_optional_senior_or_disabled_countable_income: 9_290.4- name: California applicant who pays IRMAA is income eligible once the full Part B premium is disregarded in 2026.
period: 2026
input:
people:
person1:
age: 70
medicare_enrolled: true
social_security_retirement: 25_200
tax_units:
tax_unit:
members: [person1]
medicare_irmaa_magi: 150_000
households:
household:
members: [person1]
state_code: CA
output:
# 2,100 - 20 - 405.80 = 1,674.20 a month, under 138% FPL (1,835.40).
# With only the 202.90 base premium, 1,877.10 is over the limit.
is_optional_senior_or_disabled_income_eligible: trueShould Address
SA8 (carried). Source conflict: record the ruling in the candidate, the register and the PR body.
- Status: couples are done. The steps below remain. The code change for individuals is C8.
- Steps:
- Replace the candidate at
source_conflicts/candidates.yaml:3732-3765with this entry. Replace<URL of this review>with the link to this review. The new id covers individuals too. You can keep the old id if you widen the question. The entry passes the guard's id, field and privacy rules on a copy.
- Replace the candidate at
- id: us-mo:mhabd-resource-limit-boundary
program: medicaid
years:
from: 2018
type: state-fiscal
question: From fiscal year 2018, is a Missouri aged, blind or disabled claimant or couple whose countable resources
equal the limit eligible, as the statute's "not to exceed" says, or ineligible, as the rule's "at or in excess of"
says?
sources:
- kind: statute
citation: RSMo 208.010.2(7)
url: https://revisor.mo.gov/main/OneSection.aspx?section=208.010
- kind: statute
citation: RSMo 536.014(2)
url: https://revisor.mo.gov/main/OneSection.aspx?section=536.014
- kind: regulation
citation: 13 CSR 40-8.020(4)(B)
url: https://www.sos.mo.gov/CMSImages/AdRules/csr/current/13csr/13c40-8.pdf#page=2
readings:
statute: A claimant "owns or possesses resources not to exceed" the individual amount and a married couple "may
own resources not to exceed" the couple amount, so resources equal to either limit qualify.
other: A household with countable assets "at or in excess of" the limit is ineligible.
example: In 2026, an individual with $6,068.80 or a couple with $12,137.55 of countable resources is eligible under
the statute and ineligible under the rule.
pe_us:
follows: statute
code:
- policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/assets/limit/individual_limit_inclusive.yaml
- policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/assets/limit/couple_limit_inclusive.yaml
prs:
- https://github.com/PolicyEngine/policyengine-us/pull/10364
state: ruled
note: Ruled on 2026-10-27 by the project lead to follow the statute for individuals and couples (ruling record
<URL of this review>). RSMo 536.014(2) makes a rule that is in conflict with state law not valid. Missouri
fiscal year 2018 began July 1, 2017. Before then, RSMo 208.010.2(4) (before August 28, 2016) and 13 CSR
40-2.030(12) set a strict single-person test and an inclusive couple test, and the sources did not disagree.- The entry drops "(4)(A)1.B" as the regulation side, because 13 CSR 40-8.020 was not in force before July 1, 2017. It also drops "(208.010.2(4) before fiscal year 2018)".
- Open the rulespec-us
known-source-conflicts.yamlentry now, withproposeditems while the PR is open:id: mhabd-resource-limit-boundary,jurisdiction: us-mo,program: medicaid, the question above, andyears: {from: 2018, type: state-fiscal}.pending_textswith a verbatimexcerptof RSMo 208.010.2(7), 13 CSR 40-8.020(4)(B) and RSMo 536.014(2).- A
reading, one alternative (rule-at-or-in-excess), abasis, andoutcome: computed. Keep dollar figures out of the prose fields unless amoney_casecomputes them. - Entry-level
status: open, as every PolicyEngine-ruled entry in the register has. The ruling goes on each implementation:ruling: {by: PolicyEngine, date: '2026-10-27', record: <URL of this review>}. proposed: one item per flag file, withrepo: PolicyEngine/policyengine-us, the PR URL, thepathandfollows: reading.
- After the merge:
- In rulespec-us, move
proposedtoimplementationsat the merge commit. Addteststhat pin "Missouri couple at the couple resource limit is eligible." and "Missouri individual at the 2026 individual resource limit is eligible.". - In a follow-up policyengine-us PR, run
python scripts/update_source_conflicts.py --commit <rulespec-us commit>. Delete the candidate in the same commit. Put# Source conflict us-mo:mhabd-resource-limit-boundaryalone on the line directly above2017-07-01: truein the individual file and above2015-01-01: truein the couple file. - Do not add the markers earlier.
test_every_marker_names_a_registered_entry_that_lists_its_filereads onlyimplementations, so a marker fails while the PR is open. #10176 and then #10441 used the same order.
- In rulespec-us, move
- Correct the text:
- PR body: "Missouri individuals keep the strict test (
<), the agency's reading in 13 CSR 40-8.020(4)(B)" and "individual_limit_inclusive(CA)" become: Missouri individuals' resources may equal the limit from July 1, 2017 (RSMo 208.010.2(7)), and the flag covers CA and MO. In "Out of scope", the strict test stays "outside AR, OK, SC, CA and MO". - PR body, "Source conflicts": link this review as the ruling, use the new id, and delete "the model needs no change".
- Issue #10466: it says Missouri's rule stays strict "for individuals" and lists Missouri for couples only. Under the ruling, both Missouri units are inclusive from July 1, 2017.
- PR body: "Missouri individuals keep the strict test (
SA9. Missing edge cases: four PR-authored values in the asset test have no case that pins them.
- Each change below passes all 105 PR cases (and all 750 Medicaid baseline cases), and each can change an eligibility result. The four cases pass at head and with the C8 and C9 fixes, and each fails on its change.
- (a) Whole-cent rounding (round-1 C1).
V/eligibility/categories/is_optional_senior_or_disabled_asset_eligible.py:22. Round 2 pinned it with the MO couple at the limit under<. Under<=, that couple's 6,000 + 6,137.55 is stored as 12,137.5498, under the limit with or without the rounding. Change: removenp.round, or sum in float32 without it. Without the rounding, the split couple below reads 12,137.5503 and is ineligible. - (b) CA
individual_limit_inclusivefrom 2015. Every CA at-limit case is in 2023 or 2026. Change: start the flag on 2022-07-01. A 2019 applicant at $2,000 becomes ineligible. - (c) CA
couple_limit_inclusivefrom 2015. The same gap for couples at $3,000. - (d) CA step of 2022-07-01 (
P/assets/limit/{individual,couple}.yaml:53-54). No case reads CA in 2022, so only the late side is pinned (T asset file line 547). Change: date the step 2022-01-01. Every 2022 applicant with $2,000.01 to $130,000 becomes eligible.
- (a) Whole-cent rounding (round-1 C1).
- Append to the T asset file:
- name: Missouri couple whose split resources sum to the 2026 couple limit is eligible.
period: 2026
input:
people:
person1:
age: 70
ssi_countable_resources: 5_000.1
person2:
age: 68
ssi_countable_resources: 7_137.45
tax_units:
tax_unit:
members: [person1, person2]
tax_unit_is_joint: true
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: MO
output:
# 5,000.10 + 7,137.45 = 12,137.55, the couple limit; RSMo 208.010.2(7)
# "not to exceed". The inputs are stored as float32, and their sum is
# 12,137.5503, so only the whole-cent rounding keeps the couple eligible.
is_optional_senior_or_disabled_asset_eligible: [true, true]
- name: California applicant at the 2,000-dollar individual resource limit is eligible in 2019.
period: 2019
input:
age: 70
ssi_countable_resources: 2_000
state_code: CA
output:
# 22 CCR 50420(a): the property reserve "shall not exceed" 2,000.
is_optional_senior_or_disabled_asset_eligible: true
- name: California couple at the 3,000-dollar couple resource limit is eligible in 2019.
period: 2019
input:
people:
person1:
age: 70
ssi_countable_resources: 1_500
person2:
age: 68
ssi_countable_resources: 1_500
tax_units:
tax_unit:
members: [person1, person2]
tax_unit_is_joint: true
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: CA
output:
# 22 CCR 50420(a): 3,000 combined equals the two-person limit.
is_optional_senior_or_disabled_asset_eligible: [true, true]
- name: California applicant one cent over the 2,000-dollar individual resource limit is ineligible in 2022.
period: 2022
input:
age: 70
ssi_countable_resources: 2_000.01
state_code: CA
output:
# Annual calculations read January 1, so 2022 uses the 2,000 limit; the
# 130,000 limit of July 1, 2022 (ACWDL 21-31) first applies in 2023.
is_optional_senior_or_disabled_asset_eligible: falseSA10. Missing edge cases: three PR-authored branches or values in countable income have no case that pins them.
- Each change below passes all 105 PR cases, and each can change an eligibility result. The three cases pass at head and with the C8 and C9 fixes, and each fails on its change.
- (a) Person-paid Part B before 12/2020 (
V/income/medicaid_optional_senior_or_disabled_countable_income.py:87). Every pre-2021 CA case has no Medicare or an MSP that pays Part B, sopaid_part_bis 0 in all of them. Change: drop the person-paid Part B in this branch. Flip window: in 2019, with $100 a month of other premiums, Social Security from $1,430 to $1,535 a month is income eligible at head and ineligible with the change. In that band the MSP pays nothing, because income is over the QI limit. The case setsmedicare_part_b_premiumdirectly, so it does not read the pre-2021 base premium (G12). - (b) The $230 for an applicant with an ineligible spouse (G11). Change: give the couple disregard to an applicant with deemed spouse income. This moves some 2019 deemed households across the two-person FPL. Do not assert eligibility in this case: MC 176 lines 19 and 21 (the spouse's maintenance need level, the one-person FPL) are not modeled (G17).
- (c) Minnesota couple disregard of 0. The three MN cases are single people. Change: a $20 couple disregard. A 2026 MN couple with combined unearned income of $1,805 to $1,820 a month is ineligible at head and eligible with the change.
- (a) Person-paid Part B before 12/2020 (
- Append to the T income file:
- name: California deducted a Part B premium that the person paid before 12/2020.
period: 2019
absolute_error_margin: 0.01
input:
age: 70
medicare_enrolled: true
social_security_retirement: 17_400
medicare_part_b_premium: 1_626
health_insurance_premiums_without_medicare_part_b: 1_200
state_code: CA
output:
# 22 CCR 50555.2(c) and MC 176 line 17: Part B counts in the months that
# the person pays it (135.50 a month in 2019). The person's income is over
# the QI limit, so no Medicare Savings Program pays it.
# (1,450 - 20 - 230 - 100 - 135.50) x 12 = 11,574, under the 12,490 limit.
# Without the Part B deduction, 13,200 would be over it.
medicaid_optional_senior_or_disabled_countable_income: 11_574
- name: California gives an applicant whose spouse is not aged or disabled the 230-dollar individual disregard in 2019.
period: 2019
absolute_error_margin: 0.01
input:
people:
person1:
age: 70
is_tax_unit_head: true
medicare_enrolled: false
ssi_unearned_income: 15_000
person2:
age: 50
is_tax_unit_spouse: true
ssi_earned_income: 6_000
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: CA
output:
# The spouse is not aged or disabled, so the applicant is a qualified
# individual, not part of a qualified couple (ACWDL 00-57 p1; MC 176
# line 16): 230, not 310. The spouse's 500 a month is over the 2019
# deeming threshold (1,157 - 771 = 386), so it counts.
# MC 176 lines 8-16: (1,250 - 20) + (500 - 65) / 2 = 1,447.50; less 230
# = 1,217.50 a month. Lines 19 and 21 (the spouse's MNL, the 1-person
# FPL) are not modeled, so this case asserts no eligibility.
ssi_couple_computation_applies: [false, false]
medicaid_optional_senior_or_disabled_income_deemed_from_ineligible_spouse: [2_610, 0]
medicaid_optional_senior_or_disabled_countable_income: [14_610, 0]
- name: Minnesota applies no 20-dollar disregard to a couple.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1:
age: 70
is_tax_unit_head: true
ssi_unearned_income: 15_600
person2:
age: 68
is_tax_unit_spouse: true
ssi_unearned_income: 7_800
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: MN
output:
ssi_couple_computation_applies: [true, true]
# Minn. Stat. 256B.056, subd. 1b: 1,950 x 12 / 2 = 11,700 each.
# A 20-dollar couple disregard would give 11,580.
medicaid_optional_senior_or_disabled_countable_income: [11_700, 11_700]- Optional: an eligibility copy of case (a) without the margin (
is_optional_senior_or_disabled_income_eligible: true), as the PR does at T income file line 426.
Suggestions
- G15. Pin the floor in the couple branch.
V/income/medicaid_optional_senior_or_disabled_countable_income.py:121. Removingmax_(..., 0)there passes all 105 cases. No eligibility result can change: every reader compares the value with a limit of 0 or more, so 0 and a negative value give the same result. Optional case for the T income file:
- name: California couple countable income does not go below zero when premiums exceed income.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1:
age: 70
is_tax_unit_head: true
medicare_enrolled: true
ssi_unearned_income: 1_200
person2:
age: 68
is_tax_unit_spouse: true
medicare_enrolled: true
marital_units:
marital_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: CA
output:
ssi_couple_computation_applies: [true, true]
# (100 - 20) x 12 = 960, less 2 x 2,434.80 Part B, floored at 0.
medicaid_optional_senior_or_disabled_countable_income: [0, 0]- G16. Assert the Example 5 result. The case at T income file line 463 says "over the limit, which is the letter's result", but asserts no eligibility. Add a copy of its input without
absolute_error_margin, named "California applicant in ACWDL 20-24 Example 5 is not income eligible.", withis_optional_senior_or_disabled_income_eligible: [false, false]. It passes at head. - G17. Open an issue for California's spouse method. MC 176 line 19 deducts the maintenance need level ($600 for one person) for an ineligible spouse, and line 21 compares with the FPL for the people evaluated. ACWDL 20-24 page 3 keeps that method. The model uses SSI deeming and the two-person FPL for every married applicant (
V/eligibility/categories/medicaid_optional_senior_or_disabled_income_limit.py:25, 43, onmainbefore this PR).- The G11 fix exposes the gap. Example: in 2019, an applicant with Social Security of $1,250 a month and a spouse aged 50 who earns $1,000. Round-2 head: 1,407.50 a month, eligible against 1,409.17. Head: 1,467.50, ineligible. MC 176: 867.50 against 1,040.83, eligible.
- The gap goes both ways: an applicant whose spouse has no income is ineligible in the model and eligible under MC 176. Keep the $230, because line 16 requires it.
- Open an issue for all years. Cite it in the body's "Not modeled" item and in the Example 5 NOTE at lines 76-78.
- G18. Minnesota: title, body and sources.
- Retitle the PR to "... (CA, CT, MN, MO, AR, OK, SC)". In the first body paragraph, change "six states" to "seven states" and "the other five states" to "the other six states". Issue #10356 lists six states, so note Minnesota as an addition.
- The first reference in
P/income/disregard/{individual,couple}.yaml(KFF) lists $20 for Minnesota. Add the agency source:title: Minnesota DHS Health Care Programs Eligibility Policy Manual 2.3.3.3.2.2, MA-ABD Disregards and Deductions,href: https://hcopub.dhs.state.mn.us/epm/2_3_3_3_2_2.htm. - Add Minnesota to issue #10466. Minn. Stat. 256B.056, subd. 3(a) says "must not individually own more than $3,000", but the MN asset test stays strict.
- G19. Statute citations and reference titles.
P/income/additional_disregard/{individual,couple}.yaml: add WIC 14005.40(c)(2)(A), the statute that sets "two hundred thirty dollars ($230) for an individual or, in the case of a couple, three hundred ten dollars ($310)" (https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=WIC§ionNum=14005.40).P/income/disregards_medicare_part_b_premium.yaml: add WIC 14005.401, the authority that ACWDL 20-18 page 1 names.- The WIC 14005.40 href opens leginfo's list of two versions, and the "do not exceed" clause was (c)(3) before July 9, 2019. In both inclusive files, use
title: California Welfare and Institutions Code 14005.40(c)(5) (version operative January 1, 2026; (c)(3) before July 9, 2019). - Optional: in
P/assets/limit/{individual,couple}.yaml:11, use the ACWDL 21-31 subject, "Increases to the Asset Limits for Non-Modified Adjusted Gross Income Medi-Cal Programs".
- G20. Cite the rule in force in the 2017 Missouri case. The comment at T asset file line 359 cites 13 CSR 40-8.020(4)(A), a 2017 rule that describes the earlier limits. Use:
# 13 CSR 40-2.030(12) (11/30/15 edition): 1,000 "or more" before July 1, 2017. 1,500 is over it.The value is right.
Investigated and cleared
- The $230 for an applicant with an ineligible spouse before 12/2020. ACWDL 00-57 page 1 ties the $310 to "qualified couples", and "Qualified individuals/couples need to be aged or disabled". MC 176 line 16, ACWDL 02-38 Q1 and Q7, and ACWDL 20-24 pages 2-3 agree. The round-2 effective $310 came from the deeming helper, which uses
disregard.couple. It also made an $80-a-month jump at the deeming threshold, which head removes. 20 CFR 416.1163(d)(2) sets no state disregard. - Missouri couples in 2017. No statute covered these couples from August 28, 2016 to June 30, 2017. 13 CSR 40-2.030(12) did ("exceeds a value of two thousand dollars"), and 13 CSR 40-8.020 began on July 1, 2017. So MO
couple_limit_inclusivetrue from 2015 is right for 2017. A 2017falsewould be wrong. - California assets. The inclusive test in the $2,000 / $3,000 years follows 22 CCR 50420(a) in every year. The 2022-07-01 step matches ACWDL 21-31 pages 2-4, and a probe confirms that it first applies in 2023. WIC 14005.62 words the $130,000 as a "disregard", and DHCS applies it as the limit (ACWDL 21-31 page 1).
- Minnesota. The statute and EPM 2.3.3.3.2.2 agree on $0. KFF's $20 is a secondary survey, so there is no source conflict. The income test at the limit uses
<=, as EPM 2.3.3.3.1 does. - Code. No dependency cycle. A batch of 432 households (CA, MO, MN, NC, CT, SC, AR and OK; 7 years) matches 108 households computed one at a time, with 0 mismatches. Period use, entities and the monthly-to-annual conversion are correct.
ruff formatandruff checkpass. No hard-coded values. - Inner floor and date shifts.
max_(paid_premiums - paid_part_b, 0)binds only for an inconsistent input (a direct total below the modeled Part B, which the direct input is documented to include). Moving a CA step by one day changes nothing, because annual calculations read January 1. - Register guard. 103 tests passed at
60ef70cb9c, and CI passes at head. The SA8 candidate passes the id, field and privacy rules. - Partner contract tests. No partner file changes. The CA partner senior is still $1,110 a month in 2026.
Out of scope / follow-up
- DHCS links. Every
dhcs.ca.gov/.../letters/Documents/*.pdfhref now redirects (302) to a/file/<name>-pdf/page behind a bot check. The repo has 24 such hrefs, so this is repo-wide. The cited content is stable in Wayback. - WIC 14005.62 becomes inoperative on July 1, 2027. This bears on draft PR #10375, not on this PR.
- Issue #10466: the strict test in the other states. The
falsedefaults in the two inclusive flags have no source; 42 USC 1396a(m)(1)(C) says "do not exceed". - Carried from earlier rounds: AR ARSeniors is aged-only; the asset files have different
periodmetadata; the KFF titles;ParameterNotFoundErrorbefore 2015-01-01; the CT 2023 income limits and the CT couple values before 2024; issue #9734; CA whole-dollar rounding; issues #10457, #10458 and #10470; base Part B values before 2021 (a separate PR, as the author proposed).
PDF Audit Summary
| Category | Count |
|---|---|
| Confirmed correct | 15 of 16 values (CA 2022 limits, CA inclusive flags, CA additional disregard and Part B dates, CA $20, MN $0, OK C-1 2026, MO couple flag) and 14 of 15 references |
| Mismatches (code-path confirmed + visually verified) | 1: MO individual flag false from 2017-07-01 (C8). 1 reference supports only 2018 on (MO couple flag, C8) |
| Formula mismatch | 1: IRMAA dropped from the Part B disregard (C9) |
| Not checked | The 49 default keys of each inclusive flag (issue #10466) |
| Unmodeled items | CA spouse method, MC 176 lines 19 and 21 (G17); Example 5 spouse premium; CA whole-dollar rounding |
Validation Summary
| Check | Result |
|---|---|
| Regulatory Accuracy | 2 critical (C8, C9); 1 should address (SA8) |
| Reference Quality | MO flag references missing or partial (C8); 2 suggestions (G18, G19); G5 partial |
| Code Patterns | 0 issues; no hard-coded values |
| Formatting (params & vars) | 0 issues |
| Test Coverage | 2 should address (SA9, SA10: 7 untested PR values or branches); 3 suggestions (G15, G16, G20) |
| PDF Value Audit | 1 value mismatch (C8); 15 confirmed |
| CI Status | Passing: 33 of 33 checks |
| Local tests | PR test files 105 passed. The 17 proposed cases: 12 pass at head, and the 5 C8 and C9 cases fail by design. On a copy with the C8 and C9 fixes: 122 passed (the 17 cases and the 105 PR cases), Medicaid baseline 750 passed, code-health 114 passed |
| Partner contract tests | No partner file touched. 853 Medicaid and partner cases pass on the C9 fix copy |
| Branch | 11 ahead, 6 behind main; MERGEABLE |
| Other reviews | None |
Review Severity: REQUEST_CHANGES
Two critical items (C8, C9) and three should-address items (SA8, SA9, SA10) are open.
Next Steps
- To auto-fix issues: run the fix-pr workflow for this PR.
- Suggested order: C8 with SA8 (the flag YAML, the variable comment, five cases, the candidate, the body and issue #10466). Then C9 (one code edit and three cases). Then SA9 and SA10 (seven cases). The suggestions can follow in the same commit or later.
- The C8 and C9 edits do not overlap, and they ran together on one copy. After you apply them, run
policyengine-core test policyengine_us/tests/policy/baseline/gov/hhs/medicaid -c policyengine_usand the Medicare tests. - C9 changes CA countable income for IRMAA payers. Run the partner tests under
policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/healthcareagain. Do not edit a partner file without the partner review gate. - Open the rulespec-us entry with
proposeditems now (SA8, step 2). Add the markers only in a follow-up PR after the merge (SA8, step 3). - Process note, not counted: the
axiom:line is now in the body.
Closes #10356
What and why
The optional Medicaid pathway for aged, blind and disabled people (
is_optional_senior_or_disabled_for_medicaid) used outdated disregards and asset limits in six states. California still applied disregards the state removed in 2020, and the other five states had values that were never updated.<How the model applies them
senior_or_disabled.assets.limit.uses_msp_limit, true for AR, OK and SC from 2015-01-01, the first date in the asset files.is_optional_senior_or_disabled_asset_eligiblereadsgov.hhs.medicare.savings_programs.eligibility.asset.{individual,couple}for those states. Their copied dollar entries are removed from the asset files, so they will not go stale again.<=), as in MS 23110(6), C-1 Schedule VI and MPPM 303.06.02, and as inmsp_asset_eligible.<), the agency's reading in 13 CSR 40-8.020(4)(B).senior_or_disabled.assets.limit.individual_limit_inclusive(CA) andcouple_limit_inclusive(CA, MO), switch the comparison to<=. Other states keep<; issue Medicaid aged, blind and disabled pathway: let resources equal the state asset limit unless a state source says otherwise #10466 tracks checking them, since the federal rule (1396a(m)(1)(C)) reads "do not exceed".senior_or_disabled.income.disregardvalue is now the $20 deduction in every year. The newsenior_or_disabled.income.additional_disregard.{individual,couple}($230 / $310 for CA until 2020-12-01) comes off after the SSI exclusions, as on MC 176 line 16. The unused part of the $20 still moves to earned income before the half, as on line 12.senior_or_disabled.income.deducts_health_insurance_premiumsis true for CA from 2015. It deducts the premiums the person pays, from the sharedmedical_expense_health_insurance_premiumsaggregate. That aggregate covers the directhealth_insurance_premiumsinput or the decomposed inputs, and Part B net of MSP coverage.senior_or_disabled.income.disregards_medicare_part_b_premiumis true for CA from 2020-12-01. It swaps the person-paid Part B in that aggregate for the fullbase_part_b_premium, so an MSP buy-in does not remove the deduction and a self-paid premium is not counted twice.Examples:
Dates that differ from the issue
Missouri's July 1 values and California's December 1, 2020 changes first apply in the next year's calculation, because these variables are annual and read parameters on January 1.
Not confirmed against a primary source
The Missouri 2023 couple limit ($11,452) is confirmed by DSS memo IM-57.
The issue listed Arkansas 2026 and South Carolina as resting on KFF alone. Arkansas's April 2026 chart and MS 23110 now confirm the Arkansas limit. The SCDHHS manual and State Plan confirm South Carolina's disregard and asset limit.
Out of scope
<outside AR, OK, SC, CA and Missouri couples until each state's rule is checked.medicare_enrolled(Part A and/or Part B) stands in for Part B enrollment, as elsewhere in the Part B chain. Part A-only enrollees therefore get the California Part B disregard. The microdata also has no SSDI duration, so people under 65 do not reach Medicare. The code carries a NOTE.gov.hhs.medicare.part_b.base_premiumstarts in 2021. A person-paid Part B in California before 2021 therefore reads $148.50. The code carries a NOTE. That affects only people the MSP does not cover, whose income is above the pre-2021 limit.Test plan
health_insurance_premiumsinput ($10,560); an MSP buy-in with a total input ($8,125.20); a self-paid Part B inside the total, counted once ($18,325.20);us-mo:mhabd-couple-resource-limit-boundary, ruled: statute (ruling, 2026-10-27). The code already follows the statute, so the model needs no change.source_conflicts/candidates.yamlrecords the ruling (state: ruled). The register entry and the# Source conflictmarker follow the merge. The statute reading matches the Colorado ruling,us-co:premium-assistance-ptc-recipients.make format(ruff)changelog.d/No partner contract file in
tests/policy/baseline/partners/changes. The only partner Medicaid case in these states is a California senior with $1,333 a month of Social Security. In 2026 that senior's countable income goes from $1,103 a month onmainto $1,110 ($1,333 − $20 − $202.90 Part B) and stays under the $1,835 limit. The pre-2021 California changes do not reach it.axiom: TheAxiomFoundation/rulespec-us#1933 queued
🤖 Generated with Claude Code