diff --git a/changelog.d/al-liheap-cooling.added.md b/changelog.d/al-liheap-cooling.added.md new file mode 100644 index 00000000000..ba256d83edd --- /dev/null +++ b/changelog.d/al-liheap-cooling.added.md @@ -0,0 +1 @@ +Add Alabama LIHEAP regular cooling assistance. diff --git a/changelog.d/al-liheap-cooling.fixed.md b/changelog.d/al-liheap-cooling.fixed.md new file mode 100644 index 00000000000..a38b9cfb862 --- /dev/null +++ b/changelog.d/al-liheap-cooling.fixed.md @@ -0,0 +1 @@ +Stop Alabama LIHEAP income limits at the federal maximum, the greater of HHS's 60% state median income amount and 150% of the poverty guideline. diff --git a/policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml b/policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml index e811bea6fbd..9db68e546b1 100644 --- a/policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml +++ b/policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml @@ -3,6 +3,7 @@ values: 2023-01-01: - ak_hap # Alaska Heating Assistance Program - al_liheap # Alabama LIHEAP + - al_liheap_cooling # Alabama LIHEAP cooling - ar_liheap # Arkansas LIHEAP - az_liheap # Arizona LIHEAP # California's three components are exclusive by eligibility, so their sum is its single regular payment. diff --git a/policyengine_us/parameters/gov/states/al/adeca/liheap/cooling/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/al/adeca/liheap/cooling/fpg_year_lag.yaml new file mode 100644 index 00000000000..a9169a58452 --- /dev/null +++ b/policyengine_us/parameters/gov/states/al/adeca/liheap/cooling/fpg_year_lag.yaml @@ -0,0 +1,17 @@ +description: Alabama uses federal poverty guidelines from this many years before the benefit year for regular cooling assistance under the Low Income Home Energy Assistance Program. +# The May-September cooling season runs on the chart ADECA updates to the +# calendar year's guidelines once they are released. The May 15, 2026 effective +# date of the summer 2026 chart is reported from an attachment to the draft +# FY2027 plan that ADECA later removed; no live copy was found. The model applies +# the updated chart to the whole season, including applications before the update. +values: + 2025-10-01: 0 +metadata: + unit: year + period: year + label: Alabama LIHEAP cooling poverty guideline year lag + reference: + - title: "Alabama FY2026 LIHEAP State Plan, sections 1.1 and 3.5 (May-September cooling season; adopt the 2026 guidelines upon release) #page 4,12" + href: https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=4 + - title: Alabama FY2027 LIHEAP State Plan, section 3.5 (the 2026 guidelines set the $1,995 one-person limit and $665, $1,331 and $1,995 band tops; adopt the 2027 guidelines upon release) + href: https://liheapch.acf.gov/docs/2027/state-plans/AL_Plan_2027.pdf#page=12 diff --git a/policyengine_us/parameters/gov/states/al/adeca/liheap/eligibility/fpg_rate.yaml b/policyengine_us/parameters/gov/states/al/adeca/liheap/eligibility/fpg_rate.yaml index 2f2d2065135..3ece83e0352 100644 --- a/policyengine_us/parameters/gov/states/al/adeca/liheap/eligibility/fpg_rate.yaml +++ b/policyengine_us/parameters/gov/states/al/adeca/liheap/eligibility/fpg_rate.yaml @@ -6,5 +6,5 @@ metadata: period: year label: Alabama LIHEAP federal poverty guideline rate reference: - - title: Alabama FY2026 LIHEAP State Plan, section 2.1 + - title: "Alabama FY2026 LIHEAP State Plan, sections 2.1 and 3.1 #page 8,11" href: https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=8 diff --git a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/additional_person_amount.yaml b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/additional_person_amount.yaml index fb7ddf01173..6e9fd5edfe0 100644 --- a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/additional_person_amount.yaml +++ b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/additional_person_amount.yaml @@ -4,7 +4,7 @@ values: metadata: unit: currency-USD period: year - label: Alabama LIHEAP additional person heating payment + label: Alabama LIHEAP additional person payment reference: - title: Alabama FY2026 LIHEAP Policy Manual, Appendix D (current benefit chart) href: https://adeca.alabama.gov/wp-content/uploads/FY-2026-LIHEAP-Manual-1.pdf#page=57 diff --git a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/base_amount.yaml b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/base_amount.yaml index b71aa51c967..40eab3f14c1 100644 --- a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/base_amount.yaml +++ b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/base_amount.yaml @@ -1,4 +1,4 @@ -description: Alabama provides this base payment for a one-person household in the lowest income band, by heating fuel, under the Low Income Home Energy Assistance Program. +description: Alabama provides this base payment for a one-person household in the lowest income band, by fuel type, under the Low Income Home Energy Assistance Program. propane: 2025-10-01: 500 natural_gas: @@ -10,7 +10,7 @@ wood_coal_kerosene: metadata: unit: currency-USD period: year - label: Alabama LIHEAP base heating payment by fuel + label: Alabama LIHEAP base payment by fuel propagate_metadata_to_children: true reference: - title: Alabama FY2026 LIHEAP Policy Manual, Appendix D (current benefit chart) diff --git a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/iija_supplement.yaml b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/iija_supplement.yaml index e64582a64a3..32b43d01e4c 100644 --- a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/iija_supplement.yaml +++ b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/iija_supplement.yaml @@ -1,24 +1,23 @@ -description: Alabama provides this amount as an Infrastructure Investment and Jobs Act supplement with each regular heating assistance award under the Low Income Home Energy Assistance Program. +description: Alabama provides this amount as an Infrastructure Investment and Jobs Act supplement with each regular heating or cooling assistance award under the Low Income Home Energy Assistance Program. # Award 2601ALLIEI funds the FY2026 supplement: $1,248,405 (November 26, 2025) plus # $111,300 (August 13, 2026), or $1,359,705, roughly 13,600 supplements across heating # and cooling. The plan pays it "if funding is available"; the model assumes the award # does not run out, so population totals overstate funded supplements. values: 2025-10-01: 100 - # The draft FY2027 plan (section 2.5) omits the supplement; IIJA's last tranche was - # FY2026, although award 2601ALLIEI runs to September 30, 2027. Recheck against the - # final FY2027 plan, which was not published as of October 19, 2026. + # The draft and accepted FY2027 plans (sections 2.5 and 3.5) omit the supplement; + # IIJA's last tranche was FY2026, although award 2601ALLIEI runs to September 30, 2027. 2026-10-01: 0 metadata: unit: currency-USD period: year - label: Alabama LIHEAP IIJA heating supplement + label: Alabama LIHEAP IIJA supplement reference: - - title: Alabama FY2026 LIHEAP State Plan, section 2.5 + - title: "Alabama FY2026 LIHEAP State Plan, sections 2.5 and 3.5 #page 10,12" href: https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=10 - title: HHS TAGGS award 2601ALLIEI, Alabama LIHEAP Infrastructure Supplement (FY2026 funding) href: https://taggs.hhs.gov/Detail/AwardDetail?arg_AwardNum=2601ALLIEI&arg_ProgOfficeCode=31 - - title: "Alabama draft FY2027 LIHEAP State Plan, section 2.5 (no IIJA supplement) #page 9-10" - href: https://adeca.alabama.gov/wp-content/uploads/FY27-LIHEAP-State-Plan.pdf#page=9 + - title: "Alabama FY2027 LIHEAP State Plan, sections 2.5 and 3.5 (no IIJA supplement) #page 9-10,12" + href: https://liheapch.acf.gov/docs/2027/state-plans/AL_Plan_2027.pdf#page=9 - title: Infrastructure Investment and Jobs Act, Pub. L. 117-58, Division J, Title VII, 135 Stat. 1412 href: https://www.govinfo.gov/content/pkg/PLAW-117publ58/pdf/PLAW-117publ58.pdf#page=984 diff --git a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/income_band_reduction.yaml b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/income_band_reduction.yaml index bf665f985c8..bb1f6d5552a 100644 --- a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/income_band_reduction.yaml +++ b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/income_band_reduction.yaml @@ -1,4 +1,4 @@ -description: Alabama deducts this amount from the lowest-band heating payment for each income band under the Low Income Home Energy Assistance Program. +description: Alabama deducts this amount from the lowest-band payment for each income band under the Low Income Home Energy Assistance Program. # These differences reproduce every fuel and household-size cell in Appendix D. 1: 2025-10-01: 0 @@ -9,7 +9,7 @@ description: Alabama deducts this amount from the lowest-band heating payment fo metadata: unit: currency-USD period: year - label: Alabama LIHEAP heating payment reduction by income band + label: Alabama LIHEAP payment reduction by income band breakdown: - range(1, 4) propagate_metadata_to_children: true diff --git a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/maximum_payment_household_size.yaml b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/maximum_payment_household_size.yaml index b02c1ed57da..3ff1c484a4c 100644 --- a/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/maximum_payment_household_size.yaml +++ b/policyengine_us/parameters/gov/states/al/adeca/liheap/payment/maximum_payment_household_size.yaml @@ -1,4 +1,4 @@ -description: Alabama uses no more than this many household members to determine the regular heating payment under the Low Income Home Energy Assistance Program. +description: Alabama uses no more than this many household members to determine the regular heating or cooling payment under the Low Income Home Energy Assistance Program. values: 2025-10-01: 4 metadata: @@ -6,5 +6,5 @@ metadata: period: year label: Alabama LIHEAP maximum payment household size reference: - - title: Alabama FY2026 LIHEAP State Plan, section 2.5 (households over four receive the four-person payment) + - title: "Alabama FY2026 LIHEAP State Plan, sections 2.5 and 3.5 (households over four receive the four-person payment) #page 9,12" href: https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=9 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 6f704d520fb..0d113c1dedb 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1046,7 +1046,15 @@ programs: variable: al_liheap parameter_prefix: gov.states.al.adeca.liheap verified_years: "2026" - notes: FY2026 regular heating with the HUD allowance deduction and the funded IIJA supplement. Crisis, cooling, weatherization and equipment assistance are out of scope. + notes: FY2026 regular heating with the HUD allowance deduction and the funded IIJA supplement. Regular Cooling is a separate entry; crisis, weatherization and equipment assistance are out of scope. + - state: AL + status: partial + name: Alabama LIHEAP cooling + full_name: Alabama Low Income Home Energy Assistance Program Regular Cooling + variable: al_liheap_cooling + parameter_prefix: gov.states.al.adeca.liheap + verified_years: "2025-2026" + notes: FY2025-FY2026 Regular Cooling from the Electric column of the February 17, 2025 and May 15, 2026 charts, less the HUD allowance, plus the funded IIJA supplement, including nonsubsidized renters with energy costs in rent. Crisis cooling, fans, air conditioners and the discretionary $50 high-need addition are out of scope. - state: AK status: partial name: Alaska HAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling.yaml new file mode 100644 index 00000000000..3b61f7d8b4f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling.yaml @@ -0,0 +1,234 @@ +# Source: ADECA FY2026 LIHEAP Policy Manual (pages 9, 21-23), FY2026 plan sections 3.5-3.6 +# (pages 12-13), and the PY 2026 Payment Assistance Chart effective May 15, 2026 (no live copy; +# the FY2027 plan, section 3.5, page 12, prints the same 2026-guideline limit and bands). Regular Cooling pays the chart's Electric column, minus one month of HUD +# utility allowance, plus the $100 FY2026 IIJA supplement when the regular payment is positive. +# 2026 monthly band tops (2026 guidelines): size 1 $665 / $1,331 / $1,995; size 4 $1,375 / +# $2,751 / $4,125; size 5 $1,612 / $3,225 / $4,835. +# Electric column: size 1 $440 / $410 / $320; size 4 and up $470 / $440 / $350. + +# Part-time minimum wage: 20 hours x $7.25 x 52 weeks = $7,540 a year, $628.33 a month, +# band 1. Cooling: Electric $440 + $100 = $540. The gas heating column pays $480, and +# heating adds its own $100 supplement: $580. The national LIHEAP total is $580 + $540. +- name: Case 1, a gas-heated worker receives the Electric column cooling payment. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 45 + employment_income_before_lsr: 7_540 + heating_type: NATURAL_GAS + gas_expense: 900 + has_cooling_expense: true + hud_utility_allowance: 0 + output: + al_liheap_base_payment: 480 + al_liheap_cooling: 540 + al_liheap: 580 + liheap: 1_120 + +# Retiree with $1,100 a month of Social Security ($13,200 a year), band 2 ($666 to $1,331). +# SSI is zero: $1,100 - $20 = $1,080 exceeds the $994 federal benefit rate. +# Cooling: $440 - $30 = $410 + $100 = $510. +- name: Case 2, a one-person band 2 household receives $410 plus the supplement. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 70 + social_security_retirement: 13_200 + heating_type: ELECTRICITY + has_cooling_expense: true + hud_utility_allowance: 0 + output: + al_liheap_cooling: 510 + +# One earner at about $17.31 an hour full time: $36,000 a year, $3,000 a month, size 4 band 3 +# ($2,752 to $4,125). Cooling: $440 - $120 + 3 x $10 = $350 + $100 = $450. +- name: Case 3, a four-person band 3 household receives $350 plus the supplement. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income_before_lsr: 36_000 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + heating_type: ELECTRICITY + has_cooling_expense: true + households: + household: + members: [person1, person2, person3, person4] + state_code: AL + hud_utility_allowance: 0 + output: + al_liheap_cooling: 450 + +# Five people with $30,000 of wages: $2,500 a month. Size 5 band tops are +# floor(4,835 / 3 + 0.5) = $1,612 and 2 x 1,612 + 1 = $3,225, so band 2. The payment uses +# the four-person column: $440 - $30 + 3 x $10 = $440 + $100 = $540. +- name: Case 4, a five-person household receives the four-person payment. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + employment_income_before_lsr: 30_000 + person2: + age: 36 + person3: + age: 12 + person4: + age: 9 + person5: + age: 4 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + heating_type: ELECTRICITY + has_cooling_expense: true + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: AL + hud_utility_allowance: 0 + output: + al_liheap_cooling: 540 + +# Case 1's worker with HUD utility allowances of $50 and $440 a month ($600 and $5,280 a year). +# $440 - $50 = $390 + $100 = $490. $440 - $440 = $0, so no supplement is added. +- name: Case 5, the monthly HUD utility allowance reduces the cooling payment. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [AL, AL] + age: [45, 45] + employment_income_before_lsr: [7_540, 7_540] + heating_type: [ELECTRICITY, ELECTRICITY] + has_cooling_expense: [true, true] + hud_utility_allowance: [600, 5_280] + output: + al_liheap_cooling: [490, 0] + +# $15 an hour full time: $31,200 a year, $2,600 a month, above the $1,995 one-person limit. +- name: Case 6, income above the cooling limit pays nothing. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 30 + employment_income_before_lsr: 31_200 + heating_type: ELECTRICITY + has_cooling_expense: true + hud_utility_allowance: 0 + output: + al_liheap_cooling: 0 + +- name: Case 7, a household without a cooling cost receives no cooling payment. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 45 + employment_income_before_lsr: 7_540 + heating_type: ELECTRICITY + has_cooling_expense: false + hud_utility_allowance: 0 + output: + al_liheap_cooling: 0 + +# FY2027 carries the chart amounts forward and ends the IIJA supplement on October 1, 2026. +# $628.33 a month stays in band 1 under any 2027 guideline at least as high as 2026's $15,960 +# (band 1 top of $665 or more). Cooling: $440. +- name: Case 8, the summer 2027 payment has no IIJA supplement. + period: 2027 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 45 + employment_income_before_lsr: 7_540 + heating_type: ELECTRICITY + has_cooling_expense: true + hud_utility_allowance: 0 + output: + al_liheap_cooling: 440 + +# Each income source is floored at zero, so a $20,000 business loss leaves countable income +# at $0, band 1: $440 + $100 = $540, not more. +- name: Case 9, a business loss does not raise the payment above the band 1 amount. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 45 + self_employment_income: -20_000 + heating_type: ELECTRICITY + has_cooling_expense: true + hud_utility_allowance: 0 + output: + al_liheap_cooling: 540 + +# Case 1's worker with the heating fuel left unspecified. Regular Cooling pays the Electric +# column whatever the heating fuel, and plan item 3.2 adds no cooling requirement, so band 1 +# pays $440 + $100 = $540. +# Was false and $0, now true and $540: cooling eligibility no longer requires a reported heating fuel. +- name: Case 10, an unspecified heating fuel still receives the cooling payment. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 45 + employment_income_before_lsr: 7_540 + heating_type: UNSPECIFIED + has_cooling_expense: true + hud_utility_allowance: 0 + output: + al_liheap_cooling_eligible: true + al_liheap_cooling: 540 + +# FY2025 plan: cooling runs May 1 to September 30, 2025, pays $320 to $520, and adds the +# $100 IIJA supplement. The chart effective February 17, 2025 uses the 2025 guidelines: +# size 1 limit 15,650 x 1.5 / 12 = 1,956.25, printed $1,956 ($23,472 a year), band 2 +# $653 to $1,305, with the same Electric column. Case 2's retiree, $1,100 a month, is in +# band 2 (SSI is zero: $1,100 - $20 = $1,080 exceeds the $967 federal benefit rate). +# Cooling: $440 - $30 = $410 + $100 = $510. +- name: Case 11, the summer 2025 payment uses the February 17, 2025 chart. + period: 2025 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 70 + social_security_retirement: 13_200 + heating_type: ELECTRICITY + has_cooling_expense: true + hud_utility_allowance: 0 + output: + al_liheap_cooling_income_limit: 23_472 + al_liheap_cooling: 510 + +# 21 hours a week at the $7.25 federal minimum wage (Alabama has none): 21 x 7.25 x 52 = +# $7,917 a year, $659.75 a month. On the cooling limit, band 1 runs to +# floor(1,995 / 3 + 0.5) = $665, so Electric $440 + $100 = $540. On the heating limit of +# $1,956, band 1 ends at floor(1,956 / 3 + 0.5) = $652, so the heating band is 2, which +# would pay $410 + $100 = $510. +- name: Case 12, the cooling payment reads its band from the cooling limit. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 45 + employment_income_before_lsr: 7_917 + heating_type: ELECTRICITY + has_cooling_expense: true + hud_utility_allowance: 0 + output: + al_liheap_income_band: 2 + al_liheap_cooling: 540 diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_eligible.yaml new file mode 100644 index 00000000000..548bcb4c8f2 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_eligible.yaml @@ -0,0 +1,152 @@ +# Source: ADECA FY2026 LIHEAP Policy Manual (pages 9, 16-17, 21), FY2026 plan sections 3.1-3.2, +# and the PY 2026 Payment Assistance Chart effective May 15, 2026 (2026 guidelines). + +# One person: the cooling limit is 15,960 x 1.5 / 12 = $1,995 a month, or $23,940 a year. +# $23,940 of wages is exactly $1,995 a month, so the limit is inclusive. +- name: Case 1, income exactly at the cooling limit is eligible. + period: 2026 + input: + state_code: AL + age: 40 + employment_income_before_lsr: 23_940 + heating_type: ELECTRICITY + has_cooling_expense: true + output: + al_liheap_cooling_income_limit: 23_940 + al_liheap_cooling_eligible: true + +# $23,940.12 a year is $1,995.01 a month, one cent over the limit. +- name: Case 2, one cent a month above the cooling limit is ineligible. + period: 2026 + input: + state_code: AL + age: 40 + employment_income_before_lsr: 23_940.12 + heating_type: ELECTRICITY + has_cooling_expense: true + output: + al_liheap_cooling_eligible: false + +# $23,700 of wages is $1,975 a month: above the heating limit of 15,650 x 1.5 / 12 = $1,956 +# (2025 guidelines) but within the cooling limit of $1,995 (2026 guidelines). +- name: Case 3, cooling uses the current year guidelines while heating uses the prior year. + period: 2026 + input: + state_code: AL + age: 40 + employment_income_before_lsr: 23_700 + heating_type: NATURAL_GAS + gas_expense: 900 + has_cooling_expense: true + output: + al_liheap_income_limit: 23_472 + al_liheap_cooling_income_limit: 23_940 + al_liheap_eligible: false + al_liheap_cooling_eligible: true + +# Part-time minimum wage: 20 hours x $7.25 x 52 weeks = $7,540 a year ($628.33 a month). +# Regular Cooling has no heating-fuel requirement, so a home without heating and a gas-heated +# home are both eligible. +- name: Case 4, a home without heating and a gas-heated home are both cooling eligible. + period: 2026 + input: + state_code: [AL, AL] + age: [45, 45] + employment_income_before_lsr: [7_540, 7_540] + heating_type: [NONE, NATURAL_GAS] + has_cooling_expense: [true, true] + output: + al_liheap_cooling_eligible: [true, true] + +# The same worker heats with gas and pays a $900 gas bill but has no cooling cost. +- name: Case 5, a heating-eligible household without a cooling cost is not cooling eligible. + period: 2026 + input: + state_code: AL + age: 45 + employment_income_before_lsr: 7_540 + heating_type: NATURAL_GAS + gas_expense: 900 + has_cooling_expense: false + output: + al_liheap_eligible: true + al_liheap_cooling_eligible: false + +# Manual 5.3 and 6.1.3 make renters in nonsubsidized housing whose energy costs are +# included in the rent eligible for Regular Assistance. Both renters pay the FY2026 HUD +# Fair Market Rent for a one-bedroom unit in Jefferson County, $1,155 a month (x12 = +# 13,860), which includes utilities, and report no separate cooling cost. The part-time +# worker ($628.33 a month, band 1) receives $440 + $100 = $540 when unsubsidized; the +# subsidized renter is not covered by the rent route. +- name: Case 6, a nonsubsidized renter with energy costs in the rent is cooling eligible. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [AL, AL] + age: [45, 45] + employment_income_before_lsr: [7_540, 7_540] + heating_type: [NATURAL_GAS, NATURAL_GAS] + has_cooling_expense: [false, false] + tenant_pays_utilities: [false, false] + rent: [13_860, 13_860] + receives_housing_assistance: [false, true] + hud_utility_allowance: [0, 0] + output: + al_liheap_cooling_eligible: [true, false] + al_liheap_cooling: [540, 0] + +# Manual section 4 requires at least one citizen or qualified household member, as for +# heating. An undocumented adult alone gives household size 0, so the unit is not eligible +# although its $628.33 a month and its cooling cost would qualify. +- name: Case 7, a unit with no qualified member is not cooling eligible. + period: 2026 + input: + state_code: AL + age: 45 + immigration_status: UNDOCUMENTED + employment_income_before_lsr: 7_540 + heating_type: ELECTRICITY + has_cooling_expense: true + output: + al_liheap_household_size: 0 + al_liheap_cooling_eligible: false + +# Two nonsubsidized units without a separate cooling cost, each missing one condition of the +# rent route. Unit 1 has its utilities in the rent but pays no rent. Unit 2 pays the FY2026 +# HUD Fair Market Rent for a one-bedroom unit in Jefferson County, $1,155 a month (x12 = +# 13,860), but pays its own utilities, the default. +- name: Case 8, the rent route needs both utilities in the rent and a positive rent. + period: 2026 + input: + state_code: [AL, AL] + age: [45, 45] + employment_income_before_lsr: [7_540, 7_540] + heating_type: [NATURAL_GAS, NATURAL_GAS] + has_cooling_expense: [false, false] + tenant_pays_utilities: [false, true] + rent: [0, 13_860] + output: + al_liheap_cooling_eligible: [false, false] + +# Case 6's worker in public housing, with no other housing assistance, energy costs in the +# rent and no out-of-pocket cooling cost. Public housing is subsidized housing, and under +# manual 6.1.1 a subsidized tenant who pays nothing out of pocket is not eligible. The rent +# is the public housing tenant payment of 30% of adjusted income (24 CFR 5.628), which for a +# single adult without deductions is 0.3 x 7,540 = 2,262. +- name: Case 9, a public housing tenant with energy costs in the rent is not cooling eligible. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: AL + age: 45 + employment_income_before_lsr: 7_540 + heating_type: NATURAL_GAS + has_cooling_expense: false + tenant_pays_utilities: false + rent: 2_262 + receives_housing_assistance: false + is_in_public_housing: true + hud_utility_allowance: 0 + output: + al_liheap_cooling_eligible: false + al_liheap_cooling: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_income_limit.yaml new file mode 100644 index 00000000000..8e6f3378d2d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_income_limit.yaml @@ -0,0 +1,33 @@ +# Source: ADECA PY 2026 Payment Assistance Chart effective May 15, 2026 (no live copy; the FY2027 plan, +# section 3.5, page 12, prints the same arithmetic), +# built on the 2026 guidelines of $15,960 plus $5,680 per additional person. + +# 150% a month: size 1 = 15,960 x 1.5 / 12 = 1,995; size 2 = 21,640 x 1.5 / 12 = 2,705; +# size 3 = 3,415; size 4 = 4,125; size 5 = 4,835; size 15 = 95,480 x 1.5 / 12 = 11,935. +# Each printed monthly limit times 12. +- name: Case 1, summer 2026 cooling limits follow the May 15, 2026 chart. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [AL, AL, AL, AL, AL, AL] + heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] + has_cooling_expense: [true, true, true, true, true, true] + al_liheap_household_size: [1, 2, 3, 4, 5, 15] + output: + al_liheap_cooling_income_limit: [23_940, 32_460, 40_980, 49_500, 58_020, 143_220] + +# Summer 2025 used the chart effective February 17, 2025, on the 2025 guidelines of $15,650 plus $5,500 per +# additional person. Size 7: 48,650 x 1.5 / 12 = 6,081.25, printed as 6,081 (x 12 = 72,972). Size 8: 54,150 x 1.5 / 12 +# = 6,768.75, printed as 6,769 (x 12 = 81,228). 42 U.S.C. 8624(b)(2)(B) pays no household above the greater of 150% +# of the guideline (81,225 at size 8) and the FY2025 60% state median income amount (57,273 for four x 1.38 = +# 79,036), so the size 8 limit stops at 81,225. +- name: Case 2, a summer 2025 limit that rounds above the federal maximum stops there. + period: 2025 + absolute_error_margin: 0.01 + input: + state_code: [AL, AL] + heating_type: [ELECTRICITY, ELECTRICITY] + has_cooling_expense: [true, true] + al_liheap_household_size: [7, 8] + output: + al_liheap_cooling_income_limit: [72_972, 81_225] diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.yaml index 40b7d744bbc..e15a49cc6dd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.yaml @@ -1,7 +1,12 @@ # Source: ADECA FY2026 LIHEAP Policy Manual and its Appendix D Payment Assistance Chart. # Appendix D, sizes 1-15: each published monthly limit is annualized once; this isolated unit test supplies size directly. -- name: Case 1, all fifteen published monthly limits are reproduced annually. +# Each limit stops at the federal maximum of 42 U.S.C. 8624(b)(2)(B): the greater of 150% of the 2025 guideline +# ($15,650 plus $5,500 per additional person) and HHS's FY2026 60% state median income amount (59,220 for four, +# times the size factor, rounded down). The chart is $3 higher at sizes 10, 12 and 14: 8,144 x 12 = 97,728 against +# 65,150 x 1.5 = 97,725; 9,519 x 12 = 114,228 against 114,225; 10,894 x 12 = 130,728 against 130,725. At size 8 the +# chart's 6,769 x 12 = 81,228 is below the 60% amount (59,220 x 1.38 = 81,723), so it stays. +- name: Case 1, all fifteen published monthly limits are annualized and stop at the federal maximum. period: 2026 absolute_error_margin: 0.01 input: @@ -11,7 +16,7 @@ al_liheap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] output: al_liheap_income_limit: [23_472, 31_728, 39_972, 48_228, 56_472, 64_728, 72_972, 81_228, 89_472, - 97_728, 105_972, 114_228, 122_472, 130_728, 138_972] + 97_725, 105_972, 114_225, 122_472, 130_725, 138_972] # The 2025 model year uses the 2024 guidelines of $15,060 and $20,440: 150% a month is $1,882.50 and $2,555, @@ -25,3 +30,21 @@ al_liheap_household_size: [1, 2] output: al_liheap_income_limit: [22_596, 30_660] + +# ADECA's PY 2025 chart and Summarized Eligibility Requirements effective October 1, 2024 to February 16, 2025, on +# the 2024 guidelines ($15,060 plus $5,380 per additional person), print 5,918, 6,590, 7,263, 7,935, 8,608, 9,280, +# 9,953, 10,625 and 11,298 a month for sizes 7-15. At odd sizes 150% a month ends in $0.50 and rounds up, so the +# printed limit is $6 a year above 150% of the guideline: size 9 prints 7,263 x 12 = 87,156 against 58,100 x 1.5 = +# 87,150. From size 8, 150% of the guideline exceeds HHS's FY2025 60% state median income amount (57,273 for four, +# times the size factor, rounded down: 79,036 at size 8 against 1.5 x 52,720 = 79,080, and 80,754 at size 9), so the +# odd sizes 9, 11, 13 and 15 stop at 87,150, 103,290, 119,430 and 135,570. At size 7 the 60% amount (57,273 x 1.35 = 77,318) is the higher maximum, so the printed 71,016 stays. +# Even sizes print whole dollars. Historical estimate; 2025 is not a verified year. +- name: Case 3, the 2025 limits at sizes 9, 11, 13 and 15 stop at the federal maximum. + period: 2025 + absolute_error_margin: 0.01 + input: + state_code: [AL, AL, AL, AL, AL, AL, AL, AL, AL] + heating_type: [PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE] + al_liheap_household_size: [7, 8, 9, 10, 11, 12, 13, 14, 15] + output: + al_liheap_income_limit: [71_016, 79_080, 87_150, 95_220, 103_290, 111_360, 119_430, 127_500, 135_570] diff --git a/policyengine_us/variables/gov/states/al/adeca/liheap/al_liheap.py b/policyengine_us/variables/gov/states/al/adeca/liheap/al_liheap.py index e6bc85a0fd1..fd36c336d6b 100644 --- a/policyengine_us/variables/gov/states/al/adeca/liheap/al_liheap.py +++ b/policyengine_us/variables/gov/states/al/adeca/liheap/al_liheap.py @@ -1,6 +1,22 @@ from policyengine_us.model_api import * +def al_liheap_award(spm_unit, period, parameters, chart_amount): + p = parameters(period).gov.states.al.adeca.liheap.payment + # The monthly HUD allowance reduces the award, not countable income. + # AL local allowance schedules are not encoded in the shared input; + # an observed annual allowance can be supplied directly. + allowance = spm_unit.household("hud_utility_allowance", period) / MONTHS_IN_YEAR + regular_payment = max_(chart_amount - allowance, 0) + # The plan pays the IIJA supplement "if funding is available"; the model + # assumes the FY2026 award does not run out (see the supplement parameter). + # Interpret the plan's "receives a Heating benefit" (or Cooling benefit) + # as requiring a positive regular payment after the HUD adjustment. The + # plan does not expressly address a regular payment reduced to zero. + supplement = where(regular_payment > 0, p.iija_supplement, 0) + return regular_payment + supplement + + class al_liheap(Variable): value_type = float entity = SPMUnit @@ -15,22 +31,10 @@ class al_liheap(Variable): ) def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.al.adeca.liheap.payment eligible = spm_unit("al_liheap_eligible", period) base = spm_unit("al_liheap_base_payment", period) - # The monthly HUD allowance reduces the award, not countable income. - # AL local allowance schedules are not encoded in the shared input; - # an observed annual allowance can be supplied directly. - allowance = spm_unit.household("hud_utility_allowance", period) / MONTHS_IN_YEAR - regular_payment = max_(base - allowance, 0) - # The plan pays the IIJA supplement "if funding is available"; the model - # assumes the FY2026 award does not run out (see the supplement parameter). - # Interpret the plan's "receives a Heating benefit" as requiring a - # positive regular payment after the HUD adjustment. The plan does - # not expressly address a regular payment reduced to zero. - supplement = where(regular_payment > 0, p.iija_supplement, 0) # The separate $50 high-need addition requires an agency decision # unavailable in existing inputs, so demographic traits alone do not # add it. Fixed regular payments have no cap at the reported heating # expense. - return eligible * (regular_payment + supplement) + return eligible * al_liheap_award(spm_unit, period, parameters, base) diff --git a/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling.py b/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling.py new file mode 100644 index 00000000000..83094d7cbfa --- /dev/null +++ b/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling.py @@ -0,0 +1,53 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.al.adeca.liheap.al_liheap import ( + al_liheap_award, +) +from policyengine_us.variables.gov.states.al.adeca.liheap.payment.al_liheap_base_payment import ( + al_liheap_chart_amount, +) +from policyengine_us.variables.gov.states.al.adeca.liheap.payment.al_liheap_income_band import ( + al_liheap_income_band_for_limit, +) + + +class al_liheap_cooling(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Alabama LIHEAP regular cooling assistance" + documentation = ( + "Verified for FY2025 and FY2026 (the May-September 2025 and 2026 " + "cooling seasons). Earlier years use model parameter backfilling and " + "are unverified historical estimates. Later years carry the FY2026 " + "chart amounts forward." + ) + defined_for = "al_liheap_cooling_eligible" + reference = ( + # PDF pages 9, 21-23 + "https://adeca.alabama.gov/wp-content/uploads/FY-2026-LIHEAP-Manual-1.pdf#page=9", + # PDF pages 12-13: section 3.5 adopts the 2026 guidelines upon release. + "https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=12", + # PDF pages 4, 12-13: the FY2025 cooling season, IIJA supplement and + # $320 to $520 range. + "https://liheapch.acf.gov/docs/2025/state-plans/AL_Plan_2025.pdf#page=4", + # The chart effective February 17, 2025, on the 2025 guidelines. + "https://liheapch.acf.gov/docs/2026/benefits-matricies/AL_BenefitMatrix_Cooling_2026.pdf", + # Section 3.5: the PY2027 chart, from October 1, 2026, shows the limit + # and band arithmetic on the 2026 guidelines. + "https://liheapch.acf.gov/docs/2027/state-plans/AL_Plan_2027.pdf#page=12", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.al.adeca.liheap.payment + limit = spm_unit("al_liheap_cooling_income_limit", period) + band = al_liheap_income_band_for_limit(spm_unit, period, limit) + # Regular Cooling pays the chart's Electric column, whose $320 to + # $470 range plus the $50 high-need addition is plan section 3.6's + # $320 to $520 cooling benefit range. One payment per cooling season. + chart_amount = al_liheap_chart_amount( + spm_unit, period, parameters, p.base_amount.electricity, band + ) + # The discretionary $50 high-need addition (manual 6.1.6) requires an + # agency decision unavailable in existing inputs, as for heating. + return al_liheap_award(spm_unit, period, parameters, chart_amount) diff --git a/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_eligible.py b/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_eligible.py new file mode 100644 index 00000000000..821849400c9 --- /dev/null +++ b/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_eligible.py @@ -0,0 +1,39 @@ +from policyengine_us.model_api import * + + +class al_liheap_cooling_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Alabama LIHEAP regular cooling assistance eligibility" + defined_for = StateCode.AL + reference = ( + # PDF pages 9, 16-17, 21-22 + "https://adeca.alabama.gov/wp-content/uploads/FY-2026-LIHEAP-Manual-1.pdf#page=9", + "https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=11", + ) + + def formula(spm_unit, period, parameters): + size = spm_unit("al_liheap_household_size", period) + income = spm_unit("al_liheap_countable_income", period) + limit = spm_unit("al_liheap_cooling_income_limit", period) + # The cooling cost input stands for the recent cooling bill (manual + # 5.3) and, for subsidized tenants, the out-of-pocket energy cost that + # manual 6.1.1 requires. Renters in nonsubsidized housing whose energy + # costs are included in the rent are also eligible (manual 5.3 and + # 6.1.3). + subsidized = spm_unit("receives_housing_assistance", period) | ( + spm_unit.household("is_in_public_housing", period) + ) + # Heating's rent route reads heat_expense_included_in_rent instead, so a + # renter with energy costs in the rent also sets tenant_pays_utilities + # to false for this route. + utilities_in_rent = ~spm_unit.household("tenant_pays_utilities", period) & ( + add(spm_unit, period, ["rent"]) > 0 + ) + responsible = spm_unit("has_cooling_expense", period) | ( + utilities_in_rent & ~subsidized + ) + # Cooling pays the Electric column whatever the heating fuel, so + # heating_type, including UNSPECIFIED, does not affect eligibility. + return (size > 0) & (income <= limit) & responsible diff --git a/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_income_limit.py b/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_income_limit.py new file mode 100644 index 00000000000..92b0ec48476 --- /dev/null +++ b/policyengine_us/variables/gov/states/al/adeca/liheap/cooling/al_liheap_cooling_income_limit.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.al.adeca.liheap.eligibility.al_liheap_income_limit import ( + al_liheap_income_limit_for_lag, +) + + +class al_liheap_cooling_income_limit(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Alabama LIHEAP regular cooling annualized income limit" + defined_for = StateCode.AL + reference = ( + # Section 3.5: the PY2027 chart, from October 1, 2026, shows the 2026 + # guideline arithmetic, $15,960 x 1.5 = $23,940 a year or $1,995 a + # month for one person. + "https://liheapch.acf.gov/docs/2027/state-plans/AL_Plan_2027.pdf#page=12", + # Section 3.5: ADECA adopts the 2026 guidelines upon release. + "https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=12", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.al.adeca.liheap.cooling + return al_liheap_income_limit_for_lag( + spm_unit, period, parameters, p.fpg_year_lag + ) diff --git a/policyengine_us/variables/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.py b/policyengine_us/variables/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.py index 344ec073c87..3c01905790a 100644 --- a/policyengine_us/variables/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.py +++ b/policyengine_us/variables/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.py @@ -1,7 +1,32 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import liheap_smi_limit from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg +def al_liheap_income_limit_for_lag(spm_unit, period, parameters, year_lag): + p = parameters(period).gov.states.al.adeca.liheap.eligibility + p_hhs = parameters(period).gov.hhs.liheap + size = spm_unit("al_liheap_household_size", period) + state = spm_unit.household("state_code_str", period) + state_group = spm_unit.household("state_group_str", period) + guideline = fpg( + max_(size, 1), + state_group, + period, + parameters, + year_lag=year_lag, + ) + monthly_limit = guideline * p.fpg_rate / MONTHS_IN_YEAR + # Nearest-dollar, half-up rounding reproduces all 15 printed limits. + rounded_limit = np.floor(monthly_limit + 0.5) * MONTHS_IN_YEAR + # 42 U.S.C. 8624(b)(2)(B) pays no household above the greater of 150% of the + # poverty guideline and 60% of state median income, in the amounts HHS + # publishes by household size. A published monthly amount that rounds above + # that maximum stops there. + smi_maximum = liheap_smi_limit(size, state, p_hhs.smi_limit, period, parameters) + return min_(rounded_limit, max_(guideline * p_hhs.fpg_limit, smi_maximum)) + + class al_liheap_income_limit(Variable): value_type = float entity = SPMUnit @@ -10,22 +35,16 @@ class al_liheap_income_limit(Variable): label = "Alabama LIHEAP annualized income limit" defined_for = StateCode.AL reference = ( + "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", + # FY2026 federal amounts, PDF pages 1, 4 + "https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=1", "https://adeca.alabama.gov/wp-content/uploads/FY-2026-LIHEAP-Manual-1.pdf#page=57", "https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=9", ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.al.adeca.liheap.eligibility - size = spm_unit("al_liheap_household_size", period) - state_group = spm_unit.household("state_group_str", period) - guideline = fpg( - max_(size, 1), - state_group, - period, - parameters, - year_lag=p.fpg_year_lag, - ) - monthly_limit = guideline * p.fpg_rate / MONTHS_IN_YEAR - # Nearest-dollar, half-up rounding reproduces all 15 printed limits. # The FY2026 heating season ends before the May 2026 chart update. - return np.floor(monthly_limit + 0.5) * MONTHS_IN_YEAR + return al_liheap_income_limit_for_lag( + spm_unit, period, parameters, p.fpg_year_lag + ) diff --git a/policyengine_us/variables/gov/states/al/adeca/liheap/payment/al_liheap_base_payment.py b/policyengine_us/variables/gov/states/al/adeca/liheap/payment/al_liheap_base_payment.py index 00b210f3705..2a171bb35b4 100644 --- a/policyengine_us/variables/gov/states/al/adeca/liheap/payment/al_liheap_base_payment.py +++ b/policyengine_us/variables/gov/states/al/adeca/liheap/payment/al_liheap_base_payment.py @@ -1,6 +1,21 @@ from policyengine_us.model_api import * +def al_liheap_chart_amount(spm_unit, period, parameters, base, band): + p = parameters(period).gov.states.al.adeca.liheap.payment + size = spm_unit("al_liheap_household_size", period) + additional_people = clip(size - 1, 0, p.maximum_payment_household_size - 1) + # Cross-state rows have band zero before defined_for masks the result; + # raise it to band 1 so the eager lookup stays within the breakdown. + lookup_band = max_(band, 1) + amount = ( + base + - p.income_band_reduction[lookup_band] + + additional_people * p.additional_person_amount + ) + return where(base > 0, amount, 0) + + class al_liheap_base_payment(Variable): value_type = float entity = SPMUnit @@ -31,16 +46,7 @@ def formula(spm_unit, period, parameters): ], default=0, ) - size = spm_unit("al_liheap_household_size", period) - additional_people = clip(size - 1, 0, p.maximum_payment_household_size - 1) - # Cross-state rows have band zero before defined_for masks the result; - # raise it to band 1 so the eager lookup stays within the breakdown. - band = max_(spm_unit("al_liheap_income_band", period), 1) - amount = ( - base - - p.income_band_reduction[band] - + additional_people * p.additional_person_amount - ) + band = spm_unit("al_liheap_income_band", period) # This compact representation reproduces Appendix D's entire matrix. # The manual's worked example on page 22 uses an older payment amount. # No published category was identified for fuel oil, solar, other, or @@ -48,4 +54,4 @@ def formula(spm_unit, period, parameters): # zero leaves those estimates incomplete; it does not establish legal # ineligibility, including heat in rent. Issue 9754 tracks the # unspecified-fuel default. - return where(base > 0, amount, 0) + return al_liheap_chart_amount(spm_unit, period, parameters, base, band) diff --git a/policyengine_us/variables/gov/states/al/adeca/liheap/payment/al_liheap_income_band.py b/policyengine_us/variables/gov/states/al/adeca/liheap/payment/al_liheap_income_band.py index 184c0a34af6..60ffd3ec7fc 100644 --- a/policyengine_us/variables/gov/states/al/adeca/liheap/payment/al_liheap_income_band.py +++ b/policyengine_us/variables/gov/states/al/adeca/liheap/payment/al_liheap_income_band.py @@ -1,6 +1,20 @@ from policyengine_us.model_api import * +def al_liheap_income_band_for_limit(spm_unit, period, annual_limit): + monthly_limit = annual_limit / MONTHS_IN_YEAR + monthly_income = spm_unit("al_liheap_countable_income", period) / MONTHS_IN_YEAR + first_upper = np.floor(monthly_limit / 3 + 0.5) + second_upper = 2 * first_upper + 1 + # Published upper bounds are inclusive. Fractional dollars immediately + # above an upper bound enter the next band without a one-dollar gap. + return select( + [monthly_income <= first_upper, monthly_income <= second_upper], + [1, 2], + default=3, + ) + + class al_liheap_income_band(Variable): value_type = int entity = SPMUnit @@ -10,14 +24,5 @@ class al_liheap_income_band(Variable): reference = "https://liheapch.acf.gov/docs/2026/state-plans/AL_Plan_2026.pdf#page=9" def formula(spm_unit, period, parameters): - monthly_limit = spm_unit("al_liheap_income_limit", period) / MONTHS_IN_YEAR - monthly_income = spm_unit("al_liheap_countable_income", period) / MONTHS_IN_YEAR - first_upper = np.floor(monthly_limit / 3 + 0.5) - second_upper = 2 * first_upper + 1 - # Published upper bounds are inclusive. Fractional dollars immediately - # above an upper bound enter the next band without a one-dollar gap. - return select( - [monthly_income <= first_upper, monthly_income <= second_upper], - [1, 2], - default=3, - ) + limit = spm_unit("al_liheap_income_limit", period) + return al_liheap_income_band_for_limit(spm_unit, period, limit) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 352bbc3a578..56861541b15 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -368,6 +368,54 @@ candidates: note: 'PE-US follows the statute and current rule: estate_income counts signed in Alabama gross income, so a beneficiary''s loss passes through (gross_income_sources.yaml, read by al_agi.py). estate_income does not separate trusts from estates. Identify booklet editions repeating the obsolete restriction.' +- id: us-al:liheap-income-limit-above-federal-ceiling + program: liheap + years: + from: 2025 + to: 2026 + type: federal-fiscal + question: Can Alabama's whole-dollar monthly LIHEAP limits pay a household whose income exceeds both 150% of the + poverty guideline and HHS's 60% state median income amount? + sources: + - kind: statute + citation: 42 U.S.C. 8624(b)(2)(B) + url: https://www.law.cornell.edu/uscode/text/42/8624#b_2_B + - kind: guidance + citation: HHS LIHEAP IM 2025-02 Attachment 4, Mandatory Use in LIHEAP for FY26, Alabama, pages 1 and 4 + url: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=1 + - kind: manual + citation: ADECA FY2026 LIHEAP Policy Manual, Appendix D Payment Assistance Chart, PDF page 57 + url: https://adeca.alabama.gov/wp-content/uploads/FY-2026-LIHEAP-Manual-1.pdf#page=57 + - kind: guidance + citation: ADECA Payment Assistance Chart effective February 17, 2025 (cooling) + url: https://liheapch.acf.gov/docs/2026/benefits-matricies/AL_BenefitMatrix_Cooling_2026.pdf + - kind: guidance + citation: ADECA LIHEAP Summarized Eligibility Requirements, Effective October 1, 2024 - February 16, 2025, page 1 + url: https://adeca.alabama.gov/wp-content/uploads/LIHEAP-Summarized-Eligibility-Requirements.pdf#page=1 + - kind: guidance + citation: HHS LIHEAP IM 2024-02 Attachment 4, Mandatory Use in LIHEAP for FY25, Alabama, pages 1 and 4 + url: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM%202024-02_Att4SMITable.pdf#page=1 + readings: + statute: Payments go only to households whose income does not exceed the greater of 150% of the poverty guideline + and 60% of the state median income that HHS publishes and adjusts for household size. + other: The charts round 150% of the monthly guideline to the nearest dollar, which puts the limit $3 or $6 a year + above the federal maximum at the large household sizes where 150% of the guideline is the greater amount. + example: In FY2026, ten people with $97,728 of countable income ($8,144 a month) are within the printed heating limit + and would be paid, but exceed the $97,725 federal maximum and receive $0 in the PR. + pe_us: + follows: statute + code: + - policyengine_us/variables/gov/states/al/adeca/liheap/eligibility/al_liheap_income_limit.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10756 + state: ruled + note: 'Ruled under the 2026-10-19 statute-first rule. The PR stops each limit at the federal maximum. Heating FY2026, on + the 2025 guidelines: sizes 10, 12 and 14 are $3 lower ($97,728 and $97,725 at 10); size 8 keeps the printed $81,228 + because HHS''s 60% amount, $81,723, is the higher maximum. Heating FY2025, on the 2024 guidelines of the October 1, 2024 + to February 16, 2025 chart, with HHS''s FY2025 amounts (LIHEAP IM 2024-02 Attachment 4): sizes 9, 11, 13 and 15 are + $6 lower ($87,156 and $87,150 at 9). Summer 2025 cooling, on the 2025 guidelines, with the same FY2025 amounts: sizes + 8, 10, 12 and 14 are $3 lower ($81,228 and $81,225 at 8). The summer 2026 chart, on the 2026 guidelines, prints whole-dollar + amounts equal to 150% of the guideline, so nothing is lowered. Verify each later chart.' - id: us-al:liheap-insurance-payments program: liheap years: