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..cb417554b43 100644 --- a/policyengine_us/parameters/gov/usda/disabled_programs.yaml +++ b/policyengine_us/parameters/gov/usda/disabled_programs.yaml @@ -1,8 +1,13 @@ -description: Program participation that qualify individuals as disabled under USDA rules +description: Benefit receipt that qualifies individuals as elderly or disabled members under the Supplemental Nutrition Assistance Program. 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. + # Amount entries (ssi, social_security_disability) count when positive. + - receives_ssi + - ssi - social_security_disability - is_permanently_disabled_veteran - is_surviving_spouse_of_disabled_veteran @@ -12,3 +17,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/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..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 @@ -295,3 +295,63 @@ 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] + +- 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/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..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 @@ -127,3 +127,69 @@ # 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] + +- 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 ee08315c6a3..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 @@ -63,3 +63,32 @@ 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 + +- 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 df6bfbfee5f..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 @@ -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 @@ -38,3 +38,27 @@ 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 + +- 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/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 e11b3d35767..13f86c3bcfb 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 @@ -282,3 +282,27 @@ state_code: MO output: is_snap_ineligible_student: [false, true, false] + +- name: Case 18, 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 + +- name: Case 19, 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/student/meets_snap_non_parent_student_exception.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/meets_snap_non_parent_student_exception.yaml index 29dd00bf7fe..a78c3fef326 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/meets_snap_non_parent_student_exception.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/student/meets_snap_non_parent_student_exception.yaml @@ -48,3 +48,25 @@ tanf_person: 500 output: meets_snap_non_parent_student_exception: true + +- name: Student receiving SSDI meets the disability exception without the generic disability flag + period: 2024 + input: + is_full_time_college_student: true + age: 25 + is_disabled: false + weekly_hours_worked_before_lsr: 0 + social_security_disability: 12_000 + output: + meets_snap_non_parent_student_exception: true + +- name: Student reported to receive SSI meets the disability exception without the generic disability flag + period: 2024 + input: + is_full_time_college_student: true + age: 25 + is_disabled: false + weekly_hours_worked_before_lsr: 0 + receives_ssi: true + output: + meets_snap_non_parent_student_exception: true 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..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 @@ -266,3 +266,41 @@ 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 + +- 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 1568ec2e479..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 @@ -218,3 +218,23 @@ 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 + +- 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 bc0b8092210..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 @@ -225,3 +225,30 @@ 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 + +- 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_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..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): @@ -72,7 +73,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..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) @@ -23,9 +26,16 @@ 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. 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) + | 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..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 @@ -5,16 +5,28 @@ 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" + 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 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. 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) + | (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..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,15 +7,28 @@ 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 + # 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) + # must not vanish above the SGA threshold. is_blind = person("is_blind", period) - is_disabled = person("is_disabled", period) - demographic_eligible = is_blind | is_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 eaf15235460..f332da428ef 100644 --- a/policyengine_us/variables/gov/usda/is_usda_disabled.py +++ b/policyengine_us/variables/gov/usda/is_usda_disabled.py @@ -5,9 +5,18 @@ 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" + 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/meets_snap_non_parent_student_exception.py b/policyengine_us/variables/gov/usda/snap/eligibility/student/meets_snap_non_parent_student_exception.py index 4385cdba3ae..fec1317babb 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/student/meets_snap_non_parent_student_exception.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/student/meets_snap_non_parent_student_exception.py @@ -10,6 +10,7 @@ class meets_snap_non_parent_student_exception(Variable): reference = ( "https://www.law.cornell.edu/uscode/text/7/2015#e", "https://www.law.cornell.edu/cfr/text/7/273.5#b", + "https://www.law.cornell.edu/cfr/text/7/273.24#c_2", ) def formula(person, period, parameters): @@ -20,8 +21,13 @@ def formula(person, period, parameters): # would make a later ~ 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). 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 + ) # 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..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,8 +16,14 @@ 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. 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 + ) # (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..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,8 +38,14 @@ 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. 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 + ) # 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