From cf90d40e345842036082041bc7370521577054ed Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Mon, 19 Oct 2026 11:44:11 -0400 Subject: [PATCH 1/7] Apply the federal 110% poverty floor to MS and OR LIHEAP 42 U.S.C. 8624(b)(2)(B) bars a state from excluding a household solely on income below 110% of the poverty level. The 60% SMI limit falls below that floor in Mississippi from household size 11 (FY2026-FY2027) and in Oregon from size 19 (PY2025) or 20 (PY2026-PY2027). Both eligibility tests now accept income below 110% of the poverty guideline that HHS makes mandatory on October 1 of the program year (one-year lag). Adds gov.hhs.liheap.fpg_floor, identical to the file in #9968 and #9969, plus a poverty guideline year lag for each state. Co-Authored-By: Claude Opus 5.5 --- changelog.d/liheap-federal-fpg-floor.fixed.md | 1 + .../parameters/gov/hhs/liheap/fpg_floor.yaml | 11 ++++ .../states/ms/mdhs/liheap/fpg_year_lag.yaml | 15 +++++ .../ohcs/liheap/eligibility/fpg_year_lag.yaml | 18 ++++++ .../ms/mdhs/liheap/ms_liheap_eligible.yaml | 48 +++++++++++++++ .../eligibility/or_liheap_eligible.yaml | 59 +++++++++++++++++++ .../ms/mdhs/liheap/ms_liheap_eligible.py | 14 ++++- .../liheap/eligibility/or_liheap_eligible.py | 19 ++++-- 8 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 changelog.d/liheap-federal-fpg-floor.fixed.md create mode 100644 policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml create mode 100644 policyengine_us/parameters/gov/states/ms/mdhs/liheap/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/or/ohcs/liheap/eligibility/fpg_year_lag.yaml diff --git a/changelog.d/liheap-federal-fpg-floor.fixed.md b/changelog.d/liheap-federal-fpg-floor.fixed.md new file mode 100644 index 00000000000..93fe85c2deb --- /dev/null +++ b/changelog.d/liheap-federal-fpg-floor.fixed.md @@ -0,0 +1 @@ +Apply the federal 110% poverty guideline floor to Mississippi and Oregon LIHEAP income eligibility. diff --git a/policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml b/policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml new file mode 100644 index 00000000000..ae7cb296211 --- /dev/null +++ b/policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml @@ -0,0 +1,11 @@ +description: The US Department of Health and Human Services limits income-based exclusion to households with income of at least this percentage of the poverty guideline under the Low Income Home Energy Assistance Program. +# Pub. L. 98-558, section 605(a)(2), added the floor for fiscal year 1986 and later. +values: + 1985-10-01: 1.1 +metadata: + period: year + unit: /1 + label: LIHEAP poverty guideline income floor + reference: + - title: 42 U.S.C. 8624(b)(2)(B) + href: https://www.law.cornell.edu/uscode/text/42/8624 diff --git a/policyengine_us/parameters/gov/states/ms/mdhs/liheap/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/ms/mdhs/liheap/fpg_year_lag.yaml new file mode 100644 index 00000000000..6bc3c65113b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ms/mdhs/liheap/fpg_year_lag.yaml @@ -0,0 +1,15 @@ +description: Mississippi 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 2026 (FY2026) uses the 2025 guidelines and 2027 +# (FY2027) the 2026 guidelines. Mississippi's own limit uses state median income. +values: + 2025-10-01: 1 +metadata: + unit: year + period: year + label: Mississippi LIHEAP poverty guideline year lag + reference: + - 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 diff --git a/policyengine_us/parameters/gov/states/or/ohcs/liheap/eligibility/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/or/ohcs/liheap/eligibility/fpg_year_lag.yaml new file mode 100644 index 00000000000..d5bc8654377 --- /dev/null +++ b/policyengine_us/parameters/gov/states/or/ohcs/liheap/eligibility/fpg_year_lag.yaml @@ -0,0 +1,18 @@ +description: Oregon 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, 2026 +# (PY2026) the 2025 guidelines and 2027 (PY2027) the 2026 guidelines. Oregon's +# own limit uses state median income. +values: + 2024-10-01: 1 +metadata: + unit: year + period: year + label: Oregon LIHEAP 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 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ms/mdhs/liheap/ms_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ms/mdhs/liheap/ms_liheap_eligible.yaml index f2a24f109ae..6f75d720b6e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ms/mdhs/liheap/ms_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ms/mdhs/liheap/ms_liheap_eligible.yaml @@ -64,3 +64,51 @@ # Household 2 lives in public housing with heat included in the rent and no # energy bill of its own: not eligible. ms_liheap_eligible: [true, false] +- name: Case 5, federal 110% poverty floor above the 60% state median income limit at size 11. + period: 2026 + input: + state_code: [MS, MS, MS, MS, MS] + age: [40, 40, 40, 40, 40] + ms_liheap_household_size: [11, 11, 11, 11, 10] + ms_liheap_income: [75_593, 77_714.99, 77_715, 77_716, 74_051] + heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] + heating_expense: [1_000, 1_000, 1_000, 1_000, 1_000] + 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 10 = 70,650 for 11 people, and 110% is 77,715. + # The 60% SMI limit for 11 people is 75,593 (manual PDF page 58). + # 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 10 people, whose 74,050 limit exceeds the 71,665 floor + # (110% of 65,150), so the limit still applies: not eligible. + ms_liheap_eligible: [true, true, false, false, false] +- name: Case 6, the floor uses the poverty guidelines from the year before the model year. + period: 2026 + input: + state_code: MS + age: 40 + ms_liheap_household_size: 11 + ms_liheap_income: 78_000 + heating_type: ELECTRICITY + heating_expense: 1_000 + output: + # FY2026 uses the 2025 guidelines, so the floor is 77,715. The 2026 + # guidelines would give 110% x (15,960 + 5,680 x 10) = 80,036. + ms_liheap_eligible: false +- name: Case 7, FY2027 uses the 2026 poverty guidelines for the floor. + period: 2027 + input: + state_code: [MS, MS] + age: [40, 40] + ms_liheap_household_size: [11, 11] + ms_liheap_income: [80_035.99, 80_036] + heating_type: [ELECTRICITY, ELECTRICITY] + heating_expense: [1_000, 1_000] + output: + # LIHEAP IM 2026-01 makes the 2026 guidelines mandatory in FY2027: + # 110% x (15,960 + 5,680 x 10) = 80,036 for 11 people, above the 79,402 + # FY2027 60% SMI limit. + ms_liheap_eligible: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.yaml index d1b3ed8f290..8abd2edcc64 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.yaml @@ -43,3 +43,62 @@ # 7. public housing is subsidized housing, so heat included in rent is # again "No", ineligible. or_liheap_eligible: [false, true, false, true, true, false, false] + +- name: Case 2, federal 110% poverty floor above the 60% state median income limit at size 20. + period: 2026 + input: + state_code: [OR, OR, OR, OR, OR] + spm_unit_size: [20, 20, 20, 20, 19] + or_liheap_countable_income: [128_441, 132_164.99, 132_165, 132_166, 126_227] + heat_expense_included_in_rent: [true, true, true, true, true] + 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 19 = 120,150 for 20 people, and 110% is + # 132,165. The 60% SMI limit for 20 people is 128,441 (federal size + # factors; the manual's table stops at 12 on page 77). + # 1. at the 60% SMI limit: eligible; + # 2. one cent below the floor: eligible; + # 3. exactly at the floor, which is not below 110%: ineligible; + # 4. above the floor: ineligible; + # 5. 19 people, whose 126,226 limit exceeds the 126,115 floor (110% of + # 114,650), so the limit still applies: ineligible. + or_liheap_eligible: [true, true, false, false, false] + +- name: Case 3, the floor uses the poverty guidelines from the year before the model year. + period: 2026 + input: + state_code: OR + spm_unit_size: 20 + or_liheap_countable_income: 134_000 + heat_expense_included_in_rent: true + output: + # PY2026 uses the 2025 guidelines, so the floor is 132,165. The 2026 + # guidelines would give 110% x (15,960 + 5,680 x 19) = 136,268. + or_liheap_eligible: false + +- name: Case 4, PY2025 uses the 2024 poverty guidelines for the floor. + period: 2025 + input: + state_code: [OR, OR] + spm_unit_size: [19, 19] + or_liheap_countable_income: [123_089.99, 123_090] + heat_expense_included_in_rent: [true, true] + output: + # LIHEAP IM 2024-02 makes the 2024 guidelines mandatory in FY2025: + # 110% x (15,060 + 5,380 x 18) = 123,090 for 19 people, above the 121,051 + # PY2025 60% SMI limit. + or_liheap_eligible: [true, false] + +- name: Case 5, PY2027 uses the 2026 poverty guidelines for the floor. + period: 2027 + input: + state_code: [OR, OR] + spm_unit_size: [20, 20] + or_liheap_countable_income: [136_267.99, 136_268] + heat_expense_included_in_rent: [true, true] + output: + # LIHEAP IM 2026-01 makes the 2026 guidelines mandatory in FY2027: + # 110% x (15,960 + 5,680 x 19) = 136,268 for 20 people, above the 134,937 + # PY2027 60% SMI limit. + or_liheap_eligible: [true, false] diff --git a/policyengine_us/variables/gov/states/ms/mdhs/liheap/ms_liheap_eligible.py b/policyengine_us/variables/gov/states/ms/mdhs/liheap/ms_liheap_eligible.py index 968a281af7c..f3963bf6b5e 100644 --- a/policyengine_us/variables/gov/states/ms/mdhs/liheap/ms_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/ms/mdhs/liheap/ms_liheap_eligible.py @@ -1,4 +1,5 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class ms_liheap_eligible(Variable): @@ -12,6 +13,7 @@ class ms_liheap_eligible(Variable): "https://www.sos.ms.gov/adminsearch/ACCode/00000693c.pdf#page=22", # Section 2.3, explanations of policies (page 9). "https://liheapch.acf.gov/docs/2026/state-plans/MS_Plan_2026.pdf#page=9", + "https://www.law.cornell.edu/uscode/text/42/8624", ) def formula(spm_unit, period, parameters): @@ -19,6 +21,14 @@ def formula(spm_unit, period, parameters): size = spm_unit("ms_liheap_household_size", period) income = spm_unit("ms_liheap_income", period) limit = spm_unit("ms_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 11 in FY2026 and FY2027. + p_hhs = parameters(period).gov.hhs.liheap + 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) has_adult = spm_unit.any(spm_unit.members("age", period) >= p.adult_age) # Existing inputs do not establish emancipated-minor headship, institutional # residence, or utility account ownership. A household adult is the modeled @@ -43,6 +53,4 @@ def formula(spm_unit, period, parameters): # subsidized housing qualifies only with separately billed energy, and # the landlord-evidence route is for unsubsidized renters. housing_eligible = ~subsidized | ~heat_in_rent - return ( - (size > 0) & (income <= limit) & has_adult & responsible & housing_eligible - ) + return (size > 0) & income_eligible & has_adult & responsible & housing_eligible diff --git a/policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.py b/policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.py index 0273768c7a3..19814dfb755 100644 --- a/policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.py @@ -1,4 +1,5 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class or_liheap_eligible(Variable): @@ -11,6 +12,7 @@ class or_liheap_eligible(Variable): reference = ( "https://www.oregon.gov/ohcs/energy-weatherization/Documents/2026%20Final%20Energy%20Assistance%20Intake%20Operations%20%26%20Policy%20Manual.pdf#page=61", "https://www.law.cornell.edu/regulations/oregon/Or-Admin-Code-SS-813-200-0020", + "https://www.law.cornell.edu/uscode/text/42/8624", ) documentation = ( "SPM members approximate the economic household, with identity and SSN " @@ -25,14 +27,21 @@ class or_liheap_eligible(Variable): ) def formula(spm_unit, period, parameters): + p = parameters(period).gov.states["or"].ohcs.liheap.eligibility + p_hhs = parameters(period).gov.hhs.liheap heat_in_rent = spm_unit("heat_expense_included_in_rent", period) subsidized = spm_unit( "receives_housing_assistance", period ) | spm_unit.household("is_in_public_housing", period) heating_cost = spm_unit("has_heating_expense", period) | heat_in_rent income = spm_unit("or_liheap_countable_income", period) - return ( - heating_cost - & ~(heat_in_rent & subsidized) - & (income <= spm_unit("or_liheap_income_limit", period)) - ) + limit = spm_unit("or_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 19 in PY2025 and size 20 in PY2026 and PY2027. + 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.fpg_year_lag) + floor = np.round(guideline * p_hhs.fpg_floor, 2) + income_eligible = (income <= limit) | (income < floor) + return heating_cost & ~(heat_in_rent & subsidized) & income_eligible From e11c4df55e8e5da68f8fbad84738dfb75ee71be3 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Mon, 19 Oct 2026 11:52:18 -0400 Subject: [PATCH 2/7] Apply the federal 110% poverty floor to DC, MA and NJ LIHEAP The 60% SMI limits fall below 110% of the poverty guideline only for very large households: DC from size 34 to 39 in 2022-2024, MA from size 30 to 34 and NJ from size 28 to 32 in 2022-2027. The eligibility tests now accept income below the floor, using the one-year guideline lag. MA reuses ma_liheap_fpg, which already lags the guideline; DC and NJ get their own fpg_year_lag parameters. Co-Authored-By: Claude Opus 5.5 --- changelog.d/liheap-federal-fpg-floor.fixed.md | 2 +- .../states/dc/doee/liheap/fpg_year_lag.yaml | 18 ++++++++ .../dca/liheap/eligibility/fpg_year_lag.yaml | 20 +++++++++ .../dc/doee/liheap/dc_liheap_eligible.yaml | 41 +++++++++++++++++ .../ma_liheap_income_eligible.yaml | 42 +++++++++++++++++ .../eligibility/nj_liheap_eligible.yaml | 45 +++++++++++++++++++ .../dc/doee/liheap/dc_liheap_eligible.py | 18 +++++++- .../eligibility/ma_liheap_income_eligible.py | 11 ++++- .../liheap/eligibility/nj_liheap_eligible.py | 20 ++++++--- 9 files changed, 207 insertions(+), 10 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/dc/doee/liheap/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/fpg_year_lag.yaml diff --git a/changelog.d/liheap-federal-fpg-floor.fixed.md b/changelog.d/liheap-federal-fpg-floor.fixed.md index 93fe85c2deb..18c4f573594 100644 --- a/changelog.d/liheap-federal-fpg-floor.fixed.md +++ b/changelog.d/liheap-federal-fpg-floor.fixed.md @@ -1 +1 @@ -Apply the federal 110% poverty guideline floor to Mississippi and Oregon LIHEAP income eligibility. +Apply the federal 110% poverty guideline floor to District of Columbia, Massachusetts, Mississippi, New Jersey and Oregon LIHEAP income eligibility. diff --git a/policyengine_us/parameters/gov/states/dc/doee/liheap/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/dc/doee/liheap/fpg_year_lag.yaml new file mode 100644 index 00000000000..4a6632b74de --- /dev/null +++ b/policyengine_us/parameters/gov/states/dc/doee/liheap/fpg_year_lag.yaml @@ -0,0 +1,18 @@ +description: The District of Columbia 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 2024 (FY2024) uses the 2023 guidelines and 2026 +# (FY2026) the 2025 guidelines. The District's own limit uses state median +# income. +values: + 2021-10-01: 1 +metadata: + unit: year + period: year + label: DC 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 2023-01, poverty guidelines for optional use in FFY 2023 and mandatory use in FFY 2024 + href: https://acf.hhs.gov/ocs/policy-guidance/liheap-im-2023-01-federal-poverty-guidelines-optional-use-ffy-2023and-mandatory + - 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 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/fpg_year_lag.yaml new file mode 100644 index 00000000000..cba42d7933c --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/fpg_year_lag.yaml @@ -0,0 +1,20 @@ +description: New Jersey 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 2024 (FY2024) uses the 2023 guidelines and 2026 +# (FY2026) the 2025 guidelines. New Jersey's own limit uses state median +# income. +values: + 2021-10-01: 1 +metadata: + unit: year + period: year + label: New Jersey 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 2023-01, poverty guidelines for optional use in FFY 2023 and mandatory use in FFY 2024 + href: https://acf.hhs.gov/ocs/policy-guidance/liheap-im-2023-01-federal-poverty-guidelines-optional-use-ffy-2023and-mandatory + - 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 diff --git a/policyengine_us/tests/policy/baseline/gov/states/dc/doee/liheap/dc_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/dc/doee/liheap/dc_liheap_eligible.yaml index 08b7843f8b1..e4712706510 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/dc/doee/liheap/dc_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/dc/doee/liheap/dc_liheap_eligible.yaml @@ -17,3 +17,44 @@ state_code: DC output: dc_liheap_eligible: false + +- name: Case 3, federal 110% poverty floor above the 60% state median income limit at size 36. + period: 2024 + input: + state_code: [DC, DC, DC, DC, DC] + spm_unit_size: [36, 36, 36, 36, 35] + irs_gross_income: [212_000, 213_927.99, 213_928, 213_929, 210_000] + output: + # 42 U.S.C. 8624(b)(2)(B) bars excluding a household on income below 110% + # of the poverty guideline. FY2024 uses the 2023 guidelines (LIHEAP IM + # 2023-01): 14,580 + 5,140 x 35 = 194,480 for 36 people, and 110% is + # 213,928. The 60% SMI limit for 36 people is 212,669.78. + # 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 35 people, whose 209,795.88 limit exceeds the 208,274 + # floor (110% of 189,340), so the limit still applies: not eligible. + dc_liheap_eligible: [true, true, false, false, false] + +- name: Case 4, the floor uses the poverty guidelines from the year before the model year. + period: 2024 + input: + state_code: DC + spm_unit_size: 36 + irs_gross_income: 215_000 + output: + # FY2024 uses the 2023 guidelines, so the floor is 213,928. The 2024 + # guidelines would give 110% x (15,060 + 5,380 x 35) = 223,696. + dc_liheap_eligible: false + +- name: Case 5, FY2023 uses the 2022 poverty guidelines for the floor. + period: 2023 + input: + state_code: [DC, DC] + spm_unit_size: [39, 39] + irs_gross_income: [212_244.99, 212_245] + output: + # 110% x (13,590 + 4,720 x 38) = 212,245 for 39 people, above the + # 210,731.61 FY2023 60% SMI limit. + dc_liheap_eligible: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.yaml index 80e9d026c33..b2040640cd6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.yaml @@ -27,3 +27,45 @@ output: ma_liheap_income_eligible: true # hhs_smi: 119_895 + +- name: Case 4, federal 110% poverty floor above the 60% state median income limit at size 34. + period: 2026 + input: + state_code: [MA, MA, MA, MA, MA] + spm_unit_size: [34, 34, 34, 34, 33] + ma_liheap_income: [215_000, 216_864.99, 216_865, 216_866, 213_000] + 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 33 = 197,150 for 34 people, and 110% is + # 216,865. The 60% SMI limit for 34 people is 215,077.70. + # 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 33 people, whose 212,090.50 limit exceeds the 210,815 + # floor (110% of 191,650), so the limit still applies: not eligible. + ma_liheap_income_eligible: [true, true, false, false, false] + +- name: Case 5, the floor uses the poverty guidelines from the year before the model year. + period: 2026 + input: + state_code: MA + spm_unit_size: 34 + ma_liheap_income: 220_000 + output: + # FY2026 uses the 2025 guidelines, so the floor is 216,865. The 2026 + # guidelines would give 110% x (15,960 + 5,680 x 33) = 223,740. + ma_liheap_income_eligible: false + +- name: Case 6, FY2025 uses the 2024 poverty guidelines for the floor. + period: 2025 + input: + state_code: [MA, MA] + spm_unit_size: [32, 32] + ma_liheap_income: [200_023.99, 200_024] + output: + # LIHEAP IM 2024-02 makes the 2024 guidelines mandatory in FY2025: + # 110% x (15,060 + 5,380 x 31) = 200,024 for 32 people, above the + # 198,676.81 FY2025 60% SMI limit. + ma_liheap_income_eligible: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml index 6b15e9404d2..d99aa38c1ff 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml @@ -120,3 +120,48 @@ is_tax_unit_dependent: [false, true] output: nj_liheap_eligible: [true, true] + +- name: Case 7, federal 110% poverty floor above the 60% state median income limit at size 32. + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ] + nj_liheap_household_size: [32, 32, 32, 32, 31] + nj_liheap_countable_income: [202_092, 204_764.99, 204_765, 204_766, 199_201] + heat_expense_included_in_rent: [true, true, true, true, true] + 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 31 = 186,150 for 32 people, and 110% is + # 204,765. The annualized 60% SMI limit for 32 people is 202,092. + # 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 31 people, whose 199,200 limit exceeds the 198,715 floor + # (110% of 180,650), so the limit still applies: not eligible. + nj_liheap_eligible: [true, true, false, false, false] + +- name: Case 8, the floor uses the poverty guidelines from the year before the model year. + period: 2026 + input: + state_code: NJ + nj_liheap_household_size: 32 + nj_liheap_countable_income: 208_000 + heat_expense_included_in_rent: true + output: + # FY2026 uses the 2025 guidelines, so the floor is 204,765. The 2026 + # guidelines would give 110% x (15,960 + 5,680 x 31) = 211,244. + nj_liheap_eligible: false + +- name: Case 9, FY2024 uses the 2023 poverty guidelines for the floor. + period: 2024 + input: + state_code: [NJ, NJ] + nj_liheap_household_size: [28, 28] + nj_liheap_countable_income: [168_695.99, 168_696] + heat_expense_included_in_rent: [true, true] + output: + # LIHEAP IM 2023-01 makes the 2023 guidelines mandatory in FY2024: + # 110% x (14,580 + 5,140 x 27) = 168,696 for 28 people, above the 167,952 + # FY2024 annualized 60% SMI limit. + nj_liheap_eligible: [true, false] diff --git a/policyengine_us/variables/gov/states/dc/doee/liheap/dc_liheap_eligible.py b/policyengine_us/variables/gov/states/dc/doee/liheap/dc_liheap_eligible.py index cff8a5bd276..0a0bca7c37e 100644 --- a/policyengine_us/variables/gov/states/dc/doee/liheap/dc_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/dc/doee/liheap/dc_liheap_eligible.py @@ -1,4 +1,5 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class dc_liheap_eligible(Variable): @@ -7,12 +8,25 @@ class dc_liheap_eligible(Variable): label = "Eligible for the DC LIHEAP" definition_period = YEAR defined_for = StateCode.DC - reference = "https://doee.dc.gov/liheap" + reference = ( + "https://doee.dc.gov/liheap", + "https://www.law.cornell.edu/uscode/text/42/8624", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.hhs.liheap + p_dc = parameters(period).gov.states.dc.doee.liheap state_median_income = spm_unit("hhs_smi", period) # The income concept is not clearly defined, assuming IRS gross income income = add(spm_unit, period, ["irs_gross_income"]) smi_limit = state_median_income * p.smi_limit - return income <= smi_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 34 to 39 in 2022 to 2024. + 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_dc.fpg_year_lag + ) + floor = np.round(guideline * p.fpg_floor, 2) + return (income <= smi_limit) | (income < floor) diff --git a/policyengine_us/variables/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.py b/policyengine_us/variables/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.py index 4cad79d38bb..275933fc1eb 100644 --- a/policyengine_us/variables/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.py +++ b/policyengine_us/variables/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.py @@ -8,10 +8,17 @@ class ma_liheap_income_eligible(Variable): definition_period = YEAR defined_for = StateCode.MA reference = ( - "https://www.mass.gov/info-details/learn-about-home-energy-assistance-heap" + "https://www.mass.gov/info-details/learn-about-home-energy-assistance-heap", + "https://www.law.cornell.edu/uscode/text/42/8624", ) def formula(spm_unit, period, parameters): + p = parameters(period).gov.hhs.liheap income = spm_unit("ma_liheap_income", period) income_threshold = spm_unit("ma_liheap_state_median_income_threshold", period) - return income <= income_threshold + # 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 30 to 34 in 2022 to 2027. ma_liheap_fpg already uses the + # guidelines in force on October 1 of the preceding year. + floor = np.round(spm_unit("ma_liheap_fpg", period) * p.fpg_floor, 2) + return (income <= income_threshold) | (income < floor) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py index 9d2bf976a34..5f0d70e3ea3 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py @@ -1,4 +1,5 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class nj_liheap_eligible(Variable): @@ -15,6 +16,7 @@ class nj_liheap_eligible(Variable): "https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-2", "https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-3", "https://www.nj.gov/bpu/newsroom/2021/approved/20211019.html", + "https://www.law.cornell.edu/uscode/text/42/8624", ) documentation = ( "Automatic enrollment does not waive the income test, and regular heating has " @@ -37,6 +39,17 @@ def formula(spm_unit, period, parameters): person("is_full_time_student", period) & person("is_tax_unit_dependent", period) ) + size = spm_unit("nj_liheap_household_size", period) + income = spm_unit("nj_liheap_countable_income", period) + limit = spm_unit("nj_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 28 to 32 in FY2022 to FY2027. + p_hhs = parameters(period).gov.hhs.liheap + 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) # The modeled 60% SMI rules begin with FY2022 (BPU, October 19, 2021); # the earlier poverty-level standard is not encoded. return ( @@ -44,9 +57,6 @@ def formula(spm_unit, period, parameters): & (spm_unit("has_heating_expense", period) | heat_in_rent) & ~(heat_in_rent & subsidized) & ~dependent_students_only - & (spm_unit("nj_liheap_household_size", period) > 0) - & ( - spm_unit("nj_liheap_countable_income", period) - <= spm_unit("nj_liheap_income_limit", period) - ) + & (size > 0) + & income_eligible ) From 9cf11a59b1e2516ca6f135b61d22d045c63f936d Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Mon, 19 Oct 2026 12:35:28 -0400 Subject: [PATCH 3/7] Anchor the LIHEAP floor reference to 42 U.S.C. 8624(b)(2)(B) Co-Authored-By: Claude Opus 5.5 --- policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml b/policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml index ae7cb296211..aeb7f8c5b07 100644 --- a/policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml +++ b/policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml @@ -8,4 +8,4 @@ metadata: label: LIHEAP poverty guideline income floor reference: - title: 42 U.S.C. 8624(b)(2)(B) - href: https://www.law.cornell.edu/uscode/text/42/8624 + href: https://www.law.cornell.edu/uscode/text/42/8624#b_2_B From 14179cb154abd97179f4617a3f2c383280a733eb Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Mon, 19 Oct 2026 13:13:41 -0400 Subject: [PATCH 4/7] Update the NC SA 2027 test for the announced 2027 COLA #10225 replaced the projected 2027 SSA uprating index with the 2026Q3 CPI-W average and set the 2027 SSI federal benefit rate to $1,029. The NC Special Assistance 2027 case still expected the old projections ($1,436 rate, $1,021.83 FBR), so the states-shard-1 suite fails on main and on every PR. The uprated rate is now $1,448 and the payment $489. Co-Authored-By: Claude Opus 5.5 --- .../baseline/gov/states/nc/ncdhhs/sa/nc_sa.yaml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/nc/ncdhhs/sa/nc_sa.yaml b/policyengine_us/tests/policy/baseline/gov/states/nc/ncdhhs/sa/nc_sa.yaml index d7a1f2a8e82..bb91214fa85 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nc/ncdhhs/sa/nc_sa.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nc/ncdhhs/sa/nc_sa.yaml @@ -485,7 +485,8 @@ nc_sa: 0 # G.S. 108A-42.1 adjusts the rates each January 1 by the Social Security -# cost-of-living adjustment. The 2027 rate and FBR are projections. +# cost-of-living adjustment. The 2027 rate is uprated until North Carolina +# publishes it; the 2027 FBR is the SSA amount announced with the 3.6% COLA. # https://www.ncleg.gov/EnactedLegislation/Statutes/PDF/BySection/Chapter_108A/GS_108A-42.1.pdf - name: Case 37, basic facility rate follows the cost-of-living adjustment in 2027. period: 2027-01 @@ -495,13 +496,13 @@ age: 65 nc_sa_care_setting: ADULT_CARE_HOME output: - # 1,397 uprated by the projected Social Security index and rounded to the - # dollar. - nc_sa_rate: 1_436 - # Projected FBR. - ssi: 1_021.83 - # 1,436 + 70 - 1,021.83 = 484.17 -> 484. - nc_sa: 484 + # 1,397 uprated by the Social Security index (2027 CPI-W 328.746 / 2026 + # 317.265 = 1.036187) and rounded to the dollar: 1,447.55 -> 1,448. + nc_sa_rate: 1_448 + # 2027 SSI federal benefit rate. + ssi: 1_029 + # 1,448 + 70 - 1,029 = 489. + nc_sa: 489 # An applicant "ineligible for SSI solely due to being over income for SSI" # qualifies without applying for SSI (SA-3100 I, II.A.6): "If the a/b From 9aca37909af8154906ae034cc524cb0292d5c468 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Mon, 19 Oct 2026 14:03:19 -0400 Subject: [PATCH 5/7] Address review: MS floor citation, IM link, exact limits, payment test - Cite Rule 6.1 C, the printed 60% SMI table and FY2026 plan assurance (2) in the Mississippi floor comment; the printed table itself falls below the floor at sizes 11 to 20. - Point the IM 2023-01 references to the acf.gov archive URL. - Correct test comments that showed float32-rounded DC and MA limits. - Add a Mississippi payment test for a household that qualifies only through the floor. Co-Authored-By: Claude Opus 5.5 --- .../states/dc/doee/liheap/fpg_year_lag.yaml | 2 +- .../dca/liheap/eligibility/fpg_year_lag.yaml | 2 +- .../dc/doee/liheap/dc_liheap_eligible.yaml | 4 ++-- .../ma_liheap_income_eligible.yaml | 6 +++--- .../gov/states/ms/mdhs/liheap/ms_liheap.yaml | 19 +++++++++++++++++++ .../ms/mdhs/liheap/ms_liheap_eligible.py | 11 ++++++++--- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/policyengine_us/parameters/gov/states/dc/doee/liheap/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/dc/doee/liheap/fpg_year_lag.yaml index 4a6632b74de..a59be34ef39 100644 --- a/policyengine_us/parameters/gov/states/dc/doee/liheap/fpg_year_lag.yaml +++ b/policyengine_us/parameters/gov/states/dc/doee/liheap/fpg_year_lag.yaml @@ -13,6 +13,6 @@ metadata: - title: LIHEAP Information Memoranda, annual poverty guideline memoranda href: https://acf.gov/ocs/policy-guidance/liheap-information-memoranda - title: LIHEAP IM 2023-01, poverty guidelines for optional use in FFY 2023 and mandatory use in FFY 2024 - href: https://acf.hhs.gov/ocs/policy-guidance/liheap-im-2023-01-federal-poverty-guidelines-optional-use-ffy-2023and-mandatory + href: https://acf.gov/archive/ocs/policy-guidance/liheap-im-2023-01-federal-poverty-guidelines-optional-use-ffy-2023and - 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 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/fpg_year_lag.yaml index cba42d7933c..12808097bbe 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/fpg_year_lag.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/fpg_year_lag.yaml @@ -13,7 +13,7 @@ metadata: - title: LIHEAP Information Memoranda, annual poverty guideline memoranda href: https://acf.gov/ocs/policy-guidance/liheap-information-memoranda - title: LIHEAP IM 2023-01, poverty guidelines for optional use in FFY 2023 and mandatory use in FFY 2024 - href: https://acf.hhs.gov/ocs/policy-guidance/liheap-im-2023-01-federal-poverty-guidelines-optional-use-ffy-2023and-mandatory + href: https://acf.gov/archive/ocs/policy-guidance/liheap-im-2023-01-federal-poverty-guidelines-optional-use-ffy-2023and - 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 diff --git a/policyengine_us/tests/policy/baseline/gov/states/dc/doee/liheap/dc_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/dc/doee/liheap/dc_liheap_eligible.yaml index e4712706510..a4b65bf8b07 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/dc/doee/liheap/dc_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/dc/doee/liheap/dc_liheap_eligible.yaml @@ -33,7 +33,7 @@ # 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 35 people, whose 209,795.88 limit exceeds the 208,274 + # Household 5 has 35 people, whose 209,795.87 limit exceeds the 208,274 # floor (110% of 189,340), so the limit still applies: not eligible. dc_liheap_eligible: [true, true, false, false, false] @@ -56,5 +56,5 @@ irs_gross_income: [212_244.99, 212_245] output: # 110% x (13,590 + 4,720 x 38) = 212,245 for 39 people, above the - # 210,731.61 FY2023 60% SMI limit. + # 210,731.60 FY2023 60% SMI limit. dc_liheap_eligible: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.yaml index b2040640cd6..1c39c912b43 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ma/doer/liheap/eligibility/ma_liheap_income_eligible.yaml @@ -38,12 +38,12 @@ # 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 33 = 197,150 for 34 people, and 110% is - # 216,865. The 60% SMI limit for 34 people is 215,077.70. + # 216,865. The 60% SMI limit for 34 people is 215,077.68. # 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 33 people, whose 212,090.50 limit exceeds the 210,815 + # Household 5 has 33 people, whose 212,090.49 limit exceeds the 210,815 # floor (110% of 191,650), so the limit still applies: not eligible. ma_liheap_income_eligible: [true, true, false, false, false] @@ -67,5 +67,5 @@ output: # LIHEAP IM 2024-02 makes the 2024 guidelines mandatory in FY2025: # 110% x (15,060 + 5,380 x 31) = 200,024 for 32 people, above the - # 198,676.81 FY2025 60% SMI limit. + # 198,676.80 FY2025 60% SMI limit. ma_liheap_income_eligible: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ms/mdhs/liheap/ms_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ms/mdhs/liheap/ms_liheap.yaml index e940bc034f8..54a044a2b9a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ms/mdhs/liheap/ms_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ms/mdhs/liheap/ms_liheap.yaml @@ -379,3 +379,22 @@ # Household 2 pays its own electric bill of 45 a month. Matrix page 1, # household size 1, first band, Electric 700: min(700, 540) = 540. ms_liheap: [0, 540] +- name: Case 20, a household that qualifies only through the federal 110% poverty floor is paid from the last income band. + period: 2026 + input: + state_code: [MS, MS] + age: [40, 40] + ms_liheap_household_size: [11, 11] + ms_liheap_income: [77_000, 77_715] + heating_type: [PROPANE, PROPANE] + heating_expense: [2_000, 2_000] + output: + # Both incomes exceed the 75,593 size-11 limit (manual PDF page 58). + # Household 1 is below the 77,715 floor (110% of the 2025 guideline of + # 70,650) and qualifies under 42 U.S.C. 8624(b)(2)(B). Household 2 is at + # the floor and does not qualify. + ms_liheap_eligible: [true, false] + # The size-11 matrix (manual PDF pages 59-64) has an open fourth band + # above 52,988. Propane column: 800 - 3 x 50 = 650. A 2,000 bill exceeds + # the cap, and no electric bill is reported. + ms_liheap: [650, 0] diff --git a/policyengine_us/variables/gov/states/ms/mdhs/liheap/ms_liheap_eligible.py b/policyengine_us/variables/gov/states/ms/mdhs/liheap/ms_liheap_eligible.py index f3963bf6b5e..d049215ee51 100644 --- a/policyengine_us/variables/gov/states/ms/mdhs/liheap/ms_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/ms/mdhs/liheap/ms_liheap_eligible.py @@ -13,6 +13,8 @@ class ms_liheap_eligible(Variable): "https://www.sos.ms.gov/adminsearch/ACCode/00000693c.pdf#page=22", # Section 2.3, explanations of policies (page 9). "https://liheapch.acf.gov/docs/2026/state-plans/MS_Plan_2026.pdf#page=9", + # Assurance (2), the 110% poverty floor (page 44). + "https://liheapch.acf.gov/docs/2026/state-plans/MS_Plan_2026.pdf#page=44", "https://www.law.cornell.edu/uscode/text/42/8624", ) @@ -21,9 +23,12 @@ def formula(spm_unit, period, parameters): size = spm_unit("ms_liheap_household_size", period) income = spm_unit("ms_liheap_income", period) limit = spm_unit("ms_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 11 in FY2026 and FY2027. + # 42 U.S.C. 8624(b)(2)(B), repeated in FY2026 plan assurance (2) (page 44), + # bars excluding a household on income below 110% of the poverty + # guideline. The Rule 6.1 C limit and its printed 60% SMI table (manual + # PDF pages 22 and 58) fall below that floor at sizes 11 to 20 in FY2026 + # (75,593 against 77,715 at size 11), and the modeled limit does so from + # size 11 in FY2026 and FY2027. p_hhs = parameters(period).gov.hhs.liheap state_group = spm_unit.household("state_group_str", period) guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) From 1e641b49dae65ff013727a62b4a58458a505c5d7 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Mon, 19 Oct 2026 14:13:51 -0400 Subject: [PATCH 6/7] Apply the federal 110% poverty floor to IN, MD and Riverside LIHEAP The 60% SMI limits fall below 110% of the poverty guideline from household size 15 (2025) or 16 (2026-2027) in Indiana EAP, size 29 in Maryland MEAP (FY25-FY27), and size 20 (2025) or 21 (2026-2027) in Riverside County LIHEAP. The eligibility tests now accept income below the floor, with the one-year guideline lag. Maryland reuses md_meap_fpg; Indiana and Riverside get fpg_year_lag parameters. Stacked on #10279, which adds gov.hhs.liheap.fpg_floor. Co-Authored-By: Claude Opus 5.5 --- .../liheap-fpg-floor-in-md-riv.fixed.md | 1 + .../local/ca/riv/cap/liheap/fpg_year_lag.yaml | 20 ++++++++ .../ihcda/eap/eligibility/fpg_year_lag.yaml | 17 +++++++ .../cap/liheap/ca_riv_liheap_eligible.yaml | 47 +++++++++++++++++ .../gov/states/in/ihcda/eap/in_eap.yaml | 24 +++++++++ .../states/in/ihcda/eap/in_eap_eligible.yaml | 42 ++++++++++++++++ .../meap/eligibility/md_meap_eligible.yaml | 50 +++++++++++++++++++ .../gov/states/md/dhs/meap/md_meap.yaml | 18 +++++++ .../ca/riv/liheap/ca_riv_liheap_eligible.py | 24 ++++++++- .../states/in/ihcda/eap/in_eap_eligible.py | 14 +++++- .../dhs/meap/eligibility/md_meap_eligible.py | 15 ++++-- 11 files changed, 266 insertions(+), 6 deletions(-) create mode 100644 changelog.d/liheap-fpg-floor-in-md-riv.fixed.md create mode 100644 policyengine_us/parameters/gov/local/ca/riv/cap/liheap/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/fpg_year_lag.yaml diff --git a/changelog.d/liheap-fpg-floor-in-md-riv.fixed.md b/changelog.d/liheap-fpg-floor-in-md-riv.fixed.md new file mode 100644 index 00000000000..841a6b6e883 --- /dev/null +++ b/changelog.d/liheap-fpg-floor-in-md-riv.fixed.md @@ -0,0 +1 @@ +Apply the federal 110% poverty guideline floor to Indiana EAP, Maryland MEAP and Riverside County LIHEAP income eligibility. diff --git a/policyengine_us/parameters/gov/local/ca/riv/cap/liheap/fpg_year_lag.yaml b/policyengine_us/parameters/gov/local/ca/riv/cap/liheap/fpg_year_lag.yaml new file mode 100644 index 00000000000..a79f8303f37 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/riv/cap/liheap/fpg_year_lag.yaml @@ -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 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/fpg_year_lag.yaml new file mode 100644 index 00000000000..bb567b174a3 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/fpg_year_lag.yaml @@ -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 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/riv/cap/liheap/ca_riv_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/riv/cap/liheap/ca_riv_liheap_eligible.yaml index 03d6a6cf399..b352237ffef 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/riv/cap/liheap/ca_riv_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/riv/cap/liheap/ca_riv_liheap_eligible.yaml @@ -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] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml index 4ac6644c22d..d59a6e468ec 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml @@ -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] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml index 981055ff692..9bb6081d328 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml @@ -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] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_eligible.yaml index fce98b98b2d..011482a852d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/eligibility/md_meap_eligible.yaml @@ -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] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/md_meap.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/md_meap.yaml index 5ed59cf4e52..55634af0952 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/md_meap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/md/dhs/meap/md_meap.yaml @@ -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] diff --git a/policyengine_us/variables/gov/local/ca/riv/liheap/ca_riv_liheap_eligible.py b/policyengine_us/variables/gov/local/ca/riv/liheap/ca_riv_liheap_eligible.py index 852c34cbe96..88d19af9002 100644 --- a/policyengine_us/variables/gov/local/ca/riv/liheap/ca_riv_liheap_eligible.py +++ b/policyengine_us/variables/gov/local/ca/riv/liheap/ca_riv_liheap_eligible.py @@ -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): @@ -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) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py index 208fe21f869..f9d73a6ebea 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py @@ -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): @@ -11,12 +12,23 @@ 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 @@ -24,5 +36,5 @@ def formula(spm_unit, period, parameters): 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)) ) diff --git a/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_eligible.py b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_eligible.py index 57967995fef..1f55c315d91 100644 --- a/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_eligible.py +++ b/policyengine_us/variables/gov/states/md/dhs/meap/eligibility/md_meap_eligible.py @@ -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 " @@ -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. From a3386208c6b0fdc3f516464ba1c72f84ae2e7fb9 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 20 Oct 2026 11:36:17 -0400 Subject: [PATCH 7/7] Remove the #10279 changelog fragment that main already released Co-Authored-By: Claude Opus 5.5 --- changelog.d/liheap-federal-fpg-floor.fixed.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 changelog.d/liheap-federal-fpg-floor.fixed.md diff --git a/changelog.d/liheap-federal-fpg-floor.fixed.md b/changelog.d/liheap-federal-fpg-floor.fixed.md deleted file mode 100644 index 18c4f573594..00000000000 --- a/changelog.d/liheap-federal-fpg-floor.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Apply the federal 110% poverty guideline floor to District of Columbia, Massachusetts, Mississippi, New Jersey and Oregon LIHEAP income eligibility.