From 339a1f1b031fa49740a330b951bac0af0def1d1c Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 24 Aug 2026 23:32:10 -0400 Subject: [PATCH 1/6] Fix federal disability gates disconnected from their legal definitions Aligns six federal disability gates with the definitions their statutes actually reference (part of the #9330 disconnected-disability-inputs audit): - SNAP disabled_programs (7 CFR 271.2): qualify by SSI receipt (receives_ssi | ssi) instead of the is_ssi_disabled criteria flag, which has no receipt test and drops blind SSI recipients. - SNAP ABAWD, work registration, general work requirements, and student rules (7 CFR 273.7(b)(1)(ii), 273.24(c)(2)): disability benefit receipt (is_usda_disabled) establishes unfitness for employment. - SSI student earned income exclusion (20 CFR 416.1112(c)(3)): gate on is_ssi_disabled rather than the generic is_disabled flag. - Medicaid work requirement and home equity family exception (42 U.S.C. 1396p(f)(2)): recognize the Section 1614 SSI definition. - HUD person with disabilities (42 U.S.C. 1437a(b)(3)(E)): recognize the SSA Section 223 path via is_ssi_disabled and SSDI receipt; drop the stray unit = USD on the boolean. Fixes #9329 Fixes #9331 Fixes #9332 Fixes #9333 Fixes #9334 Fixes #9337 Co-Authored-By: Claude Fable 5 --- changelog.d/fix-disability-input-disconnects.fixed.md | 6 ++++++ .../parameters/gov/usda/disabled_programs.yaml | 10 ++++++++-- .../medicaid_home_equity_limit_family_exception.py | 3 +++ .../eligibility/medicaid_work_requirement_eligible.py | 7 ++++++- .../variables/gov/hud/income/is_hud_dependent.py | 5 +++++ .../gov/hud/is_hud_elderly_disabled_family.py | 11 +++++++++-- ..._or_disabled_working_student_exclusion_eligible.py | 8 ++++++-- .../variables/gov/usda/is_usda_disabled.py | 6 +++++- .../eligibility/student/is_snap_ineligible_student.py | 8 ++++++-- .../work_requirements/is_snap_abawd_exempt.py | 8 ++++++-- .../is_snap_work_registration_exempt_non_age.py | 9 +++++++-- .../meets_snap_general_work_requirements.py | 9 +++++++-- 12 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 changelog.d/fix-disability-input-disconnects.fixed.md diff --git a/changelog.d/fix-disability-input-disconnects.fixed.md b/changelog.d/fix-disability-input-disconnects.fixed.md new file mode 100644 index 00000000000..bab8e2bb3da --- /dev/null +++ b/changelog.d/fix-disability-input-disconnects.fixed.md @@ -0,0 +1,6 @@ +Align federal disability gates with their governing legal definitions: +- SNAP elderly or disabled member (7 CFR 271.2): qualify by SSI receipt rather than the SSI disability criteria flag. +- SNAP work requirement, work registration, ABAWD, and student rules: recognize disability benefit receipt as unfitness for employment. +- SSI student earned income exclusion: use the SSI disability test rather than the generic disability flag. +- Medicaid work requirement and home equity family exception: recognize the Section 1614 SSI disability definition. +- HUD person-with-disabilities status: recognize the SSI and SSDI disability paths. diff --git a/policyengine_us/parameters/gov/usda/disabled_programs.yaml b/policyengine_us/parameters/gov/usda/disabled_programs.yaml index 70086e22344..1beb12367b8 100644 --- a/policyengine_us/parameters/gov/usda/disabled_programs.yaml +++ b/policyengine_us/parameters/gov/usda/disabled_programs.yaml @@ -1,8 +1,12 @@ -description: Program participation that qualify individuals as disabled under USDA rules +description: Benefit receipt that qualifies individuals as elderly or disabled members for SNAP. values: 2021-01-01: - - is_ssi_disabled + # 7 CFR 271.2 defines "elderly or disabled member" by benefit receipt + # ("receives supplemental security income benefits ... or disability or + # blindness payments"), not by meeting the disability criteria alone. + - receives_ssi + - ssi - social_security_disability - is_permanently_disabled_veteran - is_surviving_spouse_of_disabled_veteran @@ -12,3 +16,5 @@ metadata: reference: - title: "SNAP Special Rules for the Elderly or Disabled" href: https://www.fns.usda.gov/snap/eligibility/elderly-disabled-special-rules#Who%20is%20elderly? + - title: 7 CFR 271.2 (definition of elderly or disabled member) + href: https://www.law.cornell.edu/cfr/text/7/271.2 diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_home_equity_limit_family_exception.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_home_equity_limit_family_exception.py index 0cc3c7056ff..3a3f9b88678 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_home_equity_limit_family_exception.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_home_equity_limit_family_exception.py @@ -22,6 +22,9 @@ def formula(person, period, parameters): | person("is_blind", period) | person("is_disabled", period) | person("is_permanently_and_totally_disabled", period) + # 42 U.S.C. 1396p(f)(2)(A)(ii)(II) defines the child's disability + # by cross-reference to section 1614 (the SSI definition). + | person("is_ssi_disabled", period) ) has_resident_child = ( person.household.sum(qualifying_resident_child) > qualifying_resident_child diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py index e175df2457f..3640bea0bb9 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py @@ -72,7 +72,12 @@ def formula(person, period, parameters): # blind or disabled or is_incapable_of_self_care p.694 (V) is_blind = person("is_blind", period) is_incapable_of_self_care = person("is_incapable_of_self_care", period) - eligible_disabled = is_blind | is_disabled | is_incapable_of_self_care + # "Blind or disabled" is defined by cross-reference to section 1614 + # of the Social Security Act, so the SSI disability test also exempts. + is_ssi_disabled = person("is_ssi_disabled", period) + eligible_disabled = ( + is_blind | is_disabled | is_ssi_disabled | is_incapable_of_self_care + ) medically_frail = person( "is_medically_frail_or_has_special_medical_needs_for_medicaid_ce", period, diff --git a/policyengine_us/variables/gov/hud/income/is_hud_dependent.py b/policyengine_us/variables/gov/hud/income/is_hud_dependent.py index 4619ec710ab..2b7768b1daa 100644 --- a/policyengine_us/variables/gov/hud/income/is_hud_dependent.py +++ b/policyengine_us/variables/gov/hud/income/is_hud_dependent.py @@ -23,9 +23,14 @@ def formula(person, period, parameters): & ~is_head ) is_hud_head_or_spouse = is_head | is_head_spouse + # The "person with disabilities" definition (42 U.S.C. 1437a(b)(3)(E)) + # includes the section 223 SSA disability standard, so the SSI/SSDI + # paths qualify alongside the generic disability flag. meets_dependent_condition = ( person("is_child", period) | person("is_disabled", period) + | person("is_ssi_disabled", period) + | (person("social_security_disability", period) > 0) | person("is_full_time_student", period) ) is_foster = person("is_in_foster_care", period) diff --git a/policyengine_us/variables/gov/hud/is_hud_elderly_disabled_family.py b/policyengine_us/variables/gov/hud/is_hud_elderly_disabled_family.py index 4424ccf6920..222c39ea1e6 100644 --- a/policyengine_us/variables/gov/hud/is_hud_elderly_disabled_family.py +++ b/policyengine_us/variables/gov/hud/is_hud_elderly_disabled_family.py @@ -5,7 +5,6 @@ class is_hud_elderly_disabled_family(Variable): value_type = bool entity = SPMUnit label = "HUD elderly or disabled family" - unit = USD documentation = "Whether an SPM unit is deemed elderly or disabled for HUD purposes" definition_period = YEAR reference = "https://www.law.cornell.edu/cfr/text/24/5.611" @@ -14,7 +13,15 @@ def formula(spm_unit, period, parameters): hud = parameters(period).gov.hud person = spm_unit.members elderly = person("age", period) >= hud.elderly_age_threshold - disabled = person("is_disabled", period) + # 42 U.S.C. 1437a(b)(3)(E) defines a person with disabilities to + # include anyone with a disability as defined in section 223 of the + # Social Security Act (the SSDI standard), so the SSI/SSDI paths + # qualify alongside the generic disability flag. + disabled = ( + person("is_disabled", period) + | person("is_ssi_disabled", period) + | (person("social_security_disability", period) > 0) + ) child = person("is_child", period) elderly_disabled_adult = (elderly | disabled) & ~child # Simplify to having any elderly or disabled adults. diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py index fb035433068..8bb86905864 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py @@ -13,9 +13,13 @@ def formula(person, period, parameters): p = parameters( period ).gov.ssa.ssi.income.exclusions.blind_or_disabled_working_student + # "Blind or disabled" takes SSA's own meaning here: the exclusion + # applies to a blind or disabled SSI claimant (20 CFR 416.1112(c)(3)), + # so the SSI disability test (SSI criteria and not engaged in SGA) + # governs rather than the generic disability flag. is_blind = person("is_blind", period) - is_disabled = person("is_disabled", period) - demographic_eligible = is_blind | is_disabled + is_ssi_disabled = person("is_ssi_disabled", period) + demographic_eligible = is_blind | is_ssi_disabled under_age_limit = person("age", period) < p.age_limit eligible_student = under_age_limit & person("is_full_time_student", period) return eligible_student & demographic_eligible diff --git a/policyengine_us/variables/gov/usda/is_usda_disabled.py b/policyengine_us/variables/gov/usda/is_usda_disabled.py index eaf15235460..d666406e96b 100644 --- a/policyengine_us/variables/gov/usda/is_usda_disabled.py +++ b/policyengine_us/variables/gov/usda/is_usda_disabled.py @@ -5,7 +5,11 @@ class is_usda_disabled(Variable): value_type = bool entity = Person definition_period = YEAR - documentation = "Disabled according to USDA criteria" + documentation = ( + "Meets the benefit-receipt half of the SNAP 'elderly or disabled " + "member' definition (7 CFR 271.2), which counts any SSI receipt, " + "whether based on age, blindness, or disability." + ) label = "USDA disabled status" def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/student/is_snap_ineligible_student.py b/policyengine_us/variables/gov/usda/snap/eligibility/student/is_snap_ineligible_student.py index 01494774cbf..f81de6bd8fc 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/student/is_snap_ineligible_student.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/student/is_snap_ineligible_student.py @@ -23,8 +23,12 @@ def formula(person, period, parameters): # would make the ~ below a bitwise negation instead of a logical one. meets_age_exception = p.age_threshold.calc(age).astype(bool) - # Exception 2: Not physically or mentally fit (disabled) - meets_disability_exception = person("is_disabled", period) + # Exception 2: Not physically or mentally fit (disabled); receipt of + # disability benefits establishes unfitness (7 CFR 273.7(b)(1)(ii)), + # so the USDA receipt-based definition also qualifies. + meets_disability_exception = person("is_disabled", period) | person( + "is_usda_disabled", period + ) # Exceptions 3 and 7: Placed in or enrolled in an institution of # higher education through a qualifying program — an employment and diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.py b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.py index 47fd5d94a6f..0229ef67b05 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.py @@ -38,8 +38,12 @@ def formula(person, period, parameters): p.age_threshold.exempted.calc(age), p_pre.age_threshold.exempted.calc(age), ) - # (B) Disability — 7 U.S.C. 2015(o)(3)(B) - is_disabled = person("is_disabled", period) + # (B) Disability — 7 U.S.C. 2015(o)(3)(B); 7 CFR 273.24(c)(2) treats + # receipt of government or private disability benefits as unfitness + # for employment, so the USDA receipt-based definition also exempts. + is_disabled = person("is_disabled", period) | person( + "is_usda_disabled", period.this_year + ) # (D) Work registration exempt (non-age) — 7 U.S.C. 2015(o)(3)(D), # including the 7 CFR 273.7(b)(1)(vii) exemption for people working # 30 or more hours weekly. diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py index 7acb5cceb2c..4a4dc082a4e 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py @@ -15,8 +15,13 @@ def formula(person, period, parameters): p = parameters(period).gov.usda.snap.work_requirements.general # Age-based exemptions under (b)(1)(i) are handled in the # age-based work registration exemption logic. - # (ii) Physically or mentally unfit for employment - is_disabled = person("is_disabled", period) + # (ii) Physically or mentally unfit for employment; per 7 CFR + # 273.7(b)(1)(ii), receipt of temporary or permanent disability + # benefits establishes unfitness, so the USDA receipt-based + # definition also exempts. + is_disabled = person("is_disabled", period) | person( + "is_usda_disabled", period.this_year + ) # (iii) Subject to and complying with TANF work requirements. # TANF enrollment is an existing SPM-unit input; person-level # compliance is a documented input the data layer may not yet diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.py b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.py index f700bb8910b..5285ad3f66d 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.py @@ -37,8 +37,13 @@ def formula(person, period, parameters): # Exemptions under 7 CFR 273.7(b)(1): # Under 16 or 60 years of age or older are exempted worked_exempted_age = p.age_threshold.exempted.calc(age) - # Unable to work due to a physical or mental limitation - is_disabled = person("is_disabled", period) + # Unable to work due to a physical or mental limitation; per 7 CFR + # 273.7(b)(1)(ii), receipt of temporary or permanent disability + # benefits establishes unfitness, so the USDA receipt-based + # definition also exempts. + is_disabled = person("is_disabled", period) | person( + "is_usda_disabled", period.this_year + ) # Taking care of a child under six or an incapacitated person is_dependent = person("is_tax_unit_dependent", period) is_child = age < p.age_threshold.caring_dependent_child From 9668a12c9292e9d52ce17996c3b6c47861e7f845 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 25 Aug 2026 00:35:54 -0400 Subject: [PATCH 2/6] Move SEIE eligibility tests from 1974 to 1975 The gate now computes is_ssi_disabled, whose SGA parameter (gov.ssa.sga.non_blind) has no values before 1975-01-01, so the 1974-period cases crashed on an undefined parameter. Co-Authored-By: Claude Fable 5 --- ...nd_or_disabled_working_student_exclusion_eligible.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml index df6bfbfee5f..b9141ab911d 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml @@ -1,5 +1,5 @@ - name: Not demographic eligible nor student eligible - period: 1974 + period: 1975 input: is_blind: true is_disabled: false @@ -9,7 +9,7 @@ is_ssi_blind_or_disabled_working_student_exclusion_eligible: false - name: Demographic eligible but not student eligible - period: 1974 + period: 1975 input: is_blind: true is_disabled: false @@ -19,7 +19,7 @@ is_ssi_blind_or_disabled_working_student_exclusion_eligible: false - name: Student eligible but not demographic eligible - period: 1974 + period: 1975 input: is_blind: false is_disabled: false @@ -29,7 +29,7 @@ is_ssi_blind_or_disabled_working_student_exclusion_eligible: false - name: Eligible - period: 1974 + period: 1975 input: is_blind: false is_disabled: true From 484e57f5f3aef0c1eac0296f298fa7c52c161b44 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 3 Sep 2026 01:17:45 -0400 Subject: [PATCH 3/6] Test the receipt-based USDA disabled list and the new disability legs - Rewrite is_usda_disabled tests to exercise receives_ssi, an ssi input, modeled SSI receipt, blind and aged SSI recipients, and the negative case where the SSI disability test is met but no SSI is received. - Add one benefit-receipt case to each formula that gained an SSI or SSDI leg: SNAP ABAWD, work registration, general work requirements, student rule, Medicaid work requirement, Medicaid home equity family exception, HUD elderly/disabled family, and HUD dependent. Co-Authored-By: Claude Fable 5.1 --- ...d_long_term_care_home_equity_eligible.yaml | 30 ++++++++++ .../medicaid_work_requirement_eligible.yaml | 11 ++++ .../baseline/gov/hud/is_hud_dependent.yaml | 44 +++++++++++++++ .../gov/hud/is_hud_elderly_disabled.yaml | 20 +++++++ .../baseline/gov/usda/is_usda_disabled.yaml | 55 ++++++++++++++++++- .../student/is_snap_ineligible_student.yaml | 12 ++++ .../is_snap_abawd_exempt.yaml | 20 +++++++ ...snap_work_registration_exempt_non_age.yaml | 11 ++++ .../meets_snap_general_work_requirements.yaml | 15 +++++ 9 files changed, 215 insertions(+), 3 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/is_medicaid_long_term_care_home_equity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/is_medicaid_long_term_care_home_equity_eligible.yaml index 004b5811086..c625460938e 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/is_medicaid_long_term_care_home_equity_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/is_medicaid_long_term_care_home_equity_eligible.yaml @@ -295,3 +295,33 @@ home_equity: 1_217_001 output: is_medicaid_long_term_care_home_equity_eligible: false + +- name: Case 19, resident adult child meeting the section 1614 SSI disability test triggers the family exception. + period: 2028 + input: + people: + person1: + age: 65 + receives_medicaid_long_term_care_services: true + home_equity: 1_000_001 + person2: + age: 30 + is_disabled: false + is_ssi_disabled: true + is_related_to_head_or_spouse: true + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + output: + medicaid_home_equity_limit_family_exception: [true, false] + is_medicaid_long_term_care_home_equity_eligible: [true, true] diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.yaml index 1930e3c7205..3fa67b1aad2 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.yaml @@ -401,3 +401,14 @@ medicaid_community_engagement_pass_through_eligible: false output: medicaid_work_requirement_eligible: false + +- name: Case 41, meeting the section 1614 SSI disability test exempts without the generic disability flag. + period: 2027 + input: + age: 30 + monthly_hours_worked: 0 + is_disabled: false + is_ssi_disabled: true + medicaid_community_engagement_pass_through_eligible: false + output: + medicaid_work_requirement_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/hud/is_hud_dependent.yaml b/policyengine_us/tests/policy/baseline/gov/hud/is_hud_dependent.yaml index 33060ed5bb4..a344d28992b 100644 --- a/policyengine_us/tests/policy/baseline/gov/hud/is_hud_dependent.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hud/is_hud_dependent.yaml @@ -127,3 +127,47 @@ # Both are disabled adults filing separately; only the oldest is # excluded as the family head, so the younger one is a dependent. is_hud_dependent: [false, true] + +- name: A non-head adult meeting the SSI disability test is a HUD dependent (42 U.S.C. 1437a(b)(3)(E)). + period: 2022 + input: + people: + head: + age: 45 + is_household_head: true + person: + age: 40 + is_disabled: false + is_ssi_disabled: true + tax_units: + tax_unit1: + members: [head] + tax_unit2: + members: [person] + spm_units: + spm_unit: + members: [head, person] + output: + is_hud_dependent: [false, true] + +- name: A non-head adult receiving SSDI is a HUD dependent (42 U.S.C. 1437a(b)(3)(E)). + period: 2022 + input: + people: + head: + age: 45 + is_household_head: true + person: + age: 40 + is_disabled: false + social_security_disability: 12_000 + tax_units: + tax_unit1: + members: [head] + tax_unit2: + members: [person] + spm_units: + spm_unit: + members: [head, person] + output: + is_hud_dependent: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/hud/is_hud_elderly_disabled.yaml b/policyengine_us/tests/policy/baseline/gov/hud/is_hud_elderly_disabled.yaml index ee08315c6a3..1b1568f3b54 100644 --- a/policyengine_us/tests/policy/baseline/gov/hud/is_hud_elderly_disabled.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hud/is_hud_elderly_disabled.yaml @@ -63,3 +63,23 @@ members: [parent, dependent] output: is_hud_elderly_disabled_family: false + +# 42 U.S.C. 1437a(b)(3)(E): the SSA disability standard qualifies alongside +# the generic disability flag. +- name: A one-person non-elderly family meeting the SSI disability test. + period: 2022 + input: + age: 48 + is_disabled: false + is_ssi_disabled: true + output: + is_hud_elderly_disabled_family: true + +- name: A one-person non-elderly family receiving SSDI. + period: 2022 + input: + age: 48 + is_disabled: false + social_security_disability: 12_000 + output: + is_hud_elderly_disabled_family: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/is_usda_disabled.yaml b/policyengine_us/tests/policy/baseline/gov/usda/is_usda_disabled.yaml index a31f19a9ca5..1cdab9f8b50 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/is_usda_disabled.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/is_usda_disabled.yaml @@ -1,20 +1,69 @@ -- name: People without any disability flags are not USDA disabled +# 7 CFR 271.2 "elderly or disabled member" item (2): the person must +# *receive* SSI (any category) or disability/blindness payments. Meeting the +# SSI disability criteria without receiving SSI does not qualify. + +- name: Case 1, people without any disability flags are not USDA disabled. period: 2021 input: age: 30 output: is_usda_disabled: false -- name: SSI disabled people are USDA disabled +- name: Case 2, reported SSI receipt qualifies. period: 2021 input: + age: 30 + receives_ssi: true + output: + is_usda_disabled: true + +- name: Case 3, a reported SSI amount supplied as the ssi input qualifies. + period: 2021 + input: + age: 30 + ssi: 6_000 + output: + is_usda_disabled: true + +- name: Case 4, modeled SSI receipt by a person meeting the SSI disability test qualifies. + period: 2021 + input: + age: 30 is_ssi_disabled: true + employment_income: 0 output: is_usda_disabled: true -- name: People receiving SSDI are USDA disabled +- name: Case 5, meeting the SSI disability test without receiving SSI does not qualify. period: 2021 input: + age: 30 + is_ssi_disabled: true + employment_income: 100_000 + output: + ssi: 0 + is_usda_disabled: false + +- name: Case 6, blind SSI recipients qualify. + period: 2021 + input: + age: 30 + is_blind: true + output: + is_usda_disabled: true + +- name: Case 7, aged SSI recipients qualify through SSI receipt and are also USDA elderly. + period: 2021 + input: + age: 66 + output: + is_usda_disabled: true + is_usda_elderly: true + +- name: Case 8, people receiving SSDI are USDA disabled. + period: 2021 + input: + age: 30 social_security_disability: 100 output: is_usda_disabled: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/is_snap_ineligible_student.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/is_snap_ineligible_student.yaml index 17068d3b8be..6d7bd4a6b92 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/is_snap_ineligible_student.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/is_snap_ineligible_student.yaml @@ -188,3 +188,15 @@ receives_tanf: true output: is_snap_ineligible_student: false + +- name: College student receiving SSDI meets the disability exception without the generic disability flag + period: 2022 + input: + is_full_time_college_student: true + age: 25 + is_disabled: false + weekly_hours_worked_before_lsr: 0 + is_parent: false + social_security_disability: 12_000 + output: + is_snap_ineligible_student: false diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.yaml index ea27f6ae007..1ad3bb18737 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.yaml @@ -266,3 +266,23 @@ state_code: TX output: is_snap_abawd_exempt: false + +# (B) Receipt of disability benefits establishes unfitness for employment +# (7 CFR 273.24(c)(2)) even without the generic disability flag. +- name: Case 16, SSDI recipient without the generic disability flag is exempt. + period: 2026-01 + input: + people: + person1: + age: 30 + is_disabled: false + social_security_disability: 12_000 + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + is_snap_abawd_exempt: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml index 1568ec2e479..784b1593f2d 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml @@ -218,3 +218,14 @@ weekly_hours_worked_before_lsr: 29 output: is_snap_work_registration_exempt_non_age: false + +# --- (ii) Receipt of disability benefits establishes unfitness --- + +- name: Case 17, SSDI recipient without the generic disability flag is exempt. + period: 2026-01 + input: + age: 30 + is_disabled: false + social_security_disability: 12_000 + output: + is_snap_work_registration_exempt_non_age: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.yaml index bc0b8092210..0fd32a1bee3 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.yaml @@ -225,3 +225,18 @@ output: # Participation is affirmative compliance under 7 CFR 273.7(a)(1)(ii). meets_snap_general_work_requirements: true + +# Receipt of disability benefits establishes unfitness for employment under +# 7 CFR 273.7(b)(1)(ii), so the exemption applies even when the generic +# disability flag is off and the person is flagged noncompliant. +- name: Case 15, noncompliant 30-year-old receiving SSDI is exempt through benefit receipt. + period: 2022 + input: + age: 30 + weekly_hours_worked_before_lsr: 1 + is_disabled: false + is_incapable_of_self_care: false + social_security_disability: 12_000 + is_snap_work_registration_noncompliant: true + output: + meets_snap_general_work_requirements: true From e5433454d10b05f92023657b8dd667a6df7ddae7 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 3 Sep 2026 12:35:37 -0400 Subject: [PATCH 4/6] Drop the SGA screen from the SSI student exclusion and count any-month SSI receipt for SNAP - The student earned income exclusion now gates on meets_ssi_disability_criteria rather than is_ssi_disabled. The SGA screen is an initial-entitlement test, and section 1619(a) recipients keep SSI status above SGA; the exclusion also feeds MSP, Medicaid, and state supplement income methodologies that have no SGA test, so it must not vanish above the threshold. - is_usda_disabled reads monthly booleans with the ADD option so reported SSI receipt in any month qualifies for the year, matching how monthly amounts are annualized. SSI receipt reflects an SSA aged/blind/disabled determination that does not lapse month to month. Co-Authored-By: Claude Fable 5.1 --- ...led_working_student_exclusion_eligible.yaml | 12 ++++++++++++ ...abled_working_student_exclusion_eligible.py | 12 ++++++++---- .../variables/gov/usda/is_usda_disabled.py | 18 ++++++++++++++++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml index b9141ab911d..a5997cc63d4 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml @@ -38,3 +38,15 @@ is_full_time_student: true output: is_ssi_blind_or_disabled_working_student_exclusion_eligible: true + +- name: Eligible student earning above the SGA threshold keeps the exclusion + period: 2026 + input: + is_blind: false + is_disabled: false + meets_ssi_disability_criteria: true + employment_income: 30_000 + age: 20 + is_full_time_student: true + output: + is_ssi_blind_or_disabled_working_student_exclusion_eligible: true diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py index 8bb86905864..8ad1ac7e7bf 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py @@ -15,11 +15,15 @@ def formula(person, period, parameters): ).gov.ssa.ssi.income.exclusions.blind_or_disabled_working_student # "Blind or disabled" takes SSA's own meaning here: the exclusion # applies to a blind or disabled SSI claimant (20 CFR 416.1112(c)(3)), - # so the SSI disability test (SSI criteria and not engaged in SGA) - # governs rather than the generic disability flag. + # so the SSI disability criteria govern rather than the generic + # disability flag. The substantial gainful activity screen is left + # out: it is an initial-entitlement test, and section 1619(a) + # recipients keep SSI status while earning above SGA, so the + # exclusion (also used by MSP and Medicaid income methodologies) + # must not vanish above the SGA threshold. is_blind = person("is_blind", period) - is_ssi_disabled = person("is_ssi_disabled", period) - demographic_eligible = is_blind | is_ssi_disabled + meets_disability_criteria = person("meets_ssi_disability_criteria", period) + demographic_eligible = is_blind | meets_disability_criteria under_age_limit = person("age", period) < p.age_limit eligible_student = under_age_limit & person("is_full_time_student", period) return eligible_student & demographic_eligible diff --git a/policyengine_us/variables/gov/usda/is_usda_disabled.py b/policyengine_us/variables/gov/usda/is_usda_disabled.py index d666406e96b..5adeea2ac72 100644 --- a/policyengine_us/variables/gov/usda/is_usda_disabled.py +++ b/policyengine_us/variables/gov/usda/is_usda_disabled.py @@ -8,10 +8,24 @@ class is_usda_disabled(Variable): documentation = ( "Meets the benefit-receipt half of the SNAP 'elderly or disabled " "member' definition (7 CFR 271.2), which counts any SSI receipt, " - "whether based on age, blindness, or disability." + "whether based on age, blindness, or disability. SSI is paid only " + "after SSA has determined the person is aged, blind, or disabled " + "under section 1614, and that determination does not lapse month to " + "month, so receipt in any month of the year qualifies for the year." ) label = "USDA disabled status" def formula(person, period, parameters): programs = parameters(period).gov.usda.disabled_programs - return np.logical_or.reduce([person(program, period) for program in programs]) + variables = person.simulation.tax_benefit_system.variables + + def received(program): + variable = variables[program] + # Monthly booleans are stocks, which Core reads at December when + # requested for a year. Sum the months instead so receipt in any + # month qualifies, matching how monthly amounts are annualized. + if variable.definition_period == MONTH and variable.value_type == bool: + return person(program, period, options=[ADD]) > 0 + return person(program, period) + + return np.logical_or.reduce([received(program) for program in programs]) From e998515b759078c8c70e6a9d38dd9db719ca1393 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 3 Sep 2026 12:48:02 -0400 Subject: [PATCH 5/6] Use Core's default period handling in is_usda_disabled Drop the month-summing special case for monthly booleans. Core's default resolution applies: monthly amounts are summed over the year and monthly booleans are read as stocks. This also removes the ADD-option path that crashed Microsimulation.calculate_add. Co-Authored-By: Claude Fable 5.1 --- .../variables/gov/usda/is_usda_disabled.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/policyengine_us/variables/gov/usda/is_usda_disabled.py b/policyengine_us/variables/gov/usda/is_usda_disabled.py index 5adeea2ac72..d666406e96b 100644 --- a/policyengine_us/variables/gov/usda/is_usda_disabled.py +++ b/policyengine_us/variables/gov/usda/is_usda_disabled.py @@ -8,24 +8,10 @@ class is_usda_disabled(Variable): documentation = ( "Meets the benefit-receipt half of the SNAP 'elderly or disabled " "member' definition (7 CFR 271.2), which counts any SSI receipt, " - "whether based on age, blindness, or disability. SSI is paid only " - "after SSA has determined the person is aged, blind, or disabled " - "under section 1614, and that determination does not lapse month to " - "month, so receipt in any month of the year qualifies for the year." + "whether based on age, blindness, or disability." ) label = "USDA disabled status" def formula(person, period, parameters): programs = parameters(period).gov.usda.disabled_programs - variables = person.simulation.tax_benefit_system.variables - - def received(program): - variable = variables[program] - # Monthly booleans are stocks, which Core reads at December when - # requested for a year. Sum the months instead so receipt in any - # month qualifies, matching how monthly amounts are annualized. - if variable.definition_period == MONTH and variable.value_type == bool: - return person(program, period, options=[ADD]) > 0 - return person(program, period) - - return np.logical_or.reduce([received(program) for program in programs]) + return np.logical_or.reduce([person(program, period) for program in programs]) From 857d7c76e5074961cce13bb04462f84fb6b263ee Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 4 Sep 2026 21:30:12 -0400 Subject: [PATCH 6/6] Address review: citations, references, add idiom, and edge tests - Cite 42 U.S.C. 1382c(a)(3) for the blind-or-disabled precondition of the SSI student exclusion; 20 CFR 416.1112(c)(3) sets only age and student. - Repoint the receipt-establishes-unfitness rule to 7 CFR 273.24(c)(2)(i), applied by analogy to the 273.7(b)(1)(ii) exemption, in the SNAP work registration, general work requirement, and student rules. - Add the new authorities to reference attributes (Medicaid work requirement, HUD dependent, HUD elderly/disabled family, SNAP student). - Use the add(...) > 0 idiom in is_usda_disabled and add its reference. - Note that SSDI receipt is a modeling proxy for the HUD section 223 test. - Spell out SNAP in the disabled_programs description. - Tests: SSI-receipt leg on the four SNAP gates, zero-SSDI negative controls on both HUD variables, a non-triggering home equity case, and a non-disabled above-SGA mirror for the student exclusion. Co-Authored-By: Claude Fable 5.1 --- .../gov/usda/disabled_programs.yaml | 3 +- ...d_long_term_care_home_equity_eligible.yaml | 30 +++++++++++++++++++ .../baseline/gov/hud/is_hud_dependent.yaml | 22 ++++++++++++++ .../gov/hud/is_hud_elderly_disabled.yaml | 9 ++++++ ...ed_working_student_exclusion_eligible.yaml | 12 ++++++++ .../student/is_snap_ineligible_student.yaml | 12 ++++++++ .../is_snap_abawd_exempt.yaml | 18 +++++++++++ ...snap_work_registration_exempt_non_age.yaml | 9 ++++++ .../meets_snap_general_work_requirements.yaml | 12 ++++++++ .../medicaid_work_requirement_eligible.py | 1 + .../gov/hud/income/is_hud_dependent.py | 9 ++++-- .../gov/hud/is_hud_elderly_disabled_family.py | 9 ++++-- ...bled_working_student_exclusion_eligible.py | 15 ++++++---- .../variables/gov/usda/is_usda_disabled.py | 7 ++++- .../student/is_snap_ineligible_student.py | 10 +++++-- ...s_snap_work_registration_exempt_non_age.py | 10 ++++--- .../meets_snap_general_work_requirements.py | 10 ++++--- 17 files changed, 176 insertions(+), 22 deletions(-) diff --git a/policyengine_us/parameters/gov/usda/disabled_programs.yaml b/policyengine_us/parameters/gov/usda/disabled_programs.yaml index 1beb12367b8..cb417554b43 100644 --- a/policyengine_us/parameters/gov/usda/disabled_programs.yaml +++ b/policyengine_us/parameters/gov/usda/disabled_programs.yaml @@ -1,10 +1,11 @@ -description: Benefit receipt that qualifies individuals as elderly or disabled members for SNAP. +description: Benefit receipt that qualifies individuals as elderly or disabled members under the Supplemental Nutrition Assistance Program. values: 2021-01-01: # 7 CFR 271.2 defines "elderly or disabled member" by benefit receipt # ("receives supplemental security income benefits ... or disability or # blindness payments"), not by meeting the disability criteria alone. + # Amount entries (ssi, social_security_disability) count when positive. - receives_ssi - ssi - social_security_disability diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/is_medicaid_long_term_care_home_equity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/is_medicaid_long_term_care_home_equity_eligible.yaml index c625460938e..aeb4936abee 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/is_medicaid_long_term_care_home_equity_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/is_medicaid_long_term_care_home_equity_eligible.yaml @@ -325,3 +325,33 @@ output: medicaid_home_equity_limit_family_exception: [true, false] is_medicaid_long_term_care_home_equity_eligible: [true, true] + +- name: Case 20, resident adult child not meeting the SSI disability test does not trigger the family exception. + period: 2028 + input: + people: + person1: + age: 65 + receives_medicaid_long_term_care_services: true + home_equity: 1_000_001 + person2: + age: 30 + is_disabled: false + is_ssi_disabled: false + is_related_to_head_or_spouse: true + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + output: + medicaid_home_equity_limit_family_exception: [false, false] + is_medicaid_long_term_care_home_equity_eligible: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/hud/is_hud_dependent.yaml b/policyengine_us/tests/policy/baseline/gov/hud/is_hud_dependent.yaml index a344d28992b..ba9d34cb4e4 100644 --- a/policyengine_us/tests/policy/baseline/gov/hud/is_hud_dependent.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hud/is_hud_dependent.yaml @@ -171,3 +171,25 @@ members: [head, person] output: is_hud_dependent: [false, true] + +- name: A non-head adult with zero SSDI and no other disability status is not a HUD dependent. + period: 2022 + input: + people: + head: + age: 45 + is_household_head: true + person: + age: 40 + is_disabled: false + social_security_disability: 0 + tax_units: + tax_unit1: + members: [head] + tax_unit2: + members: [person] + spm_units: + spm_unit: + members: [head, person] + output: + is_hud_dependent: [false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/hud/is_hud_elderly_disabled.yaml b/policyengine_us/tests/policy/baseline/gov/hud/is_hud_elderly_disabled.yaml index 1b1568f3b54..9079167bc8c 100644 --- a/policyengine_us/tests/policy/baseline/gov/hud/is_hud_elderly_disabled.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hud/is_hud_elderly_disabled.yaml @@ -83,3 +83,12 @@ social_security_disability: 12_000 output: is_hud_elderly_disabled_family: true + +- name: A one-person non-elderly family with zero SSDI and no other disability status. + period: 2022 + input: + age: 48 + is_disabled: false + social_security_disability: 0 + output: + is_hud_elderly_disabled_family: false diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml index a5997cc63d4..8cf9f0fea12 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.yaml @@ -50,3 +50,15 @@ is_full_time_student: true output: is_ssi_blind_or_disabled_working_student_exclusion_eligible: true + +- name: Non-disabled student earning above the SGA threshold never qualifies + period: 2026 + input: + is_blind: false + is_disabled: false + meets_ssi_disability_criteria: false + employment_income: 30_000 + age: 20 + is_full_time_student: true + output: + is_ssi_blind_or_disabled_working_student_exclusion_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/is_snap_ineligible_student.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/is_snap_ineligible_student.yaml index 6d7bd4a6b92..c2ffc58d56a 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/is_snap_ineligible_student.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/is_snap_ineligible_student.yaml @@ -200,3 +200,15 @@ social_security_disability: 12_000 output: is_snap_ineligible_student: false + +- name: College student reported to receive SSI meets the disability exception without the generic disability flag + period: 2022 + input: + is_full_time_college_student: true + age: 25 + is_disabled: false + weekly_hours_worked_before_lsr: 0 + is_parent: false + receives_ssi: true + output: + is_snap_ineligible_student: false diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.yaml index 1ad3bb18737..1feb166d08a 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_abawd_exempt.yaml @@ -286,3 +286,21 @@ state_code: TX output: is_snap_abawd_exempt: true + +- name: Case 17, reported SSI recipient without the generic disability flag is exempt. + period: 2026-01 + input: + people: + person1: + age: 30 + is_disabled: false + receives_ssi: true + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + is_snap_abawd_exempt: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml index 784b1593f2d..55c8ad03b5e 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml @@ -229,3 +229,12 @@ social_security_disability: 12_000 output: is_snap_work_registration_exempt_non_age: true + +- name: Case 18, reported SSI recipient without the generic disability flag is exempt. + period: 2026-01 + input: + age: 30 + is_disabled: false + receives_ssi: true + output: + is_snap_work_registration_exempt_non_age: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.yaml index 0fd32a1bee3..31acef50f0d 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.yaml @@ -240,3 +240,15 @@ is_snap_work_registration_noncompliant: true output: meets_snap_general_work_requirements: true + +- name: Case 16, noncompliant 30-year-old with an SSI amount is exempt through benefit receipt. + period: 2022 + input: + age: 30 + weekly_hours_worked_before_lsr: 1 + is_disabled: false + is_incapable_of_self_care: false + ssi: 6_000 + is_snap_work_registration_noncompliant: true + output: + meets_snap_general_work_requirements: true diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py index 3640bea0bb9..153c5276120 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_work_requirement_eligible.py @@ -9,6 +9,7 @@ class medicaid_work_requirement_eligible(Variable): reference = ( "https://www.congress.gov/bill/119th-congress/house-bill/1/text", "https://www.medicaid.gov/federal-policy-guidance/downloads/cib12082025.pdf", + "https://www.law.cornell.edu/uscode/text/42/1382c#a_3", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/hud/income/is_hud_dependent.py b/policyengine_us/variables/gov/hud/income/is_hud_dependent.py index 2b7768b1daa..a6806d08d13 100644 --- a/policyengine_us/variables/gov/hud/income/is_hud_dependent.py +++ b/policyengine_us/variables/gov/hud/income/is_hud_dependent.py @@ -6,7 +6,10 @@ class is_hud_dependent(Variable): entity = Person label = "HUD dependent" definition_period = YEAR - reference = "https://www.law.cornell.edu/cfr/text/24/5.603" + reference = ( + "https://www.law.cornell.edu/cfr/text/24/5.603", + "https://www.law.cornell.edu/uscode/text/42/1437a#b_3_E", + ) def formula(person, period, parameters): is_household_head = person("is_household_head", period) @@ -25,7 +28,9 @@ def formula(person, period, parameters): is_hud_head_or_spouse = is_head | is_head_spouse # The "person with disabilities" definition (42 U.S.C. 1437a(b)(3)(E)) # includes the section 223 SSA disability standard, so the SSI/SSDI - # paths qualify alongside the generic disability flag. + # paths qualify alongside the generic disability flag. SSDI receipt + # is a modeling proxy for the section 223 definition: the statute + # turns on the impairment, not on receipt. meets_dependent_condition = ( person("is_child", period) | person("is_disabled", period) diff --git a/policyengine_us/variables/gov/hud/is_hud_elderly_disabled_family.py b/policyengine_us/variables/gov/hud/is_hud_elderly_disabled_family.py index 222c39ea1e6..bbb0e13f029 100644 --- a/policyengine_us/variables/gov/hud/is_hud_elderly_disabled_family.py +++ b/policyengine_us/variables/gov/hud/is_hud_elderly_disabled_family.py @@ -7,7 +7,10 @@ class is_hud_elderly_disabled_family(Variable): label = "HUD elderly or disabled family" documentation = "Whether an SPM unit is deemed elderly or disabled for HUD purposes" definition_period = YEAR - reference = "https://www.law.cornell.edu/cfr/text/24/5.611" + reference = ( + "https://www.law.cornell.edu/cfr/text/24/5.611", + "https://www.law.cornell.edu/uscode/text/42/1437a#b_3_E", + ) def formula(spm_unit, period, parameters): hud = parameters(period).gov.hud @@ -16,7 +19,9 @@ def formula(spm_unit, period, parameters): # 42 U.S.C. 1437a(b)(3)(E) defines a person with disabilities to # include anyone with a disability as defined in section 223 of the # Social Security Act (the SSDI standard), so the SSI/SSDI paths - # qualify alongside the generic disability flag. + # qualify alongside the generic disability flag. SSDI receipt is a + # modeling proxy for the section 223 definition: the statute turns + # on the impairment, not on receipt. disabled = ( person("is_disabled", period) | person("is_ssi_disabled", period) diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py index 8ad1ac7e7bf..41e0d875d32 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/is_ssi_blind_or_disabled_working_student_exclusion_eligible.py @@ -7,16 +7,21 @@ class is_ssi_blind_or_disabled_working_student_exclusion_eligible(Variable): label = "Eligible for SSI blind or disabled working student earned income exclusion" unit = USD definition_period = YEAR - reference = "https://www.law.cornell.edu/cfr/text/20/416.1112#c_3" + reference = ( + "https://www.law.cornell.edu/cfr/text/20/416.1112#c_3", + "https://www.law.cornell.edu/uscode/text/42/1382c#a_3", + ) def formula(person, period, parameters): p = parameters( period ).gov.ssa.ssi.income.exclusions.blind_or_disabled_working_student - # "Blind or disabled" takes SSA's own meaning here: the exclusion - # applies to a blind or disabled SSI claimant (20 CFR 416.1112(c)(3)), - # so the SSI disability criteria govern rather than the generic - # disability flag. The substantial gainful activity screen is left + # 20 CFR 416.1112(c)(3) itself sets only the age and student + # conditions; the blind-or-disabled precondition comes from the + # enclosing SSI context, where "blind or disabled" carries the + # section 1614 meaning (42 U.S.C. 1382c(a)(2)-(3)). So the SSI + # disability criteria govern rather than the generic disability + # flag. The substantial gainful activity screen is left # out: it is an initial-entitlement test, and section 1619(a) # recipients keep SSI status while earning above SGA, so the # exclusion (also used by MSP and Medicaid income methodologies) diff --git a/policyengine_us/variables/gov/usda/is_usda_disabled.py b/policyengine_us/variables/gov/usda/is_usda_disabled.py index d666406e96b..f332da428ef 100644 --- a/policyengine_us/variables/gov/usda/is_usda_disabled.py +++ b/policyengine_us/variables/gov/usda/is_usda_disabled.py @@ -11,7 +11,12 @@ class is_usda_disabled(Variable): "whether based on age, blindness, or disability." ) label = "USDA disabled status" + reference = "https://www.law.cornell.edu/cfr/text/7/271.2" def formula(person, period, parameters): programs = parameters(period).gov.usda.disabled_programs - return np.logical_or.reduce([person(program, period) for program in programs]) + # Each entry is truthiness-tested: boolean flags count when true, + # and amount entries (ssi, social_security_disability) count when + # positive over the period. + received = [add(person, period, [program]) > 0 for program in programs] + return np.logical_or.reduce(received) diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/student/is_snap_ineligible_student.py b/policyengine_us/variables/gov/usda/snap/eligibility/student/is_snap_ineligible_student.py index f81de6bd8fc..aa6f8fa564a 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/student/is_snap_ineligible_student.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/student/is_snap_ineligible_student.py @@ -7,7 +7,10 @@ class is_snap_ineligible_student(Variable): label = "Is an ineligible student for SNAP" definition_period = YEAR defined_for = "is_snap_higher_ed_student" - reference = "https://www.law.cornell.edu/uscode/text/7/2015#e" + reference = ( + "https://www.law.cornell.edu/uscode/text/7/2015#e", + "https://www.law.cornell.edu/cfr/text/7/273.24#c_2", + ) def formula(person, period, parameters): # Base rule: Students enrolled at least half-time in higher education @@ -23,8 +26,9 @@ def formula(person, period, parameters): # would make the ~ below a bitwise negation instead of a logical one. meets_age_exception = p.age_threshold.calc(age).astype(bool) - # Exception 2: Not physically or mentally fit (disabled); receipt of - # disability benefits establishes unfitness (7 CFR 273.7(b)(1)(ii)), + # Exception 2: Not physically or mentally fit (disabled). 7 CFR + # 273.24(c)(2)(i) treats receipt of disability benefits as + # establishing unfitness for employment, applied here by analogy, # so the USDA receipt-based definition also qualifies. meets_disability_exception = person("is_disabled", period) | person( "is_usda_disabled", period diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py index 4a4dc082a4e..aa55ab563ca 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py @@ -8,6 +8,7 @@ class is_snap_work_registration_exempt_non_age(Variable): definition_period = MONTH reference = ( "https://www.law.cornell.edu/cfr/text/7/273.7#b_1", + "https://www.law.cornell.edu/cfr/text/7/273.24#c_2", "https://www.law.cornell.edu/uscode/text/7/2015#o_3", ) @@ -15,10 +16,11 @@ def formula(person, period, parameters): p = parameters(period).gov.usda.snap.work_requirements.general # Age-based exemptions under (b)(1)(i) are handled in the # age-based work registration exemption logic. - # (ii) Physically or mentally unfit for employment; per 7 CFR - # 273.7(b)(1)(ii), receipt of temporary or permanent disability - # benefits establishes unfitness, so the USDA receipt-based - # definition also exempts. + # (ii) Physically or mentally unfit for employment. 7 CFR + # 273.7(b)(1)(ii) leaves the unfitness determination to the State + # agency; 7 CFR 273.24(c)(2)(i) treats receipt of temporary or + # permanent disability benefits as establishing unfitness, applied + # here by analogy, so the USDA receipt-based definition also exempts. is_disabled = person("is_disabled", period) | person( "is_usda_disabled", period.this_year ) diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.py b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.py index 5285ad3f66d..08237ee01ba 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/meets_snap_general_work_requirements.py @@ -24,6 +24,7 @@ class meets_snap_general_work_requirements(Variable): "https://www.law.cornell.edu/cfr/text/7/273.7#a_1", "https://www.law.cornell.edu/cfr/text/7/273.7#b_1", "https://www.law.cornell.edu/cfr/text/7/273.7#f_1", + "https://www.law.cornell.edu/cfr/text/7/273.24#c_2", "https://www.law.cornell.edu/cfr/text/7/273.7#j", ) @@ -37,10 +38,11 @@ def formula(person, period, parameters): # Exemptions under 7 CFR 273.7(b)(1): # Under 16 or 60 years of age or older are exempted worked_exempted_age = p.age_threshold.exempted.calc(age) - # Unable to work due to a physical or mental limitation; per 7 CFR - # 273.7(b)(1)(ii), receipt of temporary or permanent disability - # benefits establishes unfitness, so the USDA receipt-based - # definition also exempts. + # Unable to work due to a physical or mental limitation. 7 CFR + # 273.7(b)(1)(ii) leaves the unfitness determination to the State + # agency; 7 CFR 273.24(c)(2)(i) treats receipt of temporary or + # permanent disability benefits as establishing unfitness, applied + # here by analogy, so the USDA receipt-based definition also exempts. is_disabled = person("is_disabled", period) | person( "is_usda_disabled", period.this_year )