diff --git a/changelog.d/medicaid-abd-ssi-only-states.fixed.md b/changelog.d/medicaid-abd-ssi-only-states.fixed.md new file mode 100644 index 00000000000..70f6c83b549 --- /dev/null +++ b/changelog.d/medicaid-abd-ssi-only-states.fixed.md @@ -0,0 +1 @@ +Limit the Medicaid optional aged, blind and disabled pathway to states that cover people who do not receive SSI, turning it off in the 14 states that cover them only if they receive SSI (AL, DE, GA, KS, KY, MD, MS, NV, NM, ND, SD, TN, TX and WY). Noncitizens who fail the Medicaid immigration test keep the pathway there for emergency Medicaid and are tested against the SSI rate. diff --git a/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/covers_non_ssi_recipients.yaml b/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/covers_non_ssi_recipients.yaml new file mode 100644 index 00000000000..c3b74216bf2 --- /dev/null +++ b/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/covers_non_ssi_recipients.yaml @@ -0,0 +1,166 @@ +description: The state covers the optional Medicaid group for aged, blind, or disabled people who meet SSI's income and resource requirements without receiving SSI (42 CFR 435.210), or the poverty-level aged and disabled group (42 U.S.C. 1396a(m)), if this is true. +metadata: + unit: bool + period: year + label: Medicaid senior or disabled pathway covers people who do not receive SSI + breakdown: + - state_code + reference: + - title: 42 CFR 435.210 - Optional eligibility for individuals who meet the income and resource requirements of the cash assistance programs + href: https://www.ecfr.gov/current/title-42/section-435.210 + - title: 42 U.S. Code § 1396a(m) - Poverty-level aged and disabled group + href: https://www.law.cornell.edu/uscode/text/42/1396a#m + - title: KFF, Medicaid Eligibility and Enrollment Policies for Seniors and People with Disabilities (Non-MAGI) During the Unwinding (June 2024), Appendix Tables 5 and 6 + href: https://www.kff.org/report-section/medicaid-eligibility-and-enrollment-policies-for-seniors-and-people-with-disabilities-non-magi-during-the-unwinding-appendix/ + - title: "KFF, Medicaid Financial Eligibility for Seniors and People with Disabilities: Findings from a 50-State Survey (June 2019, 2018 data), Appendix Table 1" + href: https://www.kff.org/report-section/medicaid-financial-eligibility-for-seniors-and-people-with-disabilities-findings-from-a-50-state-survey-appendix-tables/ + - title: Ala. Admin. Code r. 560-X-25-.03(1) - Coverage Groups + href: https://www.law.cornell.edu/regulations/alabama/Ala-Admin-Code-r-560-X-25-.03 + - title: Delaware Social Services Manual 17100 - SSI Beneficiaries + href: https://archive.regulations.delaware.gov/AdminCode/title16/Department%20of%20Health%20and%20Social%20Services/Division%20of%20Social%20Services/Delaware%20Social%20Services%20Manual/17000.shtml + - title: Georgia Medicaid Policy Manual 2101 - ABD Medicaid Classes of Assistance Overview + href: https://pamms.dhs.ga.gov/dfcs/medicaid/2101/ + - title: Georgia Medicaid Policy Manual 2111 - Supplemental Security Income (SSI) Medicaid + href: https://pamms.dhs.ga.gov/dfcs/medicaid/2111/ + - title: "Kansas Medicaid State Plan Amendment KS-25-0019 (effective July 1, 2025), Aged, Blind and Disabled eligibility groups #page 22-23" + href: https://www.medicaid.gov/medicaid/spa/downloads/KS-25-0019.pdf#page=22 + - title: 907 KAR 20:005 Sections 1(1) and 9(3) - Medicaid technical eligibility requirements not related to a modified adjusted gross income standard or former foster care individuals + href: https://apps.legislature.ky.gov/law/kar/titles/907/020/005/ + - title: "Maryland Department of Health, Guide to Maryland Medical Assistance Coverage Groups (April 2025), S02 and S98 #page 12,14-15" + href: https://health.maryland.gov/mmcp/Coverage%20Groups/coverage-group-guide.pdf#page=12 + - title: Miss. Code Ann. § 43-13-115(11), as reprinted in 2024 House Bill 464 (introduced) + href: https://billstatus.ls.state.ms.us/documents/2024/pdf/HB/0400-0499/HB0464IN.pdf#page=5 + - title: Mississippi Division of Medicaid Eligibility Policy and Procedures Manual, Appendix A-4-c - Inactive Categories of Eligibility + href: https://medicaid.ms.gov/wp-content/uploads/2016/12/Appendix-A-4.pdf#page=3 + - title: "Mississippi Division of Medicaid Eligibility Policy and Procedures Manual, Section 101.02 (December 2016) #page 5,11" + href: https://medicaid.ms.gov/wp-content/uploads/2016/12/Section-101.02.pdf#page=5 + - title: Mississippi Division of Medicaid Annual Report, Fiscal Year 1997 - Eligibility + href: https://medicaid.ms.gov/wp-content/uploads/2020/11/1997.pdf#page=8 + - title: "Nevada Medical Assistance Manual B-300 - MAABD Medical Categories (March 2025), B-315, B-320 and B-340 #page 6-7,14" + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Medical/B-300%20MAABD%20MEDICAL%20CATEGORIES%20Mar%2017.pdf#page=6 + - title: 8.200.400.10(C)(1) NMAC - Supplemental security income (SSI) related medicaid + href: https://www.srca.nm.gov/parts/title08/08.200.0400.html + - title: "N.D. Admin. Code 75-02-02.1-05(1)(n), (2) and (3)(e) - Coverage groups #page 10-11" + href: https://www.ndlegis.gov/information/acdata/pdf/75-02-02.1.pdf#page=10 + - title: S.D. Admin. R. 67:46:01:02(2) - Eligibility requirements + href: https://sdlegislature.gov/Rules/Administrative/67:46:01:02 + - title: Tenn. Comp. R. & Regs. 1200-13-20-.08(1) - Supplementary Security Income (SSI) cash recipients + href: https://publications.tnsosfiles.com/rules/1200/1200-13/1200-13-20.20260423.pdf#page=73 + - title: Texas Medicaid for the Elderly and People with Disabilities Handbook A-2000 - Mandatory Coverage Groups + href: https://fhb.hhs.texas.gov/handbooks/medicaid-elderly-people-disabilities-handbook/a-2000-mandatory-coverage-groups + - title: Texas Medicaid for the Elderly and People with Disabilities Handbook A-3000 - Optional Coverage Groups + href: https://fhb.hhs.texas.gov/handbooks/medicaid-elderly-people-disabilities-handbook/a-3000-optional-coverage-groups + - title: Wyo. Admin. Rules 048.0037.18 § 8(a) - Aged, Blind or Disabled Eligibility (effective May 23, 2025) + href: https://health.wyo.gov/wp-content/uploads/2025/12/Chapter-18-1.pdf#page=8 + - title: Wyoming Medicaid Eligibility Online Manual M1005 - SSI and SSI Related + href: https://ecom.wyo.gov/m1000-aged-blind-or-disabled-program/m1005-ssi-and-ssi-related + - title: West Virginia Income Maintenance Manual 23.11.4 - SSI-Related/Non-Cash Assistance (October 5, 2026 edition) + href: https://bfa.wv.gov/media/40005/download?inline#page=1889 + +AK: + 2018-01-01: true +AL: + 2018-01-01: false +AR: + 2018-01-01: true +AZ: + 2018-01-01: true +CA: + 2018-01-01: true +CO: + 2018-01-01: true +CT: + 2018-01-01: true +DC: + 2018-01-01: true +DE: + 2018-01-01: false +FL: + 2018-01-01: true +GA: + 2018-01-01: false +HI: + 2018-01-01: true +IA: + 2018-01-01: true +ID: + 2018-01-01: true +IL: + 2018-01-01: true +IN: + 2018-01-01: true +KS: + 2018-01-01: false +KY: + 2018-01-01: false +LA: + 2018-01-01: true +MA: + 2018-01-01: true +MD: + 2018-01-01: false +ME: + 2018-01-01: true +MI: + 2018-01-01: true +MN: + 2018-01-01: true +MO: + 2018-01-01: true +MS: + # The poverty-level aged and disabled group was in force by fiscal year 1997, + # which began July 1, 1996; its start date is not sourced. It ended + # December 31, 2005. + 1996-07-01: true + 2006-01-01: false +MT: + 2018-01-01: true +NC: + 2018-01-01: true +ND: + 2018-01-01: false +NE: + 2018-01-01: true +NH: + 2018-01-01: true +NJ: + 2018-01-01: true +NM: + 2018-01-01: false +NV: + 2018-01-01: false +NY: + 2018-01-01: true +OH: + 2018-01-01: true +OK: + 2018-01-01: true +OR: + 2018-01-01: true +PA: + 2018-01-01: true +RI: + 2018-01-01: true +SC: + 2018-01-01: true +SD: + 2018-01-01: false +TN: + 2018-01-01: false +TX: + 2018-01-01: false +UT: + 2018-01-01: true +VA: + 2018-01-01: true +VT: + 2018-01-01: true +WA: + 2018-01-01: true +WI: + 2018-01-01: true +WV: + # SSI-Related/Non-Cash Assistance covers people under the SSI payment level. + 2018-01-01: true +WY: + 2018-01-01: false diff --git a/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/income/limit/couple.yaml b/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/income/limit/couple.yaml index 0eb1c1e8aaa..45f093c19a3 100644 --- a/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/income/limit/couple.yaml +++ b/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/income/limit/couple.yaml @@ -1,4 +1,4 @@ -description: Maximum countable income limit for a couple to qualify for Medicaid under the optional senior or disabled pathway, as percent of Federal Poverty Line. States whose limit is the SSI federal benefit rate are listed in uses_ssi_federal_benefit_rate and omitted here. +description: Maximum countable income limit for a couple to qualify for Medicaid under the optional senior or disabled pathway, as percent of Federal Poverty Line. States whose limit is the SSI federal benefit rate are listed in uses_ssi_federal_benefit_rate and omitted here; states where covers_non_ssi_recipients is false also use that rate, and their values here apply only if that flag is true. metadata: unit: /1 label: Medicaid senior or disabled income limit (couple) diff --git a/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/income/limit/individual.yaml b/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/income/limit/individual.yaml index 489de5e9165..99c150219c2 100644 --- a/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/income/limit/individual.yaml +++ b/policyengine_us/parameters/gov/hhs/medicaid/eligibility/categories/senior_or_disabled/income/limit/individual.yaml @@ -1,4 +1,4 @@ -description: Maximum countable income limit for an individual to qualify for Medicaid under the optional senior or disabled pathway, as percent of Federal Poverty Line. States whose limit is the SSI federal benefit rate are listed in uses_ssi_federal_benefit_rate and omitted here. +description: Maximum countable income limit for an individual to qualify for Medicaid under the optional senior or disabled pathway, as percent of Federal Poverty Line. States whose limit is the SSI federal benefit rate are listed in uses_ssi_federal_benefit_rate and omitted here; states where covers_non_ssi_recipients is false also use that rate, and their values here apply only if that flag is true. metadata: unit: /1 label: Medicaid senior or disabled income limit (individual) diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_for_medicaid.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_for_medicaid.yaml index 5cd7b9fe4c7..9f7afb5c3a5 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_for_medicaid.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_for_medicaid.yaml @@ -15,3 +15,161 @@ is_optional_senior_or_disabled_asset_eligible: false output: is_optional_senior_or_disabled_for_medicaid: false + +# 2026: Social Security of $900 a month leaves countable income of $10,560 a +# year after the $20 a month disregard, under the SSI rate ($11,928). +- name: Case 3, aged Alabaman who does not take up SSI is not covered, since Alabama covers only SSI recipients. + period: 2026 + input: + age: 70 + state_code: AL + social_security_retirement: 10_800 + takes_up_ssi_if_eligible: false + output: + ssi: 0 + is_optional_senior_or_disabled_income_eligible: true + is_optional_senior_or_disabled_for_medicaid: false + medicaid_category: NONE + is_medicaid_eligible: false + +- name: Case 4, the same person in Pennsylvania, which covers aged people who do not receive SSI, is covered. + period: 2026 + input: + age: 70 + state_code: PA + social_security_retirement: 10_800 + takes_up_ssi_if_eligible: false + output: + is_optional_senior_or_disabled_for_medicaid: true + medicaid_category: SENIOR_OR_DISABLED + is_medicaid_eligible: true + +# North Dakota covers aged, blind, or disabled people who do not receive SSI +# only as medically needy (N.D. Admin. Code 75-02-02.1-05(3)(e)). +- name: Case 5, disabled North Dakotan who does not take up SSI is not covered by the pathway. + period: 2026 + input: + age: 50 + state_code: ND + meets_ssi_disability_criteria: true + social_security_disability: 10_800 + takes_up_ssi_if_eligible: false + output: + is_optional_senior_or_disabled_income_eligible: true + is_optional_senior_or_disabled_for_medicaid: false + +# Emergency Medicaid covers noncitizens who meet the state plan's requirements +# other than the receipt of SSI (42 U.S.C. 1396b(v)(2)(B); 42 CFR 435.406(b)). +# In Alabama that leaves SSI's income test. Wages of $800 a month ($9,600 a +# year) are under the SSI rate ($11,928) before any disregard. Until #10240 +# merges, the pathway counts no income for this person; Cases 7 and 8 test it. +- name: Case 6, undocumented aged Alabaman keeps the pathway, unlike the citizen in Case 3, and qualifies for emergency Medicaid. + period: 2026 + input: + age: 70 + state_code: AL + immigration_status: UNDOCUMENTED + employment_income_before_lsr: 9_600 + has_emergency_medical_condition: true + output: + is_medicaid_immigration_status_eligible: false + ssi: 0 + is_optional_senior_or_disabled_income_eligible: true + is_optional_senior_or_disabled_for_medicaid: true + medicaid_category: SENIOR_OR_DISABLED + is_medicaid_eligible: false + is_emergency_medicaid_eligible: true + +# A permanent resident two years after entry is in the five-year bar (8 U.S.C. +# 1613) and fails the Medicaid immigration test. The pathway then tests income +# against the 2026 SSI rate, 12 x $994 = $11,928, at or below it (42 U.S.C. +# 1382(a)(1)(A)). Social Security of $1,015 a month leaves countable income of +# (1,015 - 20) x 12 = $11,940, so SSI pays nothing and the person is not an SSI +# recipient. The pathway's countable income is an input. +- name: Case 7, Alabaman permanent resident in the five-year bar with income over the SSI rate gets neither the pathway nor emergency Medicaid. + period: 2026 + input: + age: 70 + state_code: AL + immigration_status: LEGAL_PERMANENT_RESIDENT + years_since_us_entry: 2 + social_security_retirement: 12_180 + medicaid_optional_senior_or_disabled_countable_income: 11_940 + has_emergency_medical_condition: true + output: + is_medicaid_immigration_status_eligible: false + ssi: 0 + medicaid_optional_senior_or_disabled_income_limit: 11_928 + is_optional_senior_or_disabled_income_eligible: false + is_optional_senior_or_disabled_for_medicaid: false + medicaid_category: NONE + is_emergency_medicaid_eligible: false + +# The SSI couple rate in 2026 is 12 x $1,491 = $17,892; the couple's countable +# income, $8,946 each, is exactly at it. Social Security of $755.50 a month +# each gives the couple (1,511 - 20) x 12 = $17,892, so SSI pays nothing and +# neither spouse is an SSI recipient. Only the first spouse has an emergency +# medical condition. +- name: Case 8, Alabaman permanent-resident couple in the five-year bar at the SSI couple rate keeps the pathway. + period: 2026 + input: + people: + person1: + age: 70 + immigration_status: LEGAL_PERMANENT_RESIDENT + years_since_us_entry: 2 + social_security_retirement: 9_066 + medicaid_optional_senior_or_disabled_countable_income: 8_946 + has_emergency_medical_condition: true + person2: + age: 68 + immigration_status: LEGAL_PERMANENT_RESIDENT + years_since_us_entry: 2 + social_security_retirement: 9_066 + medicaid_optional_senior_or_disabled_countable_income: 8_946 + has_emergency_medical_condition: false + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AL + output: + is_medicaid_immigration_status_eligible: [false, false] + ssi: [0, 0] + medicaid_optional_senior_or_disabled_income_limit: [17_892, 17_892] + is_optional_senior_or_disabled_income_eligible: [true, true] + is_optional_senior_or_disabled_for_medicaid: [true, true] + medicaid_category: [SENIOR_OR_DISABLED, SENIOR_OR_DISABLED] + is_medicaid_eligible: [false, false] + is_emergency_medicaid_eligible: [true, false] + +# A permanent resident ten years after entry is past the five-year bar, so +# passes the Medicaid immigration test, but with no qualifying quarters fails +# SSI's noncitizen test (8 U.S.C. 1612(a)(2)(B)) and gets no SSI. Alabama has +# no group for aged people who do not receive SSI, and the emergency Medicaid +# exception does not reach someone who passes the Medicaid immigration test. +- name: Case 9, Alabaman permanent resident past the five-year bar without 40 quarters does not keep the pathway. + period: 2026 + input: + age: 70 + state_code: AL + immigration_status: LEGAL_PERMANENT_RESIDENT + years_since_us_entry: 10 + ssi_qualifying_quarters_earnings: 0 + social_security_retirement: 10_800 + output: + is_medicaid_immigration_status_eligible: true + ssi: 0 + is_optional_senior_or_disabled_income_eligible: true + is_optional_senior_or_disabled_for_medicaid: false + medicaid_category: NONE + is_medicaid_eligible: false + is_emergency_medicaid_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medicaid_category.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medicaid_category.yaml index 6489f6b6a1f..23338548149 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medicaid_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/categories/medicaid_category.yaml @@ -161,3 +161,35 @@ is_optional_senior_or_disabled_for_medicaid: [true, true] medicaid_category: [SENIOR_OR_DISABLED, SENIOR_OR_DISABLED] is_medicaid_eligible: [true, true] + +# 2026: an aged person with $900 a month of Social Security receives SSI of +# $994 - ($900 - $20) = $114 a month. +- name: Case 13, aged Alabaman who receives SSI is an SSI recipient. + period: 2026 + input: + age: 70 + state_code: AL + social_security_retirement: 10_800 + output: + ssi: 1_368 + medicaid_category: SSI_RECIPIENT + is_medicaid_eligible: true + +# Maryland covers aged, blind, or disabled people who do not receive SSI as +# medically needy, not as categorically needy. Countable income of $10,560 a +# year less $7,200 of other medical expenses (and any modeled Medicare Part B +# premium) is at most $3,360, under the medically needy limit of $350 a month +# ($4,200 a year). +- name: Case 14, aged Marylander who does not take up SSI spends down to medically needy coverage. + period: 2026 + input: + age: 70 + state_code: MD + social_security_retirement: 10_800 + takes_up_ssi_if_eligible: false + other_medical_expenses: 7_200 + output: + is_optional_senior_or_disabled_for_medicaid: false + is_medically_needy_for_medicaid: true + medicaid_category: MEDICALLY_NEEDY + is_medicaid_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ms/dom/hmw/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ms/dom/hmw/integration.yaml index f7fb8b4e1fc..43bbbc97e63 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ms/dom/hmw/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ms/dom/hmw/integration.yaml @@ -79,7 +79,7 @@ output: ms_hmw_eligible: false -- name: Case 7, person eligible under standard optional ABD Medicaid does not use HMW. +- name: Case 7, disabled person who receives SSI gets SSI-recipient Medicaid, not HMW. period: 2026 input: age: 45 @@ -90,6 +90,7 @@ medicaid_optional_senior_or_disabled_countable_income: 5_000 ssi_countable_resources: 1_500 output: + is_ssi_recipient_for_medicaid: true ms_hmw_eligible: false ms_hmw_other_coverage_ineligible: false diff --git a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/cash/ssi/federal.yaml b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/cash/ssi/federal.yaml index 802de5f7ba3..b3c8136f0c2 100644 --- a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/cash/ssi/federal.yaml +++ b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/cash/ssi/federal.yaml @@ -282,18 +282,20 @@ is_ssi_aged: true msp: 0 msp_eligible: false - # Despite $0 SSI, still Medicaid-eligible via TX's optional - # senior-or-disabled pathway: SSI-method countable income $11,928 - # <= 75% of FPG (0.75 x $15,960 = $11,970), so the calibration- - # derived TX adult per-capita cost applies. - medicaid: 13_708.50 - is_medicaid_eligible: true + # $0 SSI, so not an SSI recipient. Texas covers aged, blind and + # disabled people at home only if they receive SSI; its optional + # groups are institutional, waiver and buy-in groups (MEPD A-3000), + # with no 75% FPG group, so no Medicaid. + medicaid: 0 + is_medicaid_eligible: false chip: 0 - is_aca_ptc_eligible: false + # Without Medicaid, Medicare or an ESI offer, the PTC applies at + # 158% FPL: SLCSP $19,482.51 - 4.58% x $24,876 MAGI ($1,138.23). + is_aca_ptc_eligible: true tax_units: tax_unit: - aca_ptc: 0 - premium_tax_credit: 0 + aca_ptc: 18_344.29 + premium_tax_credit: 18_344.29 - name: ssi_unearned_income_reduction (federal) period: 2026 absolute_error_margin: 0.1 diff --git a/policyengine_us/tests/unit/test_medicaid_abd_ssi_rate_standard_properties.py b/policyengine_us/tests/unit/test_medicaid_abd_ssi_rate_standard_properties.py index f9f38924c16..03e6f445eda 100644 --- a/policyengine_us/tests/unit/test_medicaid_abd_ssi_rate_standard_properties.py +++ b/policyengine_us/tests/unit/test_medicaid_abd_ssi_rate_standard_properties.py @@ -189,10 +189,20 @@ def test_no_medicaid_without_ssi_above_the_ssi_rate(year): standard = 12 * individual # Section 209(b) states test SSI recipients against their own criteria, # so the SSI-receipt half of this property is stated for the others. - classification = SYSTEM.parameters( + categories = SYSTEM.parameters( f"{year}-01-01" - ).gov.hhs.medicaid.eligibility.categories.ssi_recipient.classification + ).gov.hhs.medicaid.eligibility.categories + classification = categories.ssi_recipient.classification states = [state for state in SSI_RATE_STATES for _ in OFFSETS] + # States without a group for people who do not receive SSI give the + # pathway to nobody in this citizen grid. All seven states here have the + # group; the mask matters once North Dakota joins the grid (#10373). + covers = np.array( + [ + bool(categories.senior_or_disabled.covers_non_ssi_recipients[state]) + for state in states + ] + ) countable = np.array( [standard + offset for _ in SSI_RATE_STATES for offset in OFFSETS] ) @@ -219,12 +229,14 @@ def test_no_medicaid_without_ssi_above_the_ssi_rate(year): # Under the rate the pathway's own tests pass, and at it they pass # except where the state requires income below the standard. covered = (countable < standard) | (at_rate & ~below_only) - assert optional[covered].all() - assert not optional[~covered].any() + assert optional[covered & covers].all() + assert not optional[~covered | ~covers].any() not_209b = np.array([not classification.section_209b[state] for state in states]) receives = (countable < standard) & not_209b assert (category[receives] == "SSI_RECIPIENT").all() - assert (category[at_rate & ~below_only & not_209b] == "SENIOR_OR_DISABLED").all() + assert ( + category[at_rate & ~below_only & not_209b & covers] == "SENIOR_OR_DISABLED" + ).all() # In Oregon a person exactly at the rate gets neither SSI nor the pathway. assert not (category[at_rate & below_only] == "SENIOR_OR_DISABLED").any() @@ -238,6 +250,12 @@ def test_unflagged_states_keep_their_share_of_the_poverty_guideline(year, couple states = [ state for state in STATES if state not in SSI_RATE_STATES and state != "MO" ] + # States without a group for people who do not receive SSI use the SSI + # rate for the noncitizens their pathway still reaches. + covers = SYSTEM.parameters( + f"{year}-01-01" + ).gov.hhs.medicaid.eligibility.categories.senior_or_disabled.covers_non_ssi_recipients + states = [state for state in states if covers[state]] simulation = unit_simulation(year, states, couple) limit = simulation.calculate( "medicaid_optional_senior_or_disabled_income_limit", year @@ -255,3 +273,29 @@ def test_unflagged_states_keep_their_share_of_the_poverty_guideline(year, couple ] ) np.testing.assert_allclose(limit, expected, rtol=1e-6) + + +# States whose rules cover aged, blind, or disabled people as categorically +# needy only if they receive SSI (cited in covers_non_ssi_recipients.yaml). +SSI_ONLY_STATES = sorted( + ["AL", "DE", "GA", "KS", "KY", "MD", "MS", "ND", "NM", "NV", "SD", "TN", "TX", "WY"] +) + + +@pytest.mark.parametrize("year", YEARS) +def test_ssi_only_states_match_their_rules(year): + flags = SYSTEM.parameters( + f"{year}-01-01" + ).gov.hhs.medicaid.eligibility.categories.senior_or_disabled.covers_non_ssi_recipients + assert sorted(state for state in STATES if not flags[state]) == SSI_ONLY_STATES + + +@pytest.mark.parametrize("couple", [False, True]) +@pytest.mark.parametrize("year", YEARS) +def test_ssi_only_states_use_the_ssi_rate(year, couple): + simulation = unit_simulation(year, SSI_ONLY_STATES, couple) + limit = simulation.calculate( + "medicaid_optional_senior_or_disabled_income_limit", year + ) + individual, couple_rate = SSA_MONTHLY_RATES[year] + np.testing.assert_array_equal(limit, 12 * (couple_rate if couple else individual)) diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_for_medicaid.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_for_medicaid.py index 51886d8c2b6..a96f2df6cbb 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_for_medicaid.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/is_optional_senior_or_disabled_for_medicaid.py @@ -7,12 +7,32 @@ class is_optional_senior_or_disabled_for_medicaid(Variable): label = "Seniors or disabled people not meeting SSI rules" documentation = "Whether this person qualifies for Medicaid through the State's optional aged, blind, or disabled pathway (not otherwise SSI-eligible)" definition_period = YEAR - reference = "https://www.law.cornell.edu/uscode/text/42/1396a#m" + reference = ( + "https://www.law.cornell.edu/uscode/text/42/1396a#m", + "https://www.law.cornell.edu/uscode/text/42/1396b#v", + "https://www.ecfr.gov/current/title-42/section-435.406#p-435.406(b)", + "https://www.ecfr.gov/current/title-42/section-440.255#p-440.255(c)", + ) def formula(person, period, parameters): + # Some states cover aged, blind, or disabled people as categorically + # needy only if they receive SSI, and have no group for those who do not. + # Emergency Medicaid waives the SSI receipt requirement for noncitizens + # who fail the Medicaid immigration test (42 U.S.C. 1396b(v)(2)(B); + # 42 CFR 435.406(b) and 440.255(c)), so they stay in this group. + state = person.household("state_code_str", period) + p = parameters( + period + ).gov.hhs.medicaid.eligibility.categories.senior_or_disabled + immigration_eligible = person("is_medicaid_immigration_status_eligible", period) + in_covered_group = ( + p.covers_non_ssi_recipients[state].astype(bool) | ~immigration_eligible + ) is_senior_or_disabled = person("is_ssi_aged_blind_disabled", period) income_eligible = person( "is_optional_senior_or_disabled_income_eligible", period ) asset_eligible = person("is_optional_senior_or_disabled_asset_eligible", period) - return is_senior_or_disabled & income_eligible & asset_eligible + return ( + in_covered_group & is_senior_or_disabled & income_eligible & asset_eligible + ) diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medicaid_optional_senior_or_disabled_income_limit.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medicaid_optional_senior_or_disabled_income_limit.py index cb5260bda63..6e676553384 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medicaid_optional_senior_or_disabled_income_limit.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/categories/medicaid_optional_senior_or_disabled_income_limit.py @@ -14,8 +14,11 @@ class medicaid_optional_senior_or_disabled_income_limit(Variable): reference = ( "https://www.law.cornell.edu/uscode/text/42/1396a#m", "https://www.ecfr.gov/current/title-42/section-435.210", + "https://www.law.cornell.edu/uscode/text/42/1396b#v", + "https://www.law.cornell.edu/uscode/text/42/1382#a", "https://dssmanuals.mo.gov/mo-healthnet-for-the-aged-blind-and-disabled/0805-000-00/0805-015-00/0805-015-45-income-maximum/", "https://dssmanuals.mo.gov/wp-content/uploads/2022/07/mhabd-appendix-j.pdf#page=1", + "https://www.ndlegis.gov/information/acdata/pdf/75-02-02.1.pdf#page=89", ) def formula(person, period, parameters): @@ -49,9 +52,17 @@ def formula(person, period, parameters): # dollar amount for an individual or a couple, rather than a share of # the poverty guideline (the group of 42 CFR 435.210; Louisiana pegs # its 42 U.S.C. 1396a(m) level to the same rate). + # States that cover aged, blind, or disabled people only if they + # receive SSI apply this limit to noncitizens kept in the pathway for + # emergency Medicaid, which waives SSI receipt alone (42 U.S.C. + # 1396b(v)(2)(B)), so they must meet SSI's income test. North + # Dakota's 209(b) recipients also read it, and its level is SSI's + # (N.D. Admin. Code 75-02-02.1-40(1)(a)(2)). ssi = parameters(period).gov.ssa.ssi.amount ssi_rate = where(is_couple, ssi.couple, ssi.individual) * MONTHS_IN_YEAR - uses_ssi_rate = p.income.limit.uses_ssi_federal_benefit_rate[state].astype(bool) + sets_ssi_rate = p.income.limit.uses_ssi_federal_benefit_rate[state].astype(bool) + covers_group = p.covers_non_ssi_recipients[state].astype(bool) + uses_ssi_rate = sets_ssi_rate | ~covers_group return select( [is_mo, uses_ssi_rate], [mo_monthly_limit * MONTHS_IN_YEAR, ssi_rate],