Skip to content
Merged
1 change: 1 addition & 0 deletions changelog.d/liheap-fpg-floor-in-md-riv.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Apply the federal 110% poverty guideline floor to Indiana EAP, Maryland MEAP and Riverside County LIHEAP income eligibility.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
description: Riverside County uses the poverty guidelines from this many years before the model year for the federal income floor under the Low Income Home Energy Assistance Program.
# HHS makes each January's guidelines mandatory for LIHEAP from the next
# October 1, so model period 2025 (FY2025) uses the 2024 guidelines and 2026
# (FY2026) the 2025 guidelines. The county's own limit uses state median
# income.
values:
2021-10-01: 1
metadata:
unit: year
period: year
label: Riverside County LIHEAP poverty guideline year lag
reference:
- title: LIHEAP Information Memoranda, annual poverty guideline memoranda
href: https://acf.gov/ocs/policy-guidance/liheap-information-memoranda
- title: LIHEAP IM 2024-02, Attachment 2, poverty guidelines for mandatory use in FY25
href: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM%202024-02_Att2FPGTables_States.pdf#page=1
- title: LIHEAP IM 2025-02, Attachment 2, poverty guidelines for mandatory use in FY26
href: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_FPGSte-Table_Att2.pdf#page=1
- title: LIHEAP IM 2026-01, poverty guidelines for optional use in FY26 and mandatory use in FY27
href: https://acf.gov/ocs/policy-guidance/liheap-im2026-01-federal-poverty-guidelines-fpg-and-state-median-income-smi
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
description: Indiana uses the poverty guidelines from this many years before the model year for the federal income floor under the Low Income Home Energy Assistance Program.
# HHS makes each January's guidelines mandatory for LIHEAP from the next
# October 1, so model period 2025 (PY2025) uses the 2024 guidelines and 2026
# (PY2026) the 2025 guidelines. Indiana's own limit uses state median income.
values:
2024-10-01: 1
metadata:
unit: year
period: year
label: Indiana EAP poverty guideline year lag
reference:
- title: LIHEAP IM 2024-02, Attachment 2, poverty guidelines for mandatory use in FY25
href: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM%202024-02_Att2FPGTables_States.pdf#page=1
- title: LIHEAP IM 2025-02, Attachment 2, poverty guidelines for mandatory use in FY26
href: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_FPGSte-Table_Att2.pdf#page=1
- title: LIHEAP IM 2026-01, poverty guidelines for optional use in FY26 and mandatory use in FY27
href: https://acf.gov/ocs/policy-guidance/liheap-im2026-01-federal-poverty-guidelines-fpg-and-state-median-income-smi
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,50 @@
output:
hhs_smi: 103_856
ca_riv_liheap_eligible: false

- name: Case 3, federal 110% poverty floor above the 60% state median income limit at size 21.
period: 2026
input:
state_code: [CA, CA, CA, CA, CA]
in_riv: [true, true, true, true, true]
spm_unit_size: [21, 21, 21, 21, 20]
ca_riv_liheap_countable_income: [136_000, 138_214.99, 138_215, 138_216, 133_800]
output:
# 42 U.S.C. 8624(b)(2)(B) bars excluding a household on income below 110%
# of the poverty guideline. FY2026 uses the 2025 guidelines (LIHEAP IM
# 2025-02): 15,650 + 5,500 x 20 = 125,650 for 21 people, and 110% is
# 138,215. The 60% SMI limit for 21 people is 136,088.93.
# Household 1 is below the 60% SMI limit: eligible.
# Household 2 is one cent below the floor: eligible.
# Household 3 is exactly at the floor, which is not below 110%: not eligible.
# Household 4 is above the floor: not eligible.
# Household 5 has 20 people, whose 133,782.34 limit exceeds the 132,165
# floor (110% of 120,150), so the limit still applies: not eligible.
ca_riv_liheap_eligible: [true, true, false, false, false]

- name: Case 4, the floor uses the poverty guidelines from the year before the model year.
period: 2026
input:
state_code: CA
in_riv: true
spm_unit_size: 21
ca_riv_liheap_countable_income: 140_000
output:
# FY2026 uses the 2025 guidelines, so the floor is 138,215. The 2026
# guidelines would give 110% x (15,960 + 5,680 x 20) = 142,516.
ca_riv_liheap_eligible: false

- name: Case 5, FY2025 uses the 2024 poverty guidelines for the floor.
period: 2025
input:
state_code: [CA, CA]
in_riv: [true, true]
spm_unit_size: [20, 20]
ca_riv_liheap_countable_income: [129_007.99, 129_008]
output:
# LIHEAP IM 2024-02 makes the 2024 guidelines mandatory in FY2025:
# 110% x (15,060 + 5,380 x 19) = 129,008 for 20 people, above the
# 127,290.74 FY2025 60% SMI limit. The 2025 CSD table (Final Plan PDF page
# 180) prints a monthly top of 10,607.47 for 20 people, also below the
# 10,750.67 monthly floor.
ca_riv_liheap_eligible: [true, false]
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,27 @@
output:
in_eap_income: [15_080, 15_080, 15_080]
in_eap: [125, 125, 175]
- name: Case 17, a household that qualifies only through the federal 110% poverty floor receives the highest-income award.
period: 2026
input:
state_code: [IN, IN]
age: [40, 40]
ssi: [0, 0]
social_security: [0, 0]
receives_ssi: [false, false]
receives_medicaid: [false, false]
rent: [0, 0]
in_eap_household_size: [16, 16]
in_eap_income: [106_000, 107_965]
heating_type: [NATURAL_GAS, NATURAL_GAS]
gas_expense: [1_000, 1_000]
pre_subsidy_electricity_expense: [1_000, 1_000]
output:
# Both incomes exceed the 104,543 size-16 limit. Household 1 is below the
# 107,965 floor (110% of the 2025 guideline of 98,150) and qualifies under
# 42 U.S.C. 8624(b)(2)(B). Household 2 is at the floor and does not qualify.
in_eap_eligible: [true, false]
# Household 1 is above the middle income band: 2 income points + 3
# single-family points + 1 natural gas point = 6 x $25 = $150, plus the
# $50 higher-income electric allowance.
in_eap: [200, 0]
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,45 @@
in_eap_income: 74_640
in_eap_eligible: false
in_eap: 0
- name: Case 6, federal 110% poverty floor above the 60% state median income limit at size 16.
period: 2026
input:
state_code: [IN, IN, IN, IN, IN]
age: [40, 40, 40, 40, 40]
in_eap_household_size: [16, 16, 16, 16, 15]
in_eap_income: [104_543, 107_964.99, 107_965, 107_966, 102_608]
output:
# 42 U.S.C. 8624(b)(2)(B) bars excluding a household on income below 110%
# of the poverty guideline. PY2026 uses the 2025 guidelines (LIHEAP IM
# 2025-02): 15,650 + 5,500 x 15 = 98,150 for 16 people, and 110% is
# 107,965. The 60% SMI limit for 16 people is 104,543.
# Household 1 is at the 60% SMI limit: eligible.
# Household 2 is one cent below the floor: eligible.
# Household 3 is exactly at the floor, which is not below 110%: not eligible.
# Household 4 is above the floor: not eligible.
# Household 5 has 15 people, whose 102,607 limit exceeds the 101,915 floor
# (110% of 92,650), so the limit still applies: not eligible.
in_eap_eligible: [true, true, false, false, false]
- name: Case 7, the floor uses the poverty guidelines from the year before the model year.
period: 2026
input:
state_code: IN
age: 40
in_eap_household_size: 16
in_eap_income: 110_000
output:
# PY2026 uses the 2025 guidelines, so the floor is 107,965. The 2026
# guidelines would give 110% x (15,960 + 5,680 x 15) = 111,276.
in_eap_eligible: false
- name: Case 8, PY2025 uses the 2024 poverty guidelines for the floor.
period: 2025
input:
state_code: [IN, IN]
age: [40, 40]
in_eap_household_size: [15, 15]
in_eap_income: [99_417.99, 99_418]
output:
# LIHEAP IM 2024-02 makes the 2024 guidelines mandatory in FY2025:
# 110% x (15,060 + 5,380 x 14) = 99,418 for 15 people, above the 98,571
# PY2025 60% SMI limit.
in_eap_eligible: [true, false]
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,53 @@
# row ACF LIHEAP IM 2025-02 Attachment 4 (page 5) prints. $135,931 is over the
# limit although it is below 200% of the eleven-person guideline ($141,300).
md_meap_eligible: [true, false]

- name: Case 8, federal 110% poverty floor above the 60% state median income limit at size 29.
period: 2026
input:
state_code: [MD, MD, MD, MD, MD]
heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS]
gas_expense: [1_150, 1_150, 1_150, 1_150, 1_150]
md_meap_household_size: [29, 29, 29, 29, 28]
md_meap_countable_income: [185_864, 186_614.99, 186_615, 186_616, 183_091]
md_meap_categorically_eligible: [false, false, false, false, false]
output:
# 42 U.S.C. 8624(b)(2)(B) bars excluding a household on income below 110%
# of the poverty guideline. FY26 uses the 2025 guidelines (md_meap_fpg):
# 15,650 + 5,500 x 28 = 169,650 for 29 people, and 110% is 186,615. The
# 60% SMI limit for 29 people is 185,864.
# Household 1 is at the 60% SMI limit: eligible.
# Household 2 is one cent below the floor: eligible.
# Household 3 is exactly at the floor, which is not below 110%: not eligible.
# Household 4 is above the floor: not eligible.
# Household 5 has 28 people, whose 183,090 limit exceeds the 180,565 floor
# (110% of 164,150), so the limit still applies: not eligible.
md_meap_eligible: [true, true, false, false, false]

- name: Case 9, the floor uses the poverty guidelines from the year before the model year.
period: 2026
input:
state_code: MD
heating_type: NATURAL_GAS
gas_expense: 1_150
md_meap_household_size: 29
md_meap_countable_income: 190_000
md_meap_categorically_eligible: false
output:
# FY26 uses the 2025 guidelines, so the floor is 186,615. The 2026
# guidelines would give 110% x (15,960 + 5,680 x 28) = 192,500.
md_meap_eligible: false

- name: Case 10, FY25 uses the 2024 poverty guidelines for the floor.
period: 2025
input:
state_code: [MD, MD]
heating_type: [NATURAL_GAS, NATURAL_GAS]
gas_expense: [1_150, 1_150]
md_meap_household_size: [29, 29]
md_meap_countable_income: [182_269.99, 182_270]
md_meap_categorically_eligible: [false, false]
output:
# 110% x (15,060 + 5,380 x 28) = 182,270 for 29 people, above the 179,993
# FY25 60% SMI limit.
md_meap_eligible: [true, false]
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,21 @@
# the plan's multiplier.
# Oil, Level 7: the $25 nominal grant, printed $25.
md_meap: [110, 732, 391, 1_078, 25]

- name: Case 15, a household that qualifies only through the federal 110% poverty floor is paid at its poverty level.
period: 2026
input:
state_code: [MD, MD]
heating_type: [NATURAL_GAS, NATURAL_GAS]
gas_expense: [1_150, 1_150]
md_meap_household_size: [29, 29]
md_meap_countable_income: [186_000, 186_615]
md_meap_categorically_eligible: [false, false]
output:
# Both incomes exceed the 185,864 size-29 limit. Household 1 is below the
# 186,615 floor (110% of the 2025 guideline of 169,650) and qualifies under
# 42 U.S.C. 8624(b)(2)(B). Household 2 is at the floor and does not qualify.
md_meap_eligible: [true, false]
# 186,000 / 169,650 = 109.6% of the guideline, Level 4 (over 100% to 150%).
# The matrix pays $360 for gas at Level 4.
md_meap: [360, 0]
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from policyengine_us.model_api import *
from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg


class ca_riv_liheap_eligible(Variable):
Expand All @@ -7,12 +8,31 @@ class ca_riv_liheap_eligible(Variable):
label = "Eligible for the California Riverside County LIHEAP"
definition_period = YEAR
defined_for = "in_riv"
reference = "https://capriverside.org/utility-assistance-program"
reference = (
"https://capriverside.org/utility-assistance-program",
# 2025 HEAP and Fast Track payment table (PDF page 180).
"https://www.csd.ca.gov/Shared%20Documents/2025-Final-LIHEAP-State-Plan.pdf#page=180",
# 2026 HEAP and Fast Track payment table (PDF page 184).
"https://www.csd.ca.gov/Shared%20Documents/2026-Final-LIHEAP-State-Plan.pdf#page=184",
"https://www.law.cornell.edu/uscode/text/42/8624",
)

def formula(spm_unit, period, parameters):
p = parameters(period).gov.hhs.liheap
p_riv = parameters(period).gov.local.ca.riv.cap.liheap
state_median_income = spm_unit("hhs_smi", period)
# The income concept is not clearly defined, assuming IRS gross income
countable_income = spm_unit("ca_riv_liheap_countable_income", period)
smi_limit = state_median_income * p.smi_limit
return countable_income <= smi_limit
# 42 U.S.C. 8624(b)(2)(B) bars excluding a household on income below 110%
# of the poverty guideline. California's printed CSD tables fall below
# that floor at sizes 20 to 25 in 2025 and 21 to 25 in 2026, and the
# modeled 60% SMI limit does so from size 20 in 2025 and size 21 in
# 2026 and 2027.
size = spm_unit("spm_unit_size", period)
state_group = spm_unit.household("state_group_str", period)
guideline = fpg(
size, state_group, period, parameters, year_lag=p_riv.fpg_year_lag
)
floor = np.round(guideline * p.fpg_floor, 2)
return (countable_income <= smi_limit) | (countable_income < floor)
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from policyengine_us.model_api import *
from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg


class in_eap_eligible(Variable):
Expand All @@ -11,18 +12,29 @@ class in_eap_eligible(Variable):
# Section 3.1 (page 23), Section 4.4 (page 29), Section 8.3 (pages 69-70) and
# Section 8.8 (pages 73-75).
"https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23",
"https://www.law.cornell.edu/uscode/text/42/8624",
)

def formula(spm_unit, period, parameters):
p = parameters(period).gov.states["in"].ihcda.eap
income = spm_unit("in_eap_income", period)
limit = np.floor(spm_unit("in_eap_smi", period) * p.eligibility.income_limit)
# 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 15 in PY2025 and size 16 in PY2026 and PY2027.
p_hhs = parameters(period).gov.hhs.liheap
size = spm_unit("in_eap_household_size", period)
state_group = spm_unit.household("state_group_str", period)
guideline = fpg(
size, state_group, period, parameters, year_lag=p.eligibility.fpg_year_lag
)
floor = np.round(guideline * p_hhs.fpg_floor, 2)
# Section 4.4 permits an ineligible adult to apply for eligible household members.
# Emancipated minors, residency duration, eviction writs, SSNs, and sanctions
# cannot be determined here. Section 8.8 separates household eligibility from
# whether each utility can receive a benefit; burden is checked in in_eap.
return (
(add(spm_unit, period, ["is_citizen_or_legal_immigrant"]) > 0)
& spm_unit.any(spm_unit.members("age", period) >= p.eligibility.adult_age)
& (income <= limit)
& ((income <= limit) | (income < floor))
)
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class md_meap_eligible(Variable):
"https://regs.maryland.gov/us/md/exec/comar/07.03.21.06",
# PDF pages 11, 12, 16, 38, 39, 108.
"https://dhs.maryland.gov/documents/OHEP/OHEP-Operations-Manual.pdf#page=11",
"https://www.law.cornell.edu/uscode/text/42/8624",
)
documentation = (
"Regular heating has no resource test. Application documentation, emancipation "
Expand All @@ -28,11 +29,19 @@ def formula(spm_unit, period, parameters):
subsidized = spm_unit(
"receives_housing_assistance", period
) | spm_unit.household("is_in_public_housing", period)
income = spm_unit("md_meap_countable_income", 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 29 in FY2025 to FY2027. md_meap_fpg already uses the
# guideline of the calendar year before the model year.
p_hhs = parameters(period).gov.hhs.liheap
floor = np.round(spm_unit("md_meap_fpg", period) * p_hhs.fpg_floor, 2)
# Manual page 38: categorical eligibility waives the income test but
# not the other denials.
income_eligible = spm_unit("md_meap_categorically_eligible", period) | (
spm_unit("md_meap_countable_income", period)
<= spm_unit("md_meap_income_limit", period)
income_eligible = (
spm_unit("md_meap_categorically_eligible", period)
| (income <= spm_unit("md_meap_income_limit", period))
| (income < floor)
)
# Manual page 108: the household must have at least one eligible
# (citizen or qualified alien) member.
Expand Down
Loading