diff --git a/changelog.d/la-liheap-cooling.added.md b/changelog.d/la-liheap-cooling.added.md new file mode 100644 index 00000000000..453da0bf5c7 --- /dev/null +++ b/changelog.d/la-liheap-cooling.added.md @@ -0,0 +1 @@ +Add Louisiana LIHEAP regular cooling assistance, paid once each program year from the same benefit matrix as heating. diff --git a/policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml b/policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml index e811bea6fbd..c5debc9771b 100644 --- a/policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml +++ b/policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml @@ -23,6 +23,7 @@ values: - ks_liheap # Kansas LIEAP - ky_liheap # Kentucky LIHEAP - la_liheap # Louisiana LIHEAP + - la_liheap_cooling # Louisiana LIHEAP cooling - ma_liheap # Massachusetts LIHEAP - md_meap # Maryland MEAP - me_heap # Maine HEAP diff --git a/policyengine_us/parameters/gov/states/la/lhc/liheap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/la/lhc/liheap/eligibility/smi_rate.yaml index 5a6410f20b7..24ab88b57ea 100644 --- a/policyengine_us/parameters/gov/states/la/lhc/liheap/eligibility/smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/la/lhc/liheap/eligibility/smi_rate.yaml @@ -1,7 +1,8 @@ -description: Louisiana limits heating assistance income to this share of state median income under the Low Income Home Energy Assistance Program. +description: Louisiana limits regular heating and cooling assistance income to this share of state median income under the Low Income Home Energy Assistance Program. # The FFY2026 notice prints the resulting limits for household sizes 1-10. -# No adopted FFY2027 plan is available; later years carry this rate forward -# as unverified estimates. +# The accepted FFY2027 plan repeats the 60% limit (pages 11-12), but no FFY2027 +# notice prints the limits, so later years carry this rate forward as +# unverified estimates. values: 2025-10-01: 0.6 @@ -10,7 +11,7 @@ metadata: period: year label: Louisiana LIHEAP state median income rate reference: - - title: Louisiana FY2026 LIHEAP State Plan, Section 2.1 + - title: "Louisiana FY2026 LIHEAP State Plan, Sections 2.1 and 3.1 #page 9,11" href: https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=9 - title: Louisiana LIHEAP Service Delivery Guide, revised January 1, 2024, Section 3.6 C.1 href: https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20REVISED%20January%201_%202024.pdf#page=29 diff --git a/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/amount.yaml b/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/amount.yaml index c7eab5d6ccc..3640a87a30b 100644 --- a/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/amount.yaml +++ b/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/amount.yaml @@ -1,7 +1,8 @@ -description: Louisiana provides this regular heating benefit by energy burden band and household size group under the Low Income Home Energy Assistance Program. +description: Louisiana provides this regular heating or cooling benefit by energy burden band and household size group under the Low Income Home Energy Assistance Program. # The matrix prints one amount for sizes 1-3 and another for sizes 4 through -# "8 or More". The FY2026 plan's $200 minimum and $800 maximum (Section 2.6) -# equal the lowest cell and the highest cell plus the $100 priority supplement. +# "8 or More". The FY2026 plan's $200 minimum and $800 maximum (Sections 2.6 +# and 3.6) equal the lowest cell and the highest cell plus the $100 priority +# supplement. The same matrix sets the heating and the cooling benefit. # Energy burden band 1: 9.9% and less. 1: 1: @@ -30,7 +31,7 @@ description: Louisiana provides this regular heating benefit by energy burden ba metadata: unit: currency-USD period: year - label: Louisiana LIHEAP regular heating benefit amount + label: Louisiana LIHEAP regular heating and cooling benefit amount breakdown: - range(1, 5) # energy burden band - range(1, 3) # household size group (1 = size 1-3, 2 = size 4+) @@ -40,7 +41,7 @@ metadata: reference: - title: Louisiana FFY2026 Heating and Cooling Benefit Matrix, benefit amount href: https://liheapch.acf.gov/docs/2026/benefits-matricies/LA_BenefitMatrix_Heat-Cool_2026.pdf - - title: Louisiana FY2026 LIHEAP State Plan, Sections 2.4-2.6 + - title: "Louisiana FY2026 LIHEAP State Plan, Sections 2.4-2.6 and 3.4-3.6 #page 10,12" href: https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=10 - title: Louisiana LIHEAP Service Delivery Guide, revised January 1, 2024, Section 4.2 href: https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20REVISED%20January%201_%202024.pdf#page=41 diff --git a/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/burden_band.yaml b/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/burden_band.yaml index afc0262c8b6..80d6f0195c6 100644 --- a/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/burden_band.yaml +++ b/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/burden_band.yaml @@ -2,7 +2,7 @@ description: Louisiana assigns this benefit matrix energy burden band from total # The matrix prints the bands as "9.9% and Less", "10% to 17.9%", "18% to # 24.9%" and "25% and Greater". The unrounded burden uses lower-inclusive # cutoffs at 10%, 18% and 25%, which equals truncating the percent to one -# decimal. Households with zero income receive band 4 in la_liheap. +# decimal. Households with zero income receive band 4 in la_liheap_matrix_amount. brackets: # 9.9% and less. - threshold: diff --git a/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/energy_cost_sources.yaml b/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/energy_cost_sources.yaml index dff2b3eb3bc..66932176cf8 100644 --- a/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/energy_cost_sources.yaml +++ b/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/energy_cost_sources.yaml @@ -2,8 +2,10 @@ description: Louisiana adds these residential energy bills to compute the total # The guide adds the bills of every energy vendor. Annual amounts stand in for # the application-month bill and give the guide's burden only when that month's # bill equals the annual monthly average; Louisiana's heating-season electric -# bills run below that average and gas bills above it. Bill line items the -# guide includes or excludes (taxes, customer charges, franchise fees, arrears, +# bills run below that average and gas bills above it. Cooling-season electric +# bills run above that average, so the cooling burden band of a household that +# pays its own bills is likely a lower bound. Bill line items the guide +# includes or excludes (taxes, customer charges, franchise fees, arrears, # deposits) cannot be separated from these totals. Community solar # participants report their electric bill. values: diff --git a/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/priority_supplement.yaml b/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/priority_supplement.yaml index f3548178ea5..64449965a4f 100644 --- a/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/priority_supplement.yaml +++ b/policyengine_us/parameters/gov/states/la/lhc/liheap/payment/priority_supplement.yaml @@ -1,4 +1,4 @@ -description: Louisiana adds this heating payment once per household with at least one member in a targeted priority group under the Low Income Home Energy Assistance Program. +description: Louisiana adds this amount to the heating or cooling benefit once per household with at least one member in a targeted priority group under the Low Income Home Energy Assistance Program. values: 2025-10-01: 100 @@ -13,5 +13,5 @@ metadata: href: https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20REVISED%20January%201_%202024.pdf#page=41 - title: Louisiana LIHEAP Service Delivery Guide, effective April 1, 2026, Section 4.2 A href: https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20FINAL%20-%20Effective%20April%201%2c%202026.pdf#page=48 - - title: Louisiana FY2026 LIHEAP State Plan, Section 2.4 + - title: "Louisiana FY2026 LIHEAP State Plan, Sections 2.4 and 3.4 #page 10,12" href: https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=10 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 6f704d520fb..942e7103263 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1222,7 +1222,15 @@ programs: variable: la_liheap parameter_prefix: gov.states.la.lhc.liheap verified_years: "2026" - notes: FY2026 regular heating-season benefit from the energy burden matrix, including the $100 priority supplement. The larger summer cooling award, crisis and weatherization assistance are out of scope. + notes: FY2026 regular heating-season benefit from the energy burden matrix, including the $100 priority supplement. The cooling-season benefit is listed separately; crisis and weatherization assistance are out of scope. + - state: LA + status: partial + name: Louisiana LIHEAP cooling + full_name: Louisiana Low Income Home Energy Assistance Program cooling assistance + variable: la_liheap_cooling + parameter_prefix: gov.states.la.lhc.liheap + verified_years: "2026" + notes: FY2026 regular cooling-season benefit from the same energy burden matrix as heating, including the $100 priority supplement, for households with cooling costs or utilities included in rent. Supplemental cooling payments, crisis and weatherization assistance are out of scope. - state: MD status: partial name: Maryland MEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/cooling/la_liheap_cooling.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/cooling/la_liheap_cooling.yaml new file mode 100644 index 00000000000..d456268f96a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/cooling/la_liheap_cooling.yaml @@ -0,0 +1,199 @@ +# FFY2026 Heating and Cooling Benefit Matrix: one cooling benefit each program year +# (Service Delivery Guide effective April 1, 2026, Section 4.2 B) from the matrix +# heating uses. Energy burden (energy cost / income) bands of 9.9% and less, 10-17.9%, +# 18-24.9% and 25% and greater pay 200, 350, 500 and 650 for one to three members and +# 250, 400, 550 and 700 for four or more, plus one 100 supplement for a member 60 or +# older, disabled, or five or younger, up to 800. Wages of 15,080 are full-time work +# at the federal 7.25 minimum wage; electricity of 1,740 is 145 a month, near the +# EIA 2024 Louisiana average residential bill of 140.96 a month. + +- name: Case 1, a home with no heating but a cooling bill receives the cooling benefit only. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: NONE + has_cooling_expense: true + pre_subsidy_electricity_expense: 1_740 + households: + household: + members: [person1] + state_code: LA + output: + # Heating requires a heating fuel. + la_liheap: 0 + # 1,740 / 15,080 = 0.1154 -> band 2, size 1 + la_liheap_cooling: 350 + +- name: Case 2, a household eligible for both seasons receives the same matrix award for cooling as for heating. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + employment_income_before_lsr: 20_000 + person2: + age: 31 + person3: + age: 7 + person4: + age: 10 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + # Not receiving FITAP. + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 900 + has_cooling_expense: true + pre_subsidy_electricity_expense: 1_740 + households: + household: + members: [person1, person2, person3, person4] + state_code: LA + output: + # (900 + 1,740) / 20,000 = 0.132 -> band 2, sizes 4+; no member is in a + # priority group. + la_liheap: 400 + la_liheap_cooling: 400 + # The national LIHEAP total adds both seasons: 400 + 400. + liheap: 800 + +- name: Case 3, zero countable income with a young child receives the 800 maximum. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + self_employment_income: -3_000 + person2: + age: 34 + person3: + age: 4 + person4: + age: 8 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + tanf: 0 + heating_type: ELECTRICITY + has_cooling_expense: true + pre_subsidy_electricity_expense: 1_740 + households: + household: + members: [person1, person2, person3, person4] + state_code: LA + output: + # max(-3,000, 0) = 0 income -> band 4, sizes 4+: 700 + 100 for the + # four-year-old + la_liheap_cooling: 800 + +- name: Case 4, a household without cooling costs receives no cooling benefit. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + has_cooling_expense: false + pre_subsidy_electricity_expense: 1_740 + households: + household: + members: [person1] + state_code: LA + output: + # The electric heating bill qualifies the household for heating: + # 1,740 / 15,080 = 0.1154 -> band 2, size 1. + la_liheap: 350 + la_liheap_cooling: 0 + +- name: Case 5, income above the size-one limit receives no cooling benefit. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 32_000 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + has_cooling_expense: true + pre_subsidy_electricity_expense: 1_740 + households: + household: + members: [person1] + state_code: LA + output: + # 32,000 is above the FFY2026 size-one limit of 30,618 (60% SMI). + la_liheap_cooling: 0 + +- name: Case 6, an unspecified heating fuel receives the cooling benefit. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + has_cooling_expense: true + pre_subsidy_electricity_expense: 1_740 + households: + household: + members: [person1] + state_code: LA + output: + # Was 0, now 350: the cooling test no longer adds a heating-fuel + # condition, since no Louisiana cooling rule names a heating fuel. + # 1,740 / 15,080 = 0.1154 -> band 2, size 1, as in Case 1. + la_liheap_cooling: 350 + +- name: Case 7, a renter with utilities and heat included in the rent and an unspecified heating fuel receives both benefits. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 15_080 + # FY2026 HUD Fair Market Rent for a one-bedroom unit in East Baton + # Rouge Parish, 1,064 a month (x12 = 12,768). + rent: 12_768 + spm_units: + spm_unit: + members: [person1] + # The tenant does not know the building's heating fuel. + heating_type: UNSPECIFIED + heat_expense_included_in_rent: true + has_cooling_expense: false + pre_subsidy_electricity_expense: 0 + households: + household: + members: [person1] + state_code: LA + tenant_pays_utilities: false + output: + # No separate bill, so the energy cost is 0 and the burden 0 / 15,080 + # falls in the 9.9% and less band, 200 for size 1. Heating accepts the + # unspecified fuel because heat is included in the rent; cooling counts + # the energy costs included in the rent (Section 3.6 E.1). + la_liheap: 200 + la_liheap_cooling: 200 diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/cooling/la_liheap_cooling_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/cooling/la_liheap_cooling_eligible.yaml new file mode 100644 index 00000000000..d59b108ce1e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/cooling/la_liheap_cooling_eligible.yaml @@ -0,0 +1,155 @@ +# Service Delivery Guide effective April 1, 2026: the heating and cooling benefits +# share their requirements (Section 3.6, page 33), responsibility covers "heating and +# cooling costs" (Section 3.6 E, page 41), and a cooling utility allowance greater +# than the bill makes a subsidized household ineligible unless a member is 60 or +# older (Section 4.1 C, pages 46-47). Wages of 15,080 are full-time work at the +# federal 7.25 minimum wage, under the FFY2026 size-one limit of 30,618; electricity +# of 1,740 is 145 a month, near the EIA 2024 Louisiana average residential bill of +# 140.96 a month. + +- name: Case 1, a home with no heating is cooling eligible like a home with a known heating fuel. + period: 2026 + input: + state_code: [LA, LA] + age: [40, 40] + employment_income_before_lsr: [15_080, 15_080] + heating_type: [NONE, NATURAL_GAS] + gas_expense: [0, 900] + pre_subsidy_electricity_expense: [1_740, 1_740] + has_cooling_expense: [true, true] + output: + # Heating needs a heating fuel; cooling does not. + la_liheap_eligible: [false, true] + la_liheap_cooling_eligible: [true, true] + +- name: Case 2, a subsidized household is eligible only when its bill exceeds the utility allowance. + period: 2026 + input: + state_code: [LA, LA, LA] + age: [40, 40, 40] + employment_income_before_lsr: [15_080, 15_080, 15_080] + receives_housing_assistance: [true, true, true] + heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY] + pre_subsidy_electricity_expense: [1_740, 1_500, 1_740] + # Section 8 utility allowances of 100, 150 and 145 a month. + hud_utility_allowance: [1_200, 1_800, 1_740] + has_cooling_expense: [true, true, true] + output: + # Energy cost 1,740 - 1,200 = 540, 1,500 - 1,800 = -300 and 1,740 - 1,740 = 0; + # an allowance equal to the bill leaves no energy burden. + la_liheap_cooling_eligible: [true, false, false] + +- name: Case 3, a household of only undocumented members is ineligible. + period: 2026 + input: + state_code: [LA] + age: [40] + immigration_status: [UNDOCUMENTED] + employment_income_before_lsr: [15_080] + heating_type: [ELECTRICITY] + pre_subsidy_electricity_expense: [1_740] + has_cooling_expense: [true] + output: + # No counted member, so household size is 0. + la_liheap_cooling_eligible: [false] + +- name: Case 4, a renter with energy costs included in the rent is cooling eligible unless subsidized. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [LA, LA] + age: [40, 40] + employment_income_before_lsr: [15_080, 15_080] + heating_type: [ELECTRICITY, ELECTRICITY] + has_cooling_expense: [false, false] + pre_subsidy_electricity_expense: [0, 0] + # Both pay the FY2026 HUD Fair Market Rent for a one-bedroom unit in East Baton + # Rouge Parish, 1,064 a month (x12 = 12,768), which includes utilities. + tenant_pays_utilities: [false, false] + rent: [12_768, 12_768] + receives_housing_assistance: [false, true] + output: + # Section 3.6 E.1 counts energy costs included in the rent. With no separate + # bill the energy cost is 0. Reading Section 3.6 E.1's example of + # "Subsidized housing tenants who are responsible for and have incurred + # excess energy charges" as the heating test does, the subsidized renter has + # no excess energy charge and is not eligible. The unsubsidized renter's + # burden 0 / 15,080 falls in the 9.9% and less band, 200 for size 1. + la_liheap_cooling_eligible: [true, false] + la_liheap_cooling: [200, 0] + +- name: Case 5, a household of only undocumented members that passes the income test is ineligible. + period: 2026 + input: + state_code: [LA] + age: [40] + immigration_status: [UNDOCUMENTED] + # 20 hours a week at the federal 7.25 minimum wage. + employment_income_before_lsr: [7_540] + heating_type: [ELECTRICITY] + pre_subsidy_electricity_expense: [1_740] + has_cooling_expense: [true] + output: + # Household size 0 makes the 60% SMI limit 0, but 7,540 is below the 110% + # poverty floor of 1.1 x (15,650 - 5,500) = 11,165, so only the household + # size test fails: "A household with only ineligible aliens does not + # qualify for LIHEAP assistance." + la_liheap_income_eligible: [true] + la_liheap_cooling_eligible: [false] + +- name: Case 6, a household that pays no rent and does not pay its own utilities is ineligible. + period: 2026 + input: + state_code: [LA] + age: [40] + employment_income_before_lsr: [15_080] + heating_type: [ELECTRICITY] + has_cooling_expense: [false] + pre_subsidy_electricity_expense: [0] + # Lives rent-free in a relative's home, and the relative pays the utilities. + tenant_pays_utilities: [false] + rent: [0] + receives_housing_assistance: [false] + output: + # No cooling bill and no rent that includes energy costs, so the + # responsibility test fails. + la_liheap_cooling_eligible: [false] + +- name: Case 7, a public housing tenant whose utility allowance exceeds the bill is ineligible. + period: 2026 + input: + state_code: [LA] + age: [40] + employment_income_before_lsr: [15_080] + # Only public housing marks the household as subsidized. + receives_housing_assistance: [false] + is_in_public_housing: [true] + heating_type: [ELECTRICITY] + pre_subsidy_electricity_expense: [1_500] + # Utility allowance of 150 a month. + hud_utility_allowance: [1_800] + has_cooling_expense: [true] + output: + # Under 60, so the energy cost 1,500 - 1,800 = -300 is not positive. The + # income and responsibility tests pass, so only the subsidized energy cost + # test fails (Section 4.1 C.1). + la_liheap_cooling_eligible: [false] + +- name: Case 8, a renter who pays the utilities separately and has no cooling cost is ineligible. + period: 2026 + input: + state_code: [LA] + age: [40] + employment_income_before_lsr: [15_080] + heating_type: [ELECTRICITY] + has_cooling_expense: [false] + pre_subsidy_electricity_expense: [0] + # FY2026 HUD Fair Market Rent for a one-bedroom unit in East Baton Rouge + # Parish, 1,064 a month (x12 = 12,768), with utilities billed separately. + tenant_pays_utilities: [true] + rent: [12_768] + receives_housing_assistance: [false] + output: + # The rent does not include energy costs and there is no cooling cost, so + # the responsibility test fails; the household is not subsidized. + la_liheap_cooling_eligible: [false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/eligibility/la_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/eligibility/la_liheap_eligible.yaml index a76449f1d0d..00e7296f4f9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/eligibility/la_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/eligibility/la_liheap_eligible.yaml @@ -5,7 +5,8 @@ # is 60 or older (page 40). 42 U.S.C. 8624(b)(2)(B) protects income below 110% of # the poverty guideline (2025 guidelines in FFY2026: 15,650 + 5,500 per extra person). # Wages of 15,080 are full-time work at the federal 7.25 minimum wage; electricity of -# 1,740 is about the EIA 2024 Louisiana average residential bill of 145 a month. +# 1,740 is 145 a month, near the EIA 2024 Louisiana average residential bill of +# 140.96 a month. - name: Case 1, income exactly at the size-one limit is eligible. period: 2026 diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/eligibility/la_liheap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/eligibility/la_liheap_income_eligible.yaml new file mode 100644 index 00000000000..216b834d321 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/eligibility/la_liheap_income_eligible.yaml @@ -0,0 +1,23 @@ +# FY2026 plan Sections 2.1 and 3.1: income at or below 60% of state median income for +# heating and cooling (Notice LHP-2025-01: 30,618 for one person). 42 U.S.C. +# 8624(b)(2)(B) protects income below 110% of the poverty guideline (2025 guidelines +# in FFY2026: 15,650 + 5,500 per extra person). + +- name: Case 1, income at the size-one limit is eligible and one dollar above is not. + period: 2026 + input: + state_code: [LA, LA] + age: [40, 40] + employment_income_before_lsr: [30_618, 30_619] + output: + la_liheap_income_eligible: [true, false] + +- name: Case 2, the poverty floor protects a fourteen-person household below 110 percent of the guideline but not at it. + period: 2026 + input: + state_code: [LA, LA] + la_liheap_household_size: [14, 14] + # Limit 91,855; floor (15,650 + 5,500 x 13) x 1.1 = 95,865. + la_liheap_countable_income: [95_864, 95_865] + output: + la_liheap_income_eligible: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/income/la_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/income/la_liheap_countable_income.yaml index 4cc4bb37ac9..959458a18e4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/income/la_liheap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/income/la_liheap_countable_income.yaml @@ -5,8 +5,8 @@ # Only income of members 18 and older counts (page 29), except Social Security and # SSI paid to minors (Appendix E page 85; FAQ A4). # Wages of 15,080 are full-time work at the federal 7.25 minimum wage (2,080 hours), -# which Louisiana follows. Electricity of 1,740 is about the EIA 2024 Louisiana -# average residential bill of 145 a month. +# which Louisiana follows. Electricity of 1,740 is 145 a month, near the EIA 2024 +# Louisiana average residential bill of 140.96 a month. - name: Case 1, gross wages and business income count while business and rental losses are floored at zero. period: 2026 diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap.yaml index 216f29e828d..ffbdea60256 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap.yaml @@ -4,8 +4,8 @@ # One 100 supplement per household for a member 60 or older, disabled, or five or # younger. Zero income receives the maximum for the size (Service Delivery Guide # page 41). Wages of 15,080 are full-time work at the federal 7.25 minimum wage; -# electricity of 1,740 is about the EIA 2024 Louisiana average residential bill of -# 145 a month. +# electricity of 1,740 is 145 a month, near the EIA 2024 Louisiana average +# residential bill of 140.96 a month. - name: Case 1, burden just below 10 percent receives the lowest size-one award. period: 2026 diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap_energy_cost.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap_energy_cost.yaml index c9a3e90207a..6cde97ea90a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap_energy_cost.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap_energy_cost.yaml @@ -1,8 +1,9 @@ # Service Delivery Guide (rev. January 1, 2024) pages 37-40: residential energy bills # from every vendor are added; sewer and water fees are excluded; a subsidized # household subtracts its utility allowance (vendor costs - utility allowance = TEC), -# except applicants 60 or older. Electricity of 1,740 is about the EIA 2024 Louisiana -# average residential bill of 145 a month; gas of 600 is about 50 a month. +# except applicants 60 or older. Electricity of 1,740 is 145 a month, near the EIA +# 2024 Louisiana average residential bill of 140.96 a month; gas of 600 is about 50 +# a month. - name: Case 1, energy bills from all vendors are added, water and sewer are excluded, and no allowance is deducted without housing assistance. period: 2026 diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap_matrix_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap_matrix_amount.yaml new file mode 100644 index 00000000000..80bd9ec6e18 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/la/lhc/liheap/la_liheap_matrix_amount.yaml @@ -0,0 +1,23 @@ +# FFY2026 Heating and Cooling Benefit Matrix award, computed for every Louisiana unit +# and paid by la_liheap and la_liheap_cooling to their eligible households. Wages of +# 15,080 are full-time work at the federal 7.25 minimum wage; electricity of 1,740 is +# 145 a month, near the EIA 2024 Louisiana average residential bill of 140.96 a month. + +- name: Case 1, the matrix amount does not depend on heating eligibility and a negative energy cost takes the lowest band. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [LA, LA] + age: [40, 40] + employment_income_before_lsr: [15_080, 15_080] + heating_type: [NONE, ELECTRICITY] + receives_housing_assistance: [false, true] + pre_subsidy_electricity_expense: [1_740, 1_500] + hud_utility_allowance: [0, 1_800] + output: + # 1,740 / 15,080 = 0.1154 -> band 2, size 1: 350, though a home with no + # heating is not heating eligible. 1,500 - 1,800 = -300 energy cost, + # floored at 0 -> band 1, size 1: 200, though the subsidized household is + # ineligible. + la_liheap_matrix_amount: [350, 200] + la_liheap: [0, 0] diff --git a/policyengine_us/variables/gov/states/la/lhc/liheap/cooling/la_liheap_cooling.py b/policyengine_us/variables/gov/states/la/lhc/liheap/cooling/la_liheap_cooling.py new file mode 100644 index 00000000000..cb853e57b6f --- /dev/null +++ b/policyengine_us/variables/gov/states/la/lhc/liheap/cooling/la_liheap_cooling.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class la_liheap_cooling(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Louisiana LIHEAP regular cooling assistance" + defined_for = "la_liheap_cooling_eligible" + reference = ( + "https://liheapch.acf.gov/docs/2026/benefits-matricies/LA_BenefitMatrix_Heat-Cool_2026.pdf", + # PDF pages 43-44, 48 + "https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20FINAL%20-%20Effective%20April%201%2c%202026.pdf#page=43", + # PDF pages 4, 12 + "https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=4", + ) + # Section 4.2 B allows "one Heating and one Cooling LIHEAP benefit each + # Program year", both from the Heating and Cooling Benefit Matrix, with no + # bill cap. Annual bills stand in for the cooling-season bill, so the + # burden band is the one heating uses. Supplemental cooling payments + # depend on available funds and are not modeled. + adds = ["la_liheap_matrix_amount"] diff --git a/policyengine_us/variables/gov/states/la/lhc/liheap/cooling/la_liheap_cooling_eligible.py b/policyengine_us/variables/gov/states/la/lhc/liheap/cooling/la_liheap_cooling_eligible.py new file mode 100644 index 00000000000..0aedb0f68b5 --- /dev/null +++ b/policyengine_us/variables/gov/states/la/lhc/liheap/cooling/la_liheap_cooling_eligible.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * + + +class la_liheap_cooling_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Louisiana LIHEAP regular cooling eligibility" + defined_for = StateCode.LA + reference = ( + # PDF pages 33, 41, 43, 46-47 + "https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20FINAL%20-%20Effective%20April%201%2c%202026.pdf#page=33", + # PDF pages 11-12 + "https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=11", + ) + + def formula(spm_unit, period, parameters): + size = spm_unit("la_liheap_household_size", period) + income_eligible = spm_unit("la_liheap_income_eligible", period) + # Vulnerability: responsibility for heating and cooling costs, or energy + # costs included in the rent (Section 3.6 E; plan section 3.3). + # Requiring has_cooling_expense from a household that pays its own + # bills is a PolicyEngine convention of the cooling programs; no + # Louisiana text asks for a cost separate from the energy bill. + 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 + # As for heating, a subsidized household needs a positive total energy + # cost: a cooling utility allowance greater than the bill makes it + # ineligible (Section 4.1 C.1), and an allowance equal to the bill + # leaves no excess energy charge (Section 3.6 E.1). + subsidized = spm_unit("receives_housing_assistance", period) | ( + spm_unit.household("is_in_public_housing", period) + ) + energy_cost_eligible = ~subsidized | ( + spm_unit("la_liheap_energy_cost", period) > 0 + ) + # The cooling requirements name no heating fuel (Section 3.6), so + # heating_type, including UNSPECIFIED, does not affect eligibility. + return (size > 0) & income_eligible & responsible & energy_cost_eligible diff --git a/policyengine_us/variables/gov/states/la/lhc/liheap/eligibility/la_liheap_eligible.py b/policyengine_us/variables/gov/states/la/lhc/liheap/eligibility/la_liheap_eligible.py index 58f9d8d1421..cbddd213186 100644 --- a/policyengine_us/variables/gov/states/la/lhc/liheap/eligibility/la_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/la/lhc/liheap/eligibility/la_liheap_eligible.py @@ -1,5 +1,4 @@ from policyengine_us.model_api import * -from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class la_liheap_eligible(Variable): @@ -15,22 +14,11 @@ class la_liheap_eligible(Variable): "https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20FINAL%20-%20Effective%20April%201%2c%202026.pdf#page=39", # PDF pages 9-10 "https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=9", - "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", ) def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.la.lhc.liheap.eligibility - p_hhs = parameters(period).gov.hhs.liheap size = spm_unit("la_liheap_household_size", period) - income = spm_unit("la_liheap_countable_income", period) - limit = spm_unit("la_liheap_income_limit", period) - # 42 U.S.C. 8624(b)(2)(B) bars excluding a household on income below 110% - # of the poverty guideline. The 60% SMI limit falls below that floor from - # household size 14 in FY2026 (91,855 against 95,865). - state_group = spm_unit.household("state_group_str", period) - guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) - floor = np.round(guideline * p_hhs.fpg_floor, 2) - income_eligible = (income <= limit) | (income < floor) + income_eligible = spm_unit("la_liheap_income_eligible", period) # Vulnerability: responsibility for a heating bill or heat included in # the rent. heat_in_rent = spm_unit("heat_expense_included_in_rent", period) diff --git a/policyengine_us/variables/gov/states/la/lhc/liheap/eligibility/la_liheap_income_eligible.py b/policyengine_us/variables/gov/states/la/lhc/liheap/eligibility/la_liheap_income_eligible.py new file mode 100644 index 00000000000..440bfadbf44 --- /dev/null +++ b/policyengine_us/variables/gov/states/la/lhc/liheap/eligibility/la_liheap_income_eligible.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class la_liheap_income_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Louisiana LIHEAP income eligible" + defined_for = StateCode.LA + reference = ( + "https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20REVISED%20January%201_%202024.pdf#page=29", + "https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20FINAL%20-%20Effective%20April%201%2c%202026.pdf#page=34", + # PDF pages 9, 11 + "https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=9", + "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.la.lhc.liheap.eligibility + p_hhs = parameters(period).gov.hhs.liheap + size = spm_unit("la_liheap_household_size", period) + income = spm_unit("la_liheap_countable_income", period) + limit = spm_unit("la_liheap_income_limit", period) + # 42 U.S.C. 8624(b)(2)(B) bars excluding a household on income below 110% + # of the poverty guideline. The 60% SMI limit falls below that floor from + # household size 14 in FY2026 (91,855 against 95,865). + state_group = spm_unit.household("state_group_str", period) + guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + floor = np.round(guideline * p_hhs.fpg_floor, 2) + return (income <= limit) | (income < floor) diff --git a/policyengine_us/variables/gov/states/la/lhc/liheap/la_liheap.py b/policyengine_us/variables/gov/states/la/lhc/liheap/la_liheap.py index 724334591cd..26936e3744f 100644 --- a/policyengine_us/variables/gov/states/la/lhc/liheap/la_liheap.py +++ b/policyengine_us/variables/gov/states/la/lhc/liheap/la_liheap.py @@ -14,11 +14,9 @@ class la_liheap(Variable): "supplement, whose disability group also covers Social Security " "disability benefits and SSI receipt. Verified for FY2026; earlier " "and later years are unverified estimates through " - "parameter backfilling. Louisiana also pays a separate summer cooling " - "award from the same matrix, with 45.5% of FY2026 funds against 25% for " - "heating, so program-year regular assistance can be twice this amount; " - "the cooling award, crisis assistance and weatherization are out of " - "scope." + "parameter backfilling. Louisiana also pays one regular cooling-season " + "benefit each program year from the same matrix, la_liheap_cooling; " + "crisis assistance and weatherization are out of scope." ) defined_for = "la_liheap_eligible" reference = ( @@ -27,54 +25,6 @@ class la_liheap(Variable): "https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20FINAL%20-%20Effective%20April%201%2c%202026.pdf#page=48", "https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=10", ) - - def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.la.lhc.liheap - income = spm_unit("la_liheap_countable_income", period) - # NOTE: the formula also runs for ineligible units, whose energy cost can - # be negative; the floor keeps their burden band inside the matrix. - energy_cost = max_(spm_unit("la_liheap_energy_cost", period), 0) - # Annual cost over annual income stands in for the application-month - # bill over 30-day income. Heat included in unsubsidized rent counts - # only separately billed energy, so its band is a lower bound. - has_income = income > 0 - burden = np.divide( - energy_cost, - income, - out=np.zeros_like(energy_cost), - where=has_income, - ) - burden_band = p.payment.burden_band - # Households with zero income receive the maximum benefit for their - # size, the top burden band. - band = where(has_income, burden_band.calc(burden), burden_band.amounts[-1]) - size = spm_unit("la_liheap_household_size", period) - size_group = p.payment.size_group.calc(size) - base = p.payment.amount[band][size_group] - person = spm_unit.members - age = person("age", period) - # Section 4.2 A accepts proof of disability from the Social Security - # Administration, so Social Security disability benefits and SSI receipt - # also place a member in the group: SSI goes only to people who are aged - # (65 or older), blind or disabled, and aged recipients already qualify - # by age. - receives_ssi = (add(person, period, ["ssi"]) > 0) | ( - add(person, period, ["receives_ssi"]) > 0 - ) - disabled = ( - person("is_disabled", period) - | (person("social_security_disability", period) > 0) - | receives_ssi - ) - priority_group = ( - (age >= p.elderly_age) - | disabled - | (age < p.payment.young_child_max_age + 1) - ) - priority_member = person("is_citizen_or_legal_immigrant", period) & ( - priority_group - ) - supplement = spm_unit.any(priority_member) * p.payment.priority_supplement - # One award covers the heating season, with no bill cap. Supplemental - # heating payments depend on available funds and are not modeled. - return base + supplement + # One award covers the heating season, with no bill cap. Supplemental + # heating payments depend on available funds and are not modeled. + adds = ["la_liheap_matrix_amount"] diff --git a/policyengine_us/variables/gov/states/la/lhc/liheap/la_liheap_matrix_amount.py b/policyengine_us/variables/gov/states/la/lhc/liheap/la_liheap_matrix_amount.py new file mode 100644 index 00000000000..bfd40618ac6 --- /dev/null +++ b/policyengine_us/variables/gov/states/la/lhc/liheap/la_liheap_matrix_amount.py @@ -0,0 +1,75 @@ +from policyengine_us.model_api import * + + +class la_liheap_matrix_amount(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Louisiana LIHEAP heating and cooling matrix amount" + documentation = ( + "The award from the FFY2026 Heating and Cooling Benefit Matrix: an " + "amount by energy burden, on a total-energy-cost basis, and household " + "size, plus one priority group supplement, whose disability group also " + "covers Social Security disability benefits and SSI receipt. The " + "heating and cooling benefits each pay this amount to eligible " + "households." + ) + defined_for = StateCode.LA + reference = ( + "https://liheapch.acf.gov/docs/2026/benefits-matricies/LA_BenefitMatrix_Heat-Cool_2026.pdf", + "https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20REVISED%20January%201_%202024.pdf#page=41", + "https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20FINAL%20-%20Effective%20April%201%2c%202026.pdf#page=48", + # PDF pages 10, 12 + "https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=10", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.la.lhc.liheap + income = spm_unit("la_liheap_countable_income", period) + # NOTE: the formula also runs for ineligible units, whose energy cost can + # be negative; the floor keeps their burden band inside the matrix. + energy_cost = max_(spm_unit("la_liheap_energy_cost", period), 0) + # Annual cost over annual income stands in for the application-month + # bill over 30-day income. Heat included in unsubsidized rent counts + # only separately billed energy, so its band is a lower bound. + has_income = income > 0 + burden = np.divide( + energy_cost, + income, + out=np.zeros_like(energy_cost), + where=has_income, + ) + burden_band = p.payment.burden_band + # Households with zero income receive the maximum benefit for their + # size, the top burden band. + band = where(has_income, burden_band.calc(burden), burden_band.amounts[-1]) + size = spm_unit("la_liheap_household_size", period) + size_group = p.payment.size_group.calc(size) + base = p.payment.amount[band][size_group] + person = spm_unit.members + age = person("age", period) + # Section 4.2 A accepts proof of disability from the Social Security + # Administration, so Social Security disability benefits and SSI receipt + # also place a member in the group: SSI goes only to people who are aged + # (65 or older), blind or disabled, and aged recipients already qualify + # by age. + receives_ssi = (add(person, period, ["ssi"]) > 0) | ( + add(person, period, ["receives_ssi"]) > 0 + ) + disabled = ( + person("is_disabled", period) + | (person("social_security_disability", period) > 0) + | receives_ssi + ) + priority_group = ( + (age >= p.elderly_age) + | disabled + | (age < p.payment.young_child_max_age + 1) + ) + priority_member = person("is_citizen_or_legal_immigrant", period) & ( + priority_group + ) + supplement = spm_unit.any(priority_member) * p.payment.priority_supplement + # The matrix has no bill cap. + return base + supplement diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 352bbc3a578..dcd60a5c76c 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -4668,21 +4668,26 @@ candidates: - kind: manual citation: Louisiana LIHEAP Service Delivery Guide (revised January 1, 2024), Section 4.1 C, PDF page 40 url: https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20REVISED%20January%201_%202024.pdf#page=40 + - kind: manual + citation: Louisiana LIHEAP Service Delivery Guide (effective April 1, 2026), Section 4.1 C.1, PDF page 46 + url: https://www.lhc.la.gov/hubfs/Document%20Libraries/Energy%20Assistance/Louisiana%20LIHEAP%20Service%20Delivery%20Guide%20-%20FINAL%20-%20Effective%20April%201%2c%202026.pdf#page=46 - kind: plan - citation: FY2026 LIHEAP State Plan §2.3, page 9 + citation: FY2026 LIHEAP State Plan §§2.3 and 3.3, pages 9 and 11 url: https://liheapch.acf.gov/docs/2026/state-plans/LA_Plan_2026.pdf#page=9 readings: statute: No statute is supplied; the guide exempts applicants 60 or older. - other: Plan 2.3 exempts applicants over 60. + other: Plan items 2.3 (heating) and 3.3 (cooling) exempt applicants over 60. example: A subsidized 60-year-old with a $1,500 bill and $1,800 allowance has a total energy cost of $1,500 and is eligible under the guide; under the plan it is -$300 and ineligible. pe_us: follows: gap-fill code: - policyengine_us/variables/gov/states/la/lhc/liheap/la_liheap_energy_cost.py + - policyengine_us/variables/gov/states/la/lhc/liheap/cooling/la_liheap_cooling_eligible.py - policyengine_us/parameters/gov/states/la/lhc/liheap/elderly_age.yaml prs: - https://github.com/PolicyEngine/policyengine-us/pull/10429 + - https://github.com/PolicyEngine/policyengine-us/pull/10750 state: ruled note: 'Ruled 2026-10-06: follow the manual over the plan.' - id: us-la:school-readiness-incapable-child