diff --git a/changelog.d/hub-pb-snap-heat-eat-1009.fixed.md b/changelog.d/hub-pb-snap-heat-eat-1009.fixed.md new file mode 100644 index 00000000000..74cb41e2fbc --- /dev/null +++ b/changelog.d/hub-pb-snap-heat-eat-1009.fixed.md @@ -0,0 +1 @@ +Restrict SNAP heat-and-eat standard utility allowances to households with an elderly or disabled SNAP member under P.L. 119-21, while preserving eligibility based on actual heating or cooling expenses. diff --git a/policyengine_us/parameters/gov/usda/snap/income/deductions/utility/heat_and_eat_requires_elderly_disabled.yaml b/policyengine_us/parameters/gov/usda/snap/income/deductions/utility/heat_and_eat_requires_elderly_disabled.yaml new file mode 100644 index 00000000000..d366ab61aee --- /dev/null +++ b/policyengine_us/parameters/gov/usda/snap/income/deductions/utility/heat_and_eat_requires_elderly_disabled.yaml @@ -0,0 +1,19 @@ +description: The Department of Agriculture requires an elderly or disabled SNAP household member for heating and cooling standard utility allowance eligibility based on energy assistance under the Supplemental Nutrition Assistance Program. + +# Section 10103 took effect upon enactment on July 4, 2025. Monthly SNAP +# formulas evaluate policy at month start, so August 2025 is the first full +# affected model month. Individual certification/recertification dates and +# state administrative implementation dates are not modeled here. +values: + 0000-01-01: false + 2025-07-04: true + +metadata: + unit: bool + period: month + label: SNAP heat-and-eat SUA elderly or disabled requirement + reference: + - title: 7 U.S.C. 2014(e)(6)(C)(iv)(I) - Availability of allowance to recipients of energy assistance + href: https://www.law.cornell.edu/uscode/text/7/2014#e_6_C_iv_I + - title: Public Law 119-21, Section 10103(a) - Standard Utility Allowance + href: https://www.govinfo.gov/content/pkg/PLAW-119publ21/html/PLAW-119publ21.htm diff --git a/policyengine_us/tests/core/test_snap_heat_and_eat.py b/policyengine_us/tests/core/test_snap_heat_and_eat.py new file mode 100644 index 00000000000..23c6b672e67 --- /dev/null +++ b/policyengine_us/tests/core/test_snap_heat_and_eat.py @@ -0,0 +1,17 @@ +"""Check the legal-day boundary that monthly policy YAML cannot express.""" + +from pathlib import Path + +from policyengine_core.parameters import load_parameter_file + + +def test_heat_and_eat_requirement_takes_effect_on_enactment_date(): + requirement = load_parameter_file( + str( + Path(__file__).resolve().parents[2] + / "parameters/gov/usda/snap/income/deductions/utility" + / "heat_and_eat_requires_elderly_disabled.yaml" + ) + ) + assert requirement("2025-07-03") is False + assert requirement("2025-07-04") is True diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/immigration/integration.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/immigration/integration.yaml index 8a4973b49ee..8ff88c98a85 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/immigration/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/immigration/integration.yaml @@ -130,15 +130,18 @@ snap_earned_income: 1_333.33 snap_earned_income_deduction: 266.67 snap_standard_deduction: 209 - # Massachusetts standard utility allowance $914 - 50% of the $857.67 - # net income before the shelter deduction ($428.83) = $485.17. - snap_utility_allowance: 914 - snap_excess_shelter_expense_deduction: 485.17 - # $857.67 - $485.17 = $372.50, rounded to $373. - snap_net_income: 373 - # 30% of $373 = $111.90, rounded up to $112; $546 - $112 = $434. - snap_expected_contribution: 112 - snap: 434 + # No utility costs or elderly/disabled member: no actual-cost SUA or + # Massachusetts H-EAT SUA under P.L. 119-21 section 10103(a). + # https://www.govinfo.gov/content/pkg/PLAW-119publ21/html/PLAW-119publ21.htm + # https://dtapolicyguide.qa.eohhs.mass.gov/SNAP/ExpensesDeductions/HEAT.htm + snap_utility_allowance: 0 + # No housing costs or SUA, so there is no excess shelter deduction. + snap_excess_shelter_expense_deduction: 0 + # $1,333.33 - $266.67 - $209 = $857.67, rounded to $858. + snap_net_income: 858 + # 30% of $858 = $257.40, rounded up to $258; $546 - $258 = $288. + snap_expected_contribution: 258 + snap: 288 - name: Case 4, LPR earner inside the waiting period is prorated under both tests in a hybrid gross-test state. period: 2026-01 diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/heat_and_eat/snap.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/heat_and_eat/snap.yaml new file mode 100644 index 00000000000..9da9145379e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/heat_and_eat/snap.yaml @@ -0,0 +1,122 @@ +# PolicyBench snapshot facts and takeup defaults. Leaf input aliases mirror +# the US Simulation adapter, which Core's YAML SimulationBuilder bypasses. +- name: Case 1, PolicyBench scenario_080 PA household receives SNAP without the heat-and-eat SUA. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 41 + employment_income_before_lsr: 0 + bank_account_assets: 19_827.646484375 + financial_assistance: 3_600 + is_disabled: true + is_tax_unit_head: true + is_tax_unit_spouse: false + long_term_capital_gains_before_response: 924 + other_medical_expenses: 12 + over_the_counter_health_expenses: 100 + qualified_dividend_income: 16 + takes_up_medicaid_if_eligible: true + takes_up_ssi_if_eligible: true + marital_units: + marital_unit_1: + members: [person1] + tax_units: + tax_unit: + members: [person1] + first_home_mortgage_balance: 93_000 + takes_up_aca_if_eligible: true + takes_up_dc_ptc: true + takes_up_eitc: true + would_file_if_eligible_for_refundable_credit: true + would_file_taxes_voluntarily: true + spm_units: + spm_unit: + members: [person1] + spm_unit_energy_subsidy: 2_000 + takes_up_snap_if_eligible: true + families: + family: + members: [person1] + households: + household: + members: [person1] + state_code: PA + household_vehicles_value: 3_570 + output: + snap: 3_270 + +- name: Case 2, PolicyBench scenario_100 MT household receives SNAP without the heat-and-eat SUA. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 46 + employment_income_before_lsr: 5_914.720703125 + bank_account_assets: 2_800 + employer_sponsored_insurance_premiums: 20_643.525390625 + fsla_overtime_premium: 709.7664794921875 + has_esi: true + health_insurance_premiums_without_medicare_part_b: 564 + hourly_wage: 2.319999933242798 + hours_worked_last_week: 55 + is_disabled: true + is_tax_unit_head: true + is_tax_unit_spouse: false + other_health_insurance_premiums: 564 + other_medical_expenses: 500 + over_the_counter_health_expenses: 480 + roth_401k_contributions_desired: 681 + roth_ira_contributions_desired: 279.67999267578125 + traditional_401k_contributions_desired: 3_859 + traditional_ira_contributions_desired: 180.32000732421875 + weekly_hours_worked_before_lsr: 55 + takes_up_medicaid_if_eligible: true + takes_up_ssi_if_eligible: true + person2: + age: 6 + employment_income_before_lsr: 0 + has_esi: true + is_tax_unit_head: false + is_tax_unit_spouse: false + takes_up_medicaid_if_eligible: true + takes_up_ssi_if_eligible: true + person3: + age: 5 + employment_income_before_lsr: 0 + is_tax_unit_head: false + is_tax_unit_spouse: false + other_medical_expenses: 500 + takes_up_medicaid_if_eligible: true + takes_up_ssi_if_eligible: true + marital_units: + marital_unit_1: + members: [person1] + marital_unit_2: + members: [person2] + marital_unit_3: + members: [person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + takes_up_aca_if_eligible: true + takes_up_dc_ptc: true + takes_up_eitc: true + would_file_if_eligible_for_refundable_credit: true + would_file_taxes_voluntarily: true + spm_units: + spm_unit: + members: [person1, person2, person3] + takes_up_snap_if_eligible: true + families: + family: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + household_vehicles_value: 1_980.88232421875 + output: + snap: 7_002 diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/heat_and_eat/snap_utility_allowance_type.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/heat_and_eat/snap_utility_allowance_type.yaml new file mode 100644 index 00000000000..5508245ea88 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/heat_and_eat/snap_utility_allowance_type.yaml @@ -0,0 +1,250 @@ +# P.L. 119-21 section 10103(a) and the August 29, 2025 FNS memo. +# SNAP evaluates monthly policy at month start: the July 4 change first +# applies to the full benefit month beginning August 1, 2025. +- name: Pennsylvania heat-and-eat eligibility changes after enactment + period: 2025 + input: + age: 40 + state_code: PA + output: + snap_state_using_standard_utility_allowance: true + snap_utility_allowance_type: + 2025-06: SUA + 2025-07: SUA + 2025-08: NONE + +- name: Pennsylvania adult without qualifying utility costs loses deemed SUA + period: 2026 + input: + age: 40 + weekly_hours_worked_before_lsr: 30 + state_code: PA + output: + snap_utility_allowance_type: NONE + snap_utility_allowance: 0 + +- name: Montana adult without qualifying utility costs loses deemed SUA + period: 2026 + input: + age: 40 + state_code: MT + output: + snap_utility_allowance_type: NONE + snap_utility_allowance: 0 + +- name: California adult without qualifying utility costs loses deemed SUA + period: 2026 + input: + age: 40 + state_code: CA + output: + snap_utility_allowance_type: NONE + snap_utility_allowance: 0 + +- name: The federal restriction continues after 2026 + period: 2027 + input: + age: 40 + state_code: PA + output: + snap_utility_allowance_type: NONE + +- name: Age 59 does not qualify for the elderly exception + period: 2026 + input: + age: 59 + weekly_hours_worked_before_lsr: 30 + state_code: PA + output: + has_snap_elderly_disabled_member: false + snap_utility_allowance_type: NONE + +- name: Age 60 preserves the heat-and-eat SUA + period: 2026 + input: + age: 60 + weekly_hours_worked_before_lsr: 30 + state_code: PA + output: + has_snap_elderly_disabled_member: true + snap_utility_allowance_type: SUA + +- name: SSDI receipt preserves the heat-and-eat SUA below age 60 + period: 2026 + input: + age: 40 + social_security_disability: 1_200 + state_code: MT + output: + has_snap_elderly_disabled_member: true + snap_utility_allowance_type: SUA + snap_utility_allowance: + 2026-01: 799 + +- name: General disability alone does not meet the USDA definition + period: 2026 + input: + age: 40 + is_disabled: true + state_code: PA + output: + has_snap_elderly_disabled_member: false + snap_utility_allowance_type: NONE + +- name: Actual heating costs independently preserve SUA eligibility + period: 2026 + input: + age: 40 + state_code: PA + heating_cooling_expense: 120 + output: + has_snap_elderly_disabled_member: false + snap_utility_allowance_type: SUA + snap_utility_allowance: + 2026-01: 857 + +- name: Two non-heating utility bills qualify for Pennsylvania LUA + period: 2026 + input: + age: 40 + state_code: PA + pre_subsidy_electricity_expense: 120 + water_expense: 120 + output: + snap_utility_allowance_type: LUA + +- name: A phone bill qualifies for California IUA + period: 2026 + input: + age: 40 + state_code: CA + phone_expense: 120 + output: + snap_utility_allowance_type: IUA + +- name: Elderly members do not create heat-and-eat eligibility in Texas + period: 2026 + input: + age: 60 + state_code: TX + output: + snap_state_using_standard_utility_allowance: false + snap_utility_allowance_type: NONE + +- name: SNAP-excluded elderly members do not confer the heat-and-eat exception + period: 2026 + input: + people: + adult: + age: 40 + weekly_hours_worked_before_lsr: 30 + excluded_elder: + age: 65 + immigration_status: UNDOCUMENTED + spm_units: + spm_unit: + members: [adult, excluded_elder] + households: + household: + members: [adult, excluded_elder] + state_code: PA + output: + has_usda_elderly_disabled: true + has_snap_elderly_disabled_member: false + snap_utility_allowance_type: NONE + +# Each adjacent pair has the same expenses, with state deeming enabled +# in the first household and disabled in its expense-only control. +# The YAML builder gives each person a separate SPM unit and household. +- name: Restricted heat-and-eat households match expense-only utility controls + period: 2026 + input: + age: + 2025: [40, 40, 40, 40, 40, 40, 40, 40] + 2026: [40, 40, 40, 40, 40, 40, 40, 40] + weekly_hours_worked_before_lsr: + 2025: [30, 30, 30, 30, 30, 30, 30, 30] + 2026: [30, 30, 30, 30, 30, 30, 30, 30] + state_code: + 2025: [PA, PA, PA, PA, PA, PA, MI, MI] + 2026: [PA, PA, PA, PA, PA, PA, MI, MI] + # No bills, phone only, PA electricity + water, MI electricity + water. + phone_expense: + 2025: [0, 0, 360, 360, 0, 0, 0, 0] + 2026: [0, 0, 360, 360, 0, 0, 0, 0] + pre_subsidy_electricity_expense: + 2025: [0, 0, 0, 0, 600, 600, 600, 600] + 2026: [0, 0, 0, 0, 600, 600, 600, 600] + water_expense: + 2025: [0, 0, 0, 0, 300, 300, 300, 300] + 2026: [0, 0, 0, 0, 300, 300, 300, 300] + # Full vectors preserve the state option in primary households. + snap_state_using_standard_utility_allowance: + 2025-08: [true, false, true, false, true, false, true, false] + 2026-01: [true, false, true, false, true, false, true, false] + output: + has_snap_elderly_disabled_member: + 2025-08: [false, false, false, false, false, false, false, false] + 2026-01: [false, false, false, false, false, false, false, false] + is_snap_excluded_member: + 2025-08: [false, false, false, false, false, false, false, false] + 2026-01: [false, false, false, false, false, false, false, false] + snap_utility_allowance_type: + 2025-08: [NONE, NONE, IUA, IUA, LUA, LUA, IUA, IUA] + 2026-01: [NONE, NONE, IUA, IUA, LUA, LUA, IUA, IUA] + snap_utility_allowance: + # FY2025: PA phone $34, LUA $402; MI $176 electric + $115 water. + 2025-08: [0, 0, 34, 34, 402, 402, 291, 291] + # FY2026: PA phone $107, LUA $488; MI $181 electric + $119 water. + 2026-01: [0, 0, 107, 107, 488, 488, 300, 300] + +# Dotted parameter inputs create an inline Core reform. Keep reform +# behavior in YAML rather than constructing a 53-state Python grid. +- name: Restoring the former heat-and-eat rule preserves expense and qualifying-member paths + period: 2026 + input: + gov.usda.snap.income.deductions.utility.heat_and_eat_requires_elderly_disabled: false + # PA: no bills, phone, two bills, heating, elderly, SSDI; then TX elderly. + age: + 2025: [40, 40, 40, 40, 60, 40, 60] + 2026: [40, 40, 40, 40, 60, 40, 60] + weekly_hours_worked_before_lsr: + 2025: [30, 30, 30, 30, 30, 30, 30] + 2026: [30, 30, 30, 30, 30, 30, 30] + state_code: + 2025: [PA, PA, PA, PA, PA, PA, TX] + 2026: [PA, PA, PA, PA, PA, PA, TX] + social_security_disability: + 2025: [0, 0, 0, 0, 0, 1_200, 0] + 2026: [0, 0, 0, 0, 0, 1_200, 0] + heating_cooling_expense: + 2025: [0, 0, 0, 1_200, 0, 0, 0] + 2026: [0, 0, 0, 1_200, 0, 0, 0] + phone_expense: + 2025: [0, 360, 0, 0, 0, 0, 0] + 2026: [0, 360, 0, 0, 0, 0, 0] + pre_subsidy_electricity_expense: + 2025: [0, 0, 600, 0, 0, 0, 0] + 2026: [0, 0, 600, 0, 0, 0, 0] + water_expense: + 2025: [0, 0, 300, 0, 0, 0, 0] + 2026: [0, 0, 300, 0, 0, 0, 0] + output: + snap_state_using_standard_utility_allowance: + 2025-07: [true, true, true, true, true, true, false] + 2025-08: [true, true, true, true, true, true, false] + 2026-01: [true, true, true, true, true, true, false] + has_snap_elderly_disabled_member: + 2025-08: [false, false, false, false, true, true, true] + 2026-01: [false, false, false, false, true, true, true] + is_snap_excluded_member: + 2025-08: [false, false, false, false, false, false, false] + 2026-01: [false, false, false, false, false, false, false] + snap_utility_allowance_type: + 2025-07: [SUA, SUA, SUA, SUA, SUA, SUA, NONE] + 2025-08: [SUA, SUA, SUA, SUA, SUA, SUA, NONE] + 2026-01: [SUA, SUA, SUA, SUA, SUA, SUA, NONE] + snap_utility_allowance: + 2025-07: [758, 758, 758, 758, 758, 758, 0] + 2025-08: [758, 758, 758, 758, 758, 758, 0] + 2026-01: [857, 857, 857, 857, 857, 857, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/snap_utility_allowance_type.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/snap_utility_allowance_type.yaml index 38f11db742c..6ead2af8600 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/snap_utility_allowance_type.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/deductions/snap_utility_allowance_type.yaml @@ -309,3 +309,56 @@ # households, so the SUA applies before the two-utility LUA count # (legacy plus water) is ever reached. snap_utility_allowance_type: SUA + +- name: Michigan heat-and-eat household with two non-heating bills receives IUA because Michigan has no LUA + period: 2026-01 + input: + age: + 2026: 40 + weekly_hours_worked_before_lsr: + 2026: 30 + state_code: + 2026: MI + pre_subsidy_electricity_expense: + 2026: 600 + water_expense: + 2026: 300 + output: + has_snap_elderly_disabled_member: false + is_snap_excluded_member: false + snap_state_using_standard_utility_allowance: true + has_heating_cooling_expense: false + count_distinct_utility_expenses: 2 + snap_utility_allowance_type: IUA + snap_utility_allowance: 300 # $181 electricity + $119 water. + +- name: Pennsylvania SPM units sharing a household qualify for heat-and-eat independently + period: 2026-01 + input: + people: + elder: + age: + 2026: 60 + weekly_hours_worked_before_lsr: + 2026: 30 + adult: + age: + 2026: 40 + weekly_hours_worked_before_lsr: + 2026: 30 + spm_units: + elderly_unit: + members: [elder] + ordinary_unit: + members: [adult] + households: + household: + members: [elder, adult] + state_code: + 2026: PA + output: + has_snap_elderly_disabled_member: [true, false] + is_snap_excluded_member: [false, false] + snap_state_using_standard_utility_allowance: [true, true] + snap_utility_allowance_type: [SUA, NONE] + snap_utility_allowance: [857, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/income/ineligible_members/integration.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/ineligible_members/integration.yaml index 1bf45126855..46a7f70a59a 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/income/ineligible_members/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/ineligible_members/integration.yaml @@ -108,7 +108,13 @@ snap_unit_size: 2 # Massachusetts counts all of the undocumented member's income. snap_earned_income: 2_000 - snap: 194 + # No utility costs or elderly/disabled member: no actual-cost SUA or + # Massachusetts H-EAT SUA under P.L. 119-21 section 10103(a). + # https://www.govinfo.gov/content/pkg/PLAW-119publ21/html/PLAW-119publ21.htm + # https://dtapolicyguide.qa.eohhs.mass.gov/SNAP/ExpensesDeductions/HEAT.htm + # $2,000 - $400 earned income deduction - $209 standard deduction + # = $1,391; $546 - ceil(30% x $1,391) = $546 - $418 = $128. + snap: 128 - name: Case 5, undocumented earner in a hybrid gross-test state. period: 2026-01 diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/snap_child_support_integration.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/snap_child_support_integration.yaml index a83935e7ac0..1b8a19ece66 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/snap_child_support_integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/snap_child_support_integration.yaml @@ -54,9 +54,17 @@ snap_child_support_gross_income_deduction: 433.33 snap_gross_income: 2_589.63 snap_child_support_deduction: 0 - meets_snap_categorical_eligibility: true - is_snap_eligible: true - snap: 24 + # Without deemed SUA, net is $2,589.63 - $604.59 - $209 = $1,776.04. + # Rent $880 is below half-net $888.02, so there is no shelter deduction. + # Main's California net screen denies SNAP at $1,776 > $1,305. + # The independent California MCE correction is tracked in #10036. + snap_utility_allowance: 0 + snap_excess_shelter_expense_deduction: 0 + snap_net_income: 1_776 + meets_tanf_non_cash_net_income_test: false + meets_snap_categorical_eligibility: false + is_snap_eligible: false + snap: 0 - name: New York excludes child support from gross income and does not deduct it again from net income. period: 2026-01 diff --git a/policyengine_us/tests/policy/baseline/partners/amplifi/2026.yaml b/policyengine_us/tests/policy/baseline/partners/amplifi/2026.yaml index 840cbe95b4f..0c4d2523093 100644 --- a/policyengine_us/tests/policy/baseline/partners/amplifi/2026.yaml +++ b/policyengine_us/tests/policy/baseline/partners/amplifi/2026.yaml @@ -260,7 +260,7 @@ spm_unit: ca_tanf: 0.0 ca_tanf_eligible: false - snap: 1917.0 + snap: 1506.0 is_snap_eligible: true lifeline: 228.0 is_lifeline_eligible: true diff --git a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ca.yaml b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ca.yaml index d01e8998b9c..da65546cf34 100644 --- a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ca.yaml +++ b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ca.yaml @@ -280,7 +280,7 @@ # fully counted; from April the head is excluded (size 2) and their # earnings count at the 2/3 prorated share under 7 CFR # 273.11(c)(2)-(3), raising the benefit relative to full counting. - snap: 2172.0 + snap: 2160.0 is_snap_eligible: true - name: snap_ca_head_immigration_undocumented_calworks_interaction (ca) period: 2026 @@ -346,5 +346,5 @@ # 2, the CalWORKs grant excludes the head from the AU but counts in # full as unit-level unearned income, and the head's earnings count # at the 2/3 prorated share under 7 CFR 273.11(c)(2)-(3). - snap: 3009.0 + snap: 2613.0 is_snap_eligible: true diff --git a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ma.yaml b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ma.yaml index f77ac275631..2a1aef1730b 100644 --- a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ma.yaml +++ b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ma.yaml @@ -206,5 +206,5 @@ output: spm_units: spm_unit: - snap: 3825.0 + snap: 2553.0 is_snap_eligible: true diff --git a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/ca.yaml b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/ca.yaml index d696fec62b2..ba2c6a460ad 100644 --- a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/ca.yaml +++ b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/ca.yaml @@ -1124,7 +1124,7 @@ la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 7956.0 + snap: 7722.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -1706,7 +1706,7 @@ la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 7956.0 + snap: 7722.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -1903,11 +1903,11 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: true + is_snap_eligible: false la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 3729.0 + snap: 0.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -2092,7 +2092,7 @@ la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 7956.0 + snap: 7722.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -2486,7 +2486,7 @@ la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 7956.0 + snap: 7722.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -2674,11 +2674,11 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: true + is_snap_eligible: false la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 3729.0 + snap: 0.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -2874,11 +2874,11 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: true + is_snap_eligible: false la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 3729.0 + snap: 0.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -3450,7 +3450,7 @@ la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 7956.0 + snap: 7722.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -4795,11 +4795,11 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: true + is_snap_eligible: false la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 3729.0 + snap: 0.0 people: head: ca_ala_general_assistance_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/federal.yaml b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/federal.yaml index ec2c49094d1..eb5e62d1ebb 100644 --- a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/federal.yaml +++ b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/federal.yaml @@ -352,8 +352,8 @@ output: spm_units: spm_unit: - is_snap_eligible: true - snap: 3729.0 + is_snap_eligible: false + snap: 0.0 people: head: is_wic_eligible: false @@ -514,8 +514,8 @@ output: spm_units: spm_unit: - is_snap_eligible: true - snap: 3729.0 + is_snap_eligible: false + snap: 0.0 people: head: is_wic_eligible: false @@ -617,8 +617,8 @@ output: spm_units: spm_unit: - is_snap_eligible: true - snap: 3729.0 + is_snap_eligible: false + snap: 0.0 people: head: is_wic_eligible: false @@ -845,7 +845,7 @@ spm_units: spm_unit: is_snap_eligible: true - snap: 5802.0 + snap: 4659.0 people: head: is_wic_eligible: false @@ -953,7 +953,7 @@ spm_units: spm_unit: is_snap_eligible: true - snap: 5802.0 + snap: 4659.0 people: head: is_wic_eligible: false @@ -1148,8 +1148,8 @@ output: spm_units: spm_unit: - is_snap_eligible: true - snap: 3729.0 + is_snap_eligible: false + snap: 0.0 people: head: is_wic_eligible: false @@ -1348,8 +1348,8 @@ output: spm_units: spm_unit: - is_snap_eligible: true - snap: 3729.0 + is_snap_eligible: false + snap: 0.0 people: head: is_wic_eligible: false @@ -1649,8 +1649,8 @@ output: spm_units: spm_unit: - is_snap_eligible: true - snap: 3729.0 + is_snap_eligible: false + snap: 0.0 people: head: is_wic_eligible: false @@ -1760,8 +1760,8 @@ output: spm_units: spm_unit: - is_snap_eligible: true - snap: 3729.0 + is_snap_eligible: false + snap: 0.0 people: head: is_wic_eligible: false diff --git a/policyengine_us/variables/gov/usda/snap/income/deductions/shelter/snap_utility_allowance_type.py b/policyengine_us/variables/gov/usda/snap/income/deductions/shelter/snap_utility_allowance_type.py index f5d5dab6bd7..b0b74d01125 100644 --- a/policyengine_us/variables/gov/usda/snap/income/deductions/shelter/snap_utility_allowance_type.py +++ b/policyengine_us/variables/gov/usda/snap/income/deductions/shelter/snap_utility_allowance_type.py @@ -17,17 +17,26 @@ class snap_utility_allowance_type(Variable): documentation = "The type of utility allowance that is eligible for the SPM unit" definition_period = MONTH reference = ( - "https://www.ecfr.gov/current/title-7/section-273.9#p-273.9(d)(6)(iii)(A)(3)" + "https://www.ecfr.gov/current/title-7/section-273.9#p-273.9(d)(6)(iii)(A)(3)", + "https://www.law.cornell.edu/uscode/text/7/2014#e_6_C_iv_I", + "https://www.govinfo.gov/content/pkg/PLAW-119publ21/html/PLAW-119publ21.htm", ) def formula(spm_unit, period, parameters): # The utility count and incurrence facts are YEAR-defined stocks # read at this MONTH period, so they are carried as is (no รท12). distinct_utility_bills = spm_unit("count_distinct_utility_expenses", period) - lua = parameters(period).gov.usda.snap.income.deductions.utility.limited + p = parameters(period).gov.usda.snap.income.deductions.utility + lua = p.limited region = spm_unit.household("snap_utility_region_str", period) always_sua = spm_unit("snap_state_using_standard_utility_allowance", period) has_heating_cooling = spm_unit("has_heating_cooling_expense", period) + # P.L. 119-21 section 10103(a) restricts energy-assistance deeming, + # while actual heating or cooling expenses still qualify on their own. + deemed_sua = always_sua + if p.heat_and_eat_requires_elderly_disabled: + elderly_disabled = spm_unit("has_snap_elderly_disabled_member", period) + deemed_sua = always_sua & elderly_disabled lua_is_defined = lua.active[region].astype(bool) # Under 7 CFR 273.9(d)(6)(iii)(A)(3), including telephone in the LUA # is a state option; where the state excludes it, a phone bill does @@ -39,7 +48,7 @@ def formula(spm_unit, period, parameters): ) return select( [ - has_heating_cooling | always_sua, + has_heating_cooling | deemed_sua, lua_is_defined & (lua_qualifying_bills >= 2), distinct_utility_bills > 0, ],