From a278309901c33c7f2c1bb10a4c087e6b5583ee34 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 8 Nov 2026 22:01:41 -0500 Subject: [PATCH 1/7] Pay Oregon LIHEAP to households whose only energy cost is cooling Co-Authored-By: Claude Opus 5.5 --- changelog.d/or-liheap-cooling.fixed.md | 1 + .../liheap/payment/amount/electricity.yaml | 6 ++- policyengine_us/programs.yaml | 2 +- .../eligibility/or_liheap_eligible.yaml | 26 +++++++++ .../gov/states/or/ohcs/liheap/or_liheap.yaml | 54 +++++++++++++++++++ .../liheap/eligibility/or_liheap_eligible.py | 21 ++++++-- .../gov/states/or/ohcs/liheap/or_liheap.py | 13 +++-- 7 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 changelog.d/or-liheap-cooling.fixed.md diff --git a/changelog.d/or-liheap-cooling.fixed.md b/changelog.d/or-liheap-cooling.fixed.md new file mode 100644 index 00000000000..b8e0e007199 --- /dev/null +++ b/changelog.d/or-liheap-cooling.fixed.md @@ -0,0 +1 @@ +Pay Oregon's LIHEAP standard payment from the matrix cooling column to households with no heating that pay an electric bill for cooling. diff --git a/policyengine_us/parameters/gov/states/or/ohcs/liheap/payment/amount/electricity.yaml b/policyengine_us/parameters/gov/states/or/ohcs/liheap/payment/amount/electricity.yaml index 6e61f0605db..7c15d7e1941 100644 --- a/policyengine_us/parameters/gov/states/or/ohcs/liheap/payment/amount/electricity.yaml +++ b/policyengine_us/parameters/gov/states/or/ohcs/liheap/payment/amount/electricity.yaml @@ -1,4 +1,6 @@ -description: Oregon provides this annual regular heating payment for electricity by region, household size and income band under the Low Income Home Energy Assistance Program. +description: Oregon provides this annual regular heating or cooling payment for electricity by region, household size and income band under the Low Income Home Energy Assistance Program. +# The COOLING Electricity column equals the HEATING Electricity column in every +# row of the PY2025 to PY2027 matrices, so this table pays both. 1: 1: 1: @@ -175,7 +177,7 @@ description: Oregon provides this annual regular heating payment for electricity metadata: unit: currency-USD period: year - label: Oregon LIHEAP electricity heating payment + label: Oregon LIHEAP electricity heating or cooling payment breakdown: - range(1, 3) - range(1, 7) diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index a7cef450f8b..7d1046428d0 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1282,7 +1282,7 @@ programs: variable: or_liheap parameter_prefix: gov.states.or.ohcs.liheap verified_years: "2025-2027" - notes: PY2025-PY2027 regular heating only, with the two county regions, five fuel columns and the roomer half payment. Crisis, cooling, Fuel Payment, equipment and OEAP assistance are out of scope. + notes: PY2025-PY2027 regular heating or cooling standard payment, with the two county regions, five fuel columns, the cooling column for cooling-only households and the roomer half payment. Crisis, Fuel Payment, equipment and OEAP assistance are out of scope. - state: SC status: partial name: South Carolina LIHEAP 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 8abd2edcc64..fbfc33bb1c0 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 @@ -102,3 +102,29 @@ # 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] + +- name: Case 6, a home without heating qualifies on an electric bill when it pays for cooling. + period: 2026 + input: + state_code: [OR, OR, OR, OR, OR, OR] + heating_type: [NONE, NONE, NONE, UNSPECIFIED, NONE, NONE] + has_cooling_expense: [true, false, true, true, true, true] + # About $125 a month for electricity. + pre_subsidy_electricity_expense: [1_500, 1_500, 0, 1_500, 1_500, 1_500] + receives_housing_assistance: [false, false, false, false, true, false] + # About 30 hours a week at the Portland-metro minimum wage, as in Case 1; + # the last household is one dollar above the size 1 limit of $38,385 + # (page 77). + or_liheap_countable_income: [26_000, 26_000, 26_000, 26_000, 26_000, 38_386] + output: + # "Eligible" households are "responsible for their home heating or cooling + # expenses" (page 90), and the matrices pay electric cooling from their + # COOLING column (pages 78-81): + # 1. no heating, pays for cooling on an electric bill: eligible; + # 2. no cooling cost: no energy burden to demonstrate, ineligible; + # 3. no electric bill: ineligible; + # 4. UNSPECIFIED fuel: ineligible; + # 5. subsidized housing paying its own electric bill: "pays a vendor + # directly for utility costs" is an energy burden (page 93), eligible; + # 6. income above the limit: ineligible. + or_liheap_eligible: [true, false, false, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml index 61b113dc114..377609a4dbf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml @@ -598,3 +598,57 @@ # Gas $380 and Heating Oil $535 in the last row. Sizes 7 to 12 print the # size 6 amounts. or_liheap: [750, 615, 515, 370, 380, 535] + +# The matrices carry a COOLING Electricity column beside the HEATING columns, +# equal to the HEATING Electricity column in every row (PY2025 pages 58-59, +# PY2026 pages 78-81, PY2027 pages 72-75). Countable income of $26,000 is about +# 30 hours a week at the Portland-metro minimum wage, and about $125 a month +# pays the electric bill. +- name: Case 26, a home without heating that pays for electric cooling receives the cooling column. + period: 2026 + input: + state_code: [OR, OR, OR] + county: [MULTNOMAH_COUNTY_OR, DESCHUTES_COUNTY_OR, MULTNOMAH_COUNTY_OR] + spm_unit_size: [1, 1, 1] + heating_type: [NONE, NONE, NONE] + has_cooling_expense: [true, true, false] + pre_subsidy_electricity_expense: [1_500, 1_500, 1_500] + or_liheap_countable_income: [26_000, 26_000, 26_000] + output: + # PY2026 size 1 row "$19,194 $28,789" (page 78). + or_liheap_income_band: [3, 3, 3] + # COOLING Electricity: Region 1 $300 (page 78), Region 2 $335 (page 80). + # Without a cooling cost the home is ineligible, $0. + or_liheap: [300, 335, 0] + +- name: Case 27, program year 2025 pays the PY2025 cooling column. + period: 2025 + input: + state_code: OR + county: DESCHUTES_COUNTY_OR + spm_unit_size: 1 + heating_type: NONE + has_cooling_expense: true + pre_subsidy_electricity_expense: 1_500 + or_liheap_countable_income: 26_000 + output: + # PY2025 size 1 row "$18,407 $27,609" (page 58); Region 2 COOLING + # Electricity $270 (page 59). + or_liheap_income_band: 3 + or_liheap: 270 + +- name: Case 28, program year 2027 pays the PY2027 cooling column. + period: 2027 + input: + state_code: OR + county: MULTNOMAH_COUNTY_OR + spm_unit_size: 1 + heating_type: NONE + has_cooling_expense: true + pre_subsidy_electricity_expense: 1_500 + or_liheap_countable_income: 26_000 + output: + # PY2027 size 1 row "$20,164 $30,245" (page 72); Region 1 COOLING + # Electricity $310 (page 72). + or_liheap_income_band: 3 + or_liheap: 310 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 19814dfb755..a7b088e8bf9 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 @@ -6,9 +6,9 @@ class or_liheap_eligible(Variable): value_type = bool entity = SPMUnit definition_period = YEAR - label = "Oregon LIHEAP regular heating eligibility" + label = "Oregon LIHEAP regular heating or cooling eligibility" defined_for = StateCode.OR - # Manual PDF pages 11, 30, 36, 61, 77, 93-94; OAR 813-200-0020(1)(b). + # Manual PDF pages 11,30,36,61,77-81,90,93-94; OAR 813-200-0020(1)(b). 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", @@ -20,7 +20,8 @@ class or_liheap_eligible(Variable): "813-200-0020(1)(b) and the manual's energy burden table: subsidized housing " "with heat included in rent is excluded even when the household pays a " "separate non-heating utility bill. The Oregon sources do not prescribe a " - "SNAP immigration test. No asset or categorical income test applies. " + "SNAP immigration test. A home without heating qualifies on an electric bill " + "when it pays for cooling. No asset or categorical income test applies. " "Institutional residence, tribal duplicate awards, documentation and " "application timing are not modeled. A zero benefit above size 12 or for an " "unknown county denotes unsupported schedule coverage, not a legal denial." @@ -33,7 +34,17 @@ def formula(spm_unit, period, parameters): 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 + heating_type = spm_unit("heating_type", period) + # Eligible households are responsible for home heating or cooling costs, + # and the matrix pays electric cooling from its COOLING column. + cooling_only = ( + (heating_type == heating_type.possible_values.NONE) + & spm_unit("has_cooling_expense", period) + & (spm_unit("pre_subsidy_electricity_expense", period) > 0) + ) + energy_cost = ( + spm_unit("has_heating_expense", period) | heat_in_rent | cooling_only + ) income = spm_unit("or_liheap_countable_income", 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% @@ -44,4 +55,4 @@ def formula(spm_unit, period, parameters): 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 + return energy_cost & ~(heat_in_rent & subsidized) & income_eligible diff --git a/policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py b/policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py index 191e8078b17..13357f02632 100644 --- a/policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py +++ b/policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py @@ -5,7 +5,7 @@ class or_liheap(Variable): value_type = float entity = SPMUnit definition_period = YEAR - label = "Oregon LIHEAP regular heating benefit" + label = "Oregon LIHEAP regular heating or cooling benefit" unit = USD defined_for = "or_liheap_eligible" reference = ( @@ -17,13 +17,15 @@ class or_liheap(Variable): "https://www.oregon.gov/ohcs/energy-weatherization/Documents/manuals/09-23-2027-PY-2027-EA-Operations-Policy-Manual.pdf#page=72", ) documentation = ( - "Annual regular heating assistance, verified for program years 2025 to 2027. " + "Annual regular heating or cooling assistance, verified for PY2025 to PY2027. " "Earlier years use parameter backfilling and are unverified historical " "estimates. No actual-expense cap applies. Heat-in-rent households need the " "building heating fuel; a fuel without a matrix column pays zero as a coverage " "gap, not a denial. Discretionary bulk-fuel minimum-delivery payments and local " "supplements are unsupported because the necessary award information is " - "absent. Cooling, crisis and equipment assistance are excluded." + "absent. A home without heating that pays for electric cooling is paid from " + "the COOLING column, which equals the Electricity column in every row of the " + "PY2025 to PY2027 matrices. Crisis and equipment assistance are excluded." ) def formula(spm_unit, period, parameters): @@ -34,11 +36,14 @@ def formula(spm_unit, period, parameters): band = max_(spm_unit("or_liheap_income_band", period), 1) fuel = spm_unit("heating_type", period) types = fuel.possible_values + # An eligible home without heating pays for electric cooling, and the + # COOLING column equals the Electricity column. + cooling_only = (fuel == types.NONE) & spm_unit("has_cooling_expense", period) # Kerosene is billed as heating oil and a grid-tied solar home pays an # electricity bill, the same pairing heating_expense uses. amount = select( [ - (fuel == types.ELECTRICITY) | (fuel == types.SOLAR), + (fuel == types.ELECTRICITY) | (fuel == types.SOLAR) | cooling_only, (fuel == types.FUEL_OIL) | (fuel == types.KEROSENE), fuel == types.PROPANE, fuel == types.NATURAL_GAS, From 570db241c797b67eb88e9666bc12dd8e594ed3d1 Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 9 Nov 2026 23:06:10 -0500 Subject: [PATCH 2/7] Open Oregon's cooling column to households with no heating cost A household with any reported heating type and no heating cost, including a home without heating, qualifies on an electric bill when it pays for cooling, and the payment uses the cooling column whenever an eligible household has no heating cost. Cite manual page 67 and open the reference on its first cited page. Co-Authored-By: Claude Opus 5.5 --- changelog.d/or-liheap-cooling.fixed.md | 2 +- policyengine_us/programs.yaml | 2 +- .../eligibility/or_liheap_eligible.yaml | 25 +++++++++++------- .../gov/states/or/ohcs/liheap/or_liheap.yaml | 26 +++++++++++-------- .../liheap/eligibility/or_liheap_eligible.py | 25 +++++++++++------- .../gov/states/or/ohcs/liheap/or_liheap.py | 17 +++++++----- 6 files changed, 58 insertions(+), 39 deletions(-) diff --git a/changelog.d/or-liheap-cooling.fixed.md b/changelog.d/or-liheap-cooling.fixed.md index b8e0e007199..7032c9bc450 100644 --- a/changelog.d/or-liheap-cooling.fixed.md +++ b/changelog.d/or-liheap-cooling.fixed.md @@ -1 +1 @@ -Pay Oregon's LIHEAP standard payment from the matrix cooling column to households with no heating that pay an electric bill for cooling. +Pay Oregon's LIHEAP standard payment from the matrix cooling column to households with no heating cost, including homes without heating, that pay an electric bill for cooling. diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 7d1046428d0..1ff94205a60 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1282,7 +1282,7 @@ programs: variable: or_liheap parameter_prefix: gov.states.or.ohcs.liheap verified_years: "2025-2027" - notes: PY2025-PY2027 regular heating or cooling standard payment, with the two county regions, five fuel columns, the cooling column for cooling-only households and the roomer half payment. Crisis, Fuel Payment, equipment and OEAP assistance are out of scope. + notes: PY2025-PY2027 regular heating or cooling standard payment, with the two county regions, five fuel columns, the cooling column for households with no heating cost and the roomer half payment. Crisis, Fuel Payment, equipment and OEAP assistance are out of scope. - state: SC status: partial name: South Carolina LIHEAP 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 fbfc33bb1c0..3d82fb67bcb 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 @@ -103,19 +103,21 @@ # PY2027 60% SMI limit. or_liheap_eligible: [true, false] -- name: Case 6, a home without heating qualifies on an electric bill when it pays for cooling. +- name: Case 6, a household with no heating cost qualifies on an electric bill when it pays for cooling. period: 2026 input: - state_code: [OR, OR, OR, OR, OR, OR] - heating_type: [NONE, NONE, NONE, UNSPECIFIED, NONE, NONE] - has_cooling_expense: [true, false, true, true, true, true] + state_code: [OR, OR, OR, OR, OR, OR, OR] + heating_type: [NONE, NONE, NONE, UNSPECIFIED, NONE, NONE, WOOD] + # The wood-heated home gathers its own wood, so it has no heating cost. + has_heating_expense: [false, false, false, false, false, false, false] + has_cooling_expense: [true, false, true, true, true, true, true] # About $125 a month for electricity. - pre_subsidy_electricity_expense: [1_500, 1_500, 0, 1_500, 1_500, 1_500] - receives_housing_assistance: [false, false, false, false, true, false] + pre_subsidy_electricity_expense: [1_500, 1_500, 0, 1_500, 1_500, 1_500, 1_500] + receives_housing_assistance: [false, false, false, false, true, false, false] # About 30 hours a week at the Portland-metro minimum wage, as in Case 1; - # the last household is one dollar above the size 1 limit of $38,385 + # the sixth household is one dollar above the size 1 limit of $38,385 # (page 77). - or_liheap_countable_income: [26_000, 26_000, 26_000, 26_000, 26_000, 38_386] + or_liheap_countable_income: [26_000, 26_000, 26_000, 26_000, 26_000, 38_386, 26_000] output: # "Eligible" households are "responsible for their home heating or cooling # expenses" (page 90), and the matrices pay electric cooling from their @@ -126,5 +128,8 @@ # 4. UNSPECIFIED fuel: ineligible; # 5. subsidized housing paying its own electric bill: "pays a vendor # directly for utility costs" is an energy burden (page 93), eligible; - # 6. income above the limit: ineligible. - or_liheap_eligible: [true, false, false, false, true, false] + # 6. income above the limit: ineligible; + # 7. wood heat with no heating cost, pays for cooling on an electric + # bill: the benefit goes to the energy type it is applied to + # (page 67), eligible. + or_liheap_eligible: [true, false, false, false, true, false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml index 377609a4dbf..e65d5bff29e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml @@ -604,22 +604,26 @@ # PY2026 pages 78-81, PY2027 pages 72-75). Countable income of $26,000 is about # 30 hours a week at the Portland-metro minimum wage, and about $125 a month # pays the electric bill. -- name: Case 26, a home without heating that pays for electric cooling receives the cooling column. +- name: Case 26, a household with no heating cost that pays for electric cooling receives the cooling column. period: 2026 input: - state_code: [OR, OR, OR] - county: [MULTNOMAH_COUNTY_OR, DESCHUTES_COUNTY_OR, MULTNOMAH_COUNTY_OR] - spm_unit_size: [1, 1, 1] - heating_type: [NONE, NONE, NONE] - has_cooling_expense: [true, true, false] - pre_subsidy_electricity_expense: [1_500, 1_500, 1_500] - or_liheap_countable_income: [26_000, 26_000, 26_000] + state_code: [OR, OR, OR, OR] + county: [MULTNOMAH_COUNTY_OR, DESCHUTES_COUNTY_OR, MULTNOMAH_COUNTY_OR, DESCHUTES_COUNTY_OR] + spm_unit_size: [1, 1, 1, 1] + heating_type: [NONE, NONE, NONE, WOOD] + # The wood-heated home gathers its own wood, so it has no heating cost. + has_heating_expense: [false, false, false, false] + has_cooling_expense: [true, true, false, true] + pre_subsidy_electricity_expense: [1_500, 1_500, 1_500, 1_500] + or_liheap_countable_income: [26_000, 26_000, 26_000, 26_000] output: # PY2026 size 1 row "$19,194 $28,789" (page 78). - or_liheap_income_band: [3, 3, 3] + or_liheap_income_band: [3, 3, 3, 3] # COOLING Electricity: Region 1 $300 (page 78), Region 2 $335 (page 80). - # Without a cooling cost the home is ineligible, $0. - or_liheap: [300, 335, 0] + # Without a cooling cost the home is ineligible, $0. The wood-heated home + # applies its benefit to electricity, so it is paid from the COOLING + # column rather than Wood/Pellets (page 67). + or_liheap: [300, 335, 0, 335] - name: Case 27, program year 2025 pays the PY2025 cooling column. period: 2025 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 a7b088e8bf9..659b17633f4 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 @@ -8,9 +8,9 @@ class or_liheap_eligible(Variable): definition_period = YEAR label = "Oregon LIHEAP regular heating or cooling eligibility" defined_for = StateCode.OR - # Manual PDF pages 11,30,36,61,77-81,90,93-94; OAR 813-200-0020(1)(b). + # Manual PDF pages 11,30,36,61,67,77-81,90,93-94; OAR 813-200-0020(1)(b). reference = ( - "https://www.oregon.gov/ohcs/energy-weatherization/Documents/2026%20Final%20Energy%20Assistance%20Intake%20Operations%20%26%20Policy%20Manual.pdf#page=61", + "https://www.oregon.gov/ohcs/energy-weatherization/Documents/2026%20Final%20Energy%20Assistance%20Intake%20Operations%20%26%20Policy%20Manual.pdf#page=11", "https://www.law.cornell.edu/regulations/oregon/Or-Admin-Code-SS-813-200-0020", "https://www.law.cornell.edu/uscode/text/42/8624", ) @@ -20,8 +20,9 @@ class or_liheap_eligible(Variable): "813-200-0020(1)(b) and the manual's energy burden table: subsidized housing " "with heat included in rent is excluded even when the household pays a " "separate non-heating utility bill. The Oregon sources do not prescribe a " - "SNAP immigration test. A home without heating qualifies on an electric bill " - "when it pays for cooling. No asset or categorical income test applies. " + "SNAP immigration test. A household with no heating cost, including a home " + "without heating, qualifies on an electric bill when it pays for cooling. No " + "asset or categorical income test applies. " "Institutional residence, tribal duplicate awards, documentation and " "application timing are not modeled. A zero benefit above size 12 or for an " "unknown county denotes unsupported schedule coverage, not a legal denial." @@ -35,16 +36,20 @@ def formula(spm_unit, period, parameters): "receives_housing_assistance", period ) | spm_unit.household("is_in_public_housing", period) heating_type = spm_unit("heating_type", period) - # Eligible households are responsible for home heating or cooling costs, - # and the matrix pays electric cooling from its COOLING column. + heating_cost = spm_unit("has_heating_expense", period) | heat_in_rent + # Eligible households are responsible for home heating or cooling costs + # (page 90). A household with no heating cost, including a home without + # heating, qualifies on an electric bill it pays for cooling; the + # benefit then follows the energy type it is applied to (page 67), and + # the matrix pays electric cooling from its COOLING column. heating_type + # is a required input, so UNSPECIFIED does not qualify. cooling_only = ( - (heating_type == heating_type.possible_values.NONE) + (heating_type != heating_type.possible_values.UNSPECIFIED) + & ~heating_cost & spm_unit("has_cooling_expense", period) & (spm_unit("pre_subsidy_electricity_expense", period) > 0) ) - energy_cost = ( - spm_unit("has_heating_expense", period) | heat_in_rent | cooling_only - ) + energy_cost = heating_cost | cooling_only income = spm_unit("or_liheap_countable_income", 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% diff --git a/policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py b/policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py index 13357f02632..e2af8f1d55d 100644 --- a/policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py +++ b/policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py @@ -23,9 +23,10 @@ class or_liheap(Variable): "building heating fuel; a fuel without a matrix column pays zero as a coverage " "gap, not a denial. Discretionary bulk-fuel minimum-delivery payments and local " "supplements are unsupported because the necessary award information is " - "absent. A home without heating that pays for electric cooling is paid from " - "the COOLING column, which equals the Electricity column in every row of the " - "PY2025 to PY2027 matrices. Crisis and equipment assistance are excluded." + "absent. A household with no heating cost that qualifies on electric cooling " + "is paid from the COOLING column, which equals the Electricity column in " + "every row of the PY2025 to PY2027 matrices. Crisis and equipment assistance " + "are excluded." ) def formula(spm_unit, period, parameters): @@ -36,9 +37,13 @@ def formula(spm_unit, period, parameters): band = max_(spm_unit("or_liheap_income_band", period), 1) fuel = spm_unit("heating_type", period) types = fuel.possible_values - # An eligible home without heating pays for electric cooling, and the - # COOLING column equals the Electricity column. - cooling_only = (fuel == types.NONE) & spm_unit("has_cooling_expense", period) + # An eligible household with neither a heating cost nor heat in the rent + # qualified on electric cooling (or_liheap_eligible), and the COOLING + # column equals the Electricity column. + cooling_only = ~( + spm_unit("has_heating_expense", period) + | spm_unit("heat_expense_included_in_rent", period) + ) # Kerosene is billed as heating oil and a grid-tied solar home pays an # electricity bill, the same pairing heating_expense uses. amount = select( From 2533627609ee76b968a37ba1c3a734e49651c75b Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 11 Nov 2026 22:54:07 -0500 Subject: [PATCH 3/7] Stop Oregon LIHEAP income limits at the federal maximum Co-Authored-By: Claude Fable 5.2 --- changelog.d/or-liheap-cooling.fixed.md | 2 +- .../eligibility/or_liheap_eligible.yaml | 6 +-- .../eligibility/or_liheap_income_limit.yaml | 41 +++++++++++------ .../states/or/ohcs/liheap/integration.yaml | 10 +++-- .../gov/states/or/ohcs/liheap/or_liheap.yaml | 37 ++++++++-------- .../eligibility/or_liheap_income_limit.py | 18 +++++++- source_conflicts/candidates.yaml | 44 +++++++++++++++++++ 7 files changed, 118 insertions(+), 40 deletions(-) diff --git a/changelog.d/or-liheap-cooling.fixed.md b/changelog.d/or-liheap-cooling.fixed.md index 7032c9bc450..7fea29c666d 100644 --- a/changelog.d/or-liheap-cooling.fixed.md +++ b/changelog.d/or-liheap-cooling.fixed.md @@ -1 +1 @@ -Pay Oregon's LIHEAP standard payment from the matrix cooling column to households with no heating cost, including homes without heating, that pay an electric bill for cooling. +Pay Oregon's LIHEAP standard payment from the matrix cooling column to households with no heating cost, including homes without heating, that pay an electric bill for cooling. Stop Oregon's LIHEAP income limits at the federal maximum, the greater of HHS's 60% state median income amount and 150% of the poverty guideline. diff --git a/policyengine_us/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 3d82fb67bcb..fa2f90455fd 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 @@ -115,9 +115,9 @@ pre_subsidy_electricity_expense: [1_500, 1_500, 0, 1_500, 1_500, 1_500, 1_500] receives_housing_assistance: [false, false, false, false, true, false, false] # About 30 hours a week at the Portland-metro minimum wage, as in Case 1; - # the sixth household is one dollar above the size 1 limit of $38,385 - # (page 77). - or_liheap_countable_income: [26_000, 26_000, 26_000, 26_000, 26_000, 38_386, 26_000] + # the sixth household is one dollar above the size 1 limit of $38,384, + # HHS's FY2026 60% state median income amount (page 77 prints $38,385). + or_liheap_countable_income: [26_000, 26_000, 26_000, 26_000, 26_000, 38_385, 26_000] output: # "Eligible" households are "responsible for their home heating or cooling # expenses" (page 90), and the matrices pay electric cooling from their diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.yaml index 61a754aa0ac..f2658a92402 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.yaml @@ -7,25 +7,36 @@ # https://www.oregon.gov/ohcs/energy-weatherization/Documents/PY25%20EA%20Operations%20%20Policy%20Manual-%20FINAL%209-27-24.pdf#page=57 # PY2027, page 71: # https://www.oregon.gov/ohcs/energy-weatherization/Documents/manuals/09-23-2027-PY-2027-EA-Operations-Policy-Manual.pdf#page=71 -- name: Case 1, published FY2026 annual income limits for the odd household sizes 1 to 11. +# Each limit stops at the federal maximum of 42 U.S.C. 8624(b)(2)(B): the greater +# of HHS's 60% state median income amount (60% of the four-person median, rounded +# down, times the size factor, rounded down) and 150% of the prior year's poverty +# guideline. HHS's FY2026 amounts for Oregon, sizes 1 to 6: $38,384, $50,194, +# $62,005, $73,816, $85,626, $97,437: +# https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=2 +- name: Case 1, FY2026 annual income limits for the odd household sizes 1 to 11 stop at the federal maximum. period: 2026 input: state_code: [OR, OR, OR, OR, OR, OR] spm_unit_size: [1, 3, 5, 7, 9, 11] output: - # FY2026 page 77: size 1 $38,385, size 3 $62,006, size 5 $85,627, size 7 - # $99,652, size 9 $104,081, size 11 $108,510. - or_liheap_income_limit: [38_385, 62_006, 85_627, 99_652, 104_081, 108_510] + # FY2026 page 77 prints size 1 $38,385, size 3 $62,006, size 5 $85,627, + # size 7 $99,652, size 9 $104,081, size 11 $108,510. HHS's amount is $1 + # lower at each: 73,816 x 1.35 = 99,651 at size 7, x 1.41 = 104,080 at + # size 9 and x 1.47 = 108,509 at size 11. + or_liheap_income_limit: [38_384, 62_005, 85_626, 99_651, 104_080, 108_509] -- name: Case 2, published PY2025 annual income limits for the odd household sizes 1 to 11. +- name: Case 2, PY2025 annual income limits for the odd household sizes 1 to 11 stop at the federal maximum. period: 2025 input: state_code: [OR, OR, OR, OR, OR, OR] spm_unit_size: [1, 3, 5, 7, 9, 11] output: - # PY2025 page 57: size 1 $36,811, size 3 $59,464, size 5 $82,117, size 7 - # $95,567, size 9 $99,814, size 11 $104,062. - or_liheap_income_limit: [36_811, 59_464, 82_117, 95_567, 99_814, 104_062] + # PY2025 page 57 prints size 1 $36,811, size 3 $59,464, size 5 $82,117, + # size 7 $95,567, size 9 $99,814, size 11 $104,062. The FY2025 four-person + # median is $117,983; 60% rounded down is $70,789, and the size factors + # 0.52, 0.84, 1.16, 1.35, 1.41 and 1.47 give $36,810, $59,462, $82,115, + # $95,565, $99,812 and $104,059. + or_liheap_income_limit: [36_810, 59_462, 82_115, 95_565, 99_812, 104_059] - name: Case 3, published PY2027 annual income limits at the sizes whose 60 percent product is a whole dollar. period: 2027 @@ -36,15 +47,19 @@ # PY2027 page 71: size 2 $52,734, size 3 $65,142, size 6 $102,366, size 8 # $107,019, size 10 $111,672, size 12 $116,325. The FY2027 four-person # median is $129,250, so these products are exact dollars (129,250 x 0.68 - # x 0.6 = 52,734) and a float32 ceiling would add $1 to each. + # x 0.6 = 52,734) and a float32 ceiling would add $1 to each. They equal + # the federal maximum, so none is lowered. or_liheap_income_limit: [52_734, 65_142, 102_366, 107_019, 111_672, 116_325] -- name: Case 4, published FY2026 annual income limits for the even household sizes 2 to 12. +- name: Case 4, FY2026 annual income limits for the even household sizes 2 to 12 stop at the federal maximum. period: 2026 input: state_code: [OR, OR, OR, OR, OR, OR] spm_unit_size: [2, 4, 6, 8, 10, 12] output: - # FY2026 page 77: size 2 $50,196, size 4 $73,817, size 6 $97,438, size 8 - # $101,867, size 10 $106,296, size 12 $110,725. - or_liheap_income_limit: [50_196, 73_817, 97_438, 101_867, 106_296, 110_725] + # FY2026 page 77 prints size 2 $50,196, size 4 $73,817, size 6 $97,438, + # size 8 $101,867, size 10 $106,296, size 12 $110,725. HHS's amount is $2 + # lower at size 2 and $1 lower at sizes 4 to 10 (73,816 x 1.38 = 101,866; + # x 1.44 = 106,295). At size 12, 150% of the 2025 guideline (76,150 x 1.5 = + # 114,225) is the higher federal maximum, so the printed amount stays. + or_liheap_income_limit: [50_194, 73_816, 97_437, 101_866, 106_295, 110_725] diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/integration.yaml index ffa79bfc7a3..409603b16ce 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/integration.yaml @@ -48,8 +48,9 @@ # 14,400 + pension 600 (page 44) + interest 201, counted because it is # over $200 a year (pages 43 and 50) = 15,201. or_liheap_countable_income: 15_201 - # 60% of state median income, size 2: $50,196 (page 77). - or_liheap_income_limit: 50_196 + # 60% of state median income, size 2: HHS's FY2026 amount is $50,194 + # (page 77 prints $50,196). + or_liheap_income_limit: 50_194 # Deschutes County is in the Region 2 list (page 80). or_liheap_region: 2 # Size 2, second row "$12,550 $25,098" (page 80). Counting the child's @@ -78,8 +79,9 @@ # Income earned by a member aged 18 or over who is enrolled in high # school is not counted (pages 41 and 53); there is no other income. or_liheap_countable_income: 0 - # 60% of state median income, size 1: $38,385 (page 77). - or_liheap_income_limit: 38_385 + # 60% of state median income, size 1: HHS's FY2026 amount is $38,384 + # (page 77 prints $38,385). + or_liheap_income_limit: 38_384 # Size 1, first row "$0 $9,597" (page 78). Counting the 13,100 of wages # would give the second row instead. or_liheap_income_band: 1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml index e65d5bff29e..580d6d8fa22 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/or_liheap.yaml @@ -216,7 +216,7 @@ # size 12 (page 81): $750, $750, $645, $460 or_liheap: [750, 655, 545, 390, 750, 725, 605, 435, 750, 750, 645, 460, 750, 750, 645, 460, 750, 750, 645, 460, 750, 750, 645, 460] -- name: Case 11, the published income limit includes the dollar above the last matrix row. +- name: Case 11, the income limit stops at the federal maximum, a dollar below the top of the last matrix row. period: 2026 input: state_code: [OR, OR, OR] @@ -225,18 +225,17 @@ heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY] # About $125 a month for electric heat. pre_subsidy_electricity_expense: [1_500, 1_500, 1_500] - # The last size 2 matrix row ends at $50,195 (page 78) while the size 2 - # income limit is $50,196 (page 77): the top of the row, the limit itself - # and one dollar above the limit. - or_liheap_countable_income: [50_195, 50_196, 50_197] + # The last size 2 matrix row ends at $50,195 (page 78) and page 77 prints + # a size 2 limit of $50,196. Both are above HHS's FY2026 60% state median + # income amount for two people, $50,194, the most 42 U.S.C. 8624(b)(2)(B) + # allows: the limit itself, the top of the row and the printed limit. + or_liheap_countable_income: [50_194, 50_195, 50_196] output: - # Size 2 limit $50,196 (page 77): $50,195 and $50,196 are within it, - # $50,197 is not. - or_liheap_eligible: [true, true, false] + # $50,194 is within the limit; $50,195 and $50,196 are not. + or_liheap_eligible: [true, false, false] # Region 1, size 2, "$37,647 $50,195", Electricity $275 (page 78). The - # eligible household at exactly $50,196 is paid from that same last row. - # The ineligible household receives $0. - or_liheap: [275, 275, 0] + # ineligible households receive $0. + or_liheap: [275, 0, 0] - name: Case 12, income bands include their printed tops and change at the next dollar. period: 2026 @@ -439,7 +438,8 @@ or_liheap: [310, 0] # PY2026 manual, page 44: rental-property income and pensions paid to surviving -# dependents count separately from wages. Page 77 gives the $38,385 size-one limit. +# dependents count separately from wages. The size-one limit is $38,384, HHS's +# FY2026 60% state median income amount (page 77 prints $38,385). # https://www.oregon.gov/ohcs/energy-weatherization/Documents/2026%20Final%20Energy%20Assistance%20Intake%20Operations%20%26%20Policy%20Manual.pdf#page=44 - name: Case 19, farm rental income puts a gas-heating household over the income limit. period: 2026 @@ -455,9 +455,9 @@ heating_type: NATURAL_GAS gas_expense: 1_200 output: - # $30,000 wages + $10,000 farm rents exceeds $38,385. + # $30,000 wages + $10,000 farm rents exceeds $38,384. or_liheap_countable_income: 40_000 - or_liheap_income_limit: 38_385 + or_liheap_income_limit: 38_384 or_liheap_eligible: false or_liheap: 0 @@ -475,9 +475,9 @@ heating_type: NATURAL_GAS gas_expense: 1_200 output: - # $30,000 wages + $10,000 survivor pension exceeds $38,385. + # $30,000 wages + $10,000 survivor pension exceeds $38,384. or_liheap_countable_income: 40_000 - or_liheap_income_limit: 38_385 + or_liheap_income_limit: 38_384 or_liheap_eligible: false or_liheap: 0 @@ -540,8 +540,9 @@ fuel_oil_expense: [0, 0, 2_400, 2_400] or_liheap_countable_income: [9_400, 0, 20_000, 20_000] output: - # PY2025 size 1 limit $36,811 (page 57). - or_liheap_income_limit: [36_811, 36_811, 36_811, 36_811] + # PY2025 size 1 limit: page 57 prints $36,811; the federal maximum is + # $36,810 (60% of $117,983, rounded down, x 0.52). + or_liheap_income_limit: [36_810, 36_810, 36_810, 36_810] # PY2025 size 1 rows "$0 $9,203", "$9,204 $18,406", "$18,407 $27,609" # (page 58). or_liheap_income_band: [2, 1, 3, 3] diff --git a/policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.py b/policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.py index f587bc50125..276986514fe 100644 --- a/policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.py +++ b/policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.py @@ -1,4 +1,6 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import liheap_smi_limit +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class or_liheap_income_limit(Variable): @@ -9,6 +11,9 @@ class or_liheap_income_limit(Variable): unit = USD defined_for = StateCode.OR reference = ( + "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", + # FY2026 federal amounts + "https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=2", "https://www.oregon.gov/ohcs/energy-weatherization/Documents/PY25%20EA%20Operations%20%20Policy%20Manual-%20FINAL%209-27-24.pdf#page=57", "https://www.oregon.gov/ohcs/energy-weatherization/Documents/2026%20Final%20Energy%20Assistance%20Intake%20Operations%20%26%20Policy%20Manual.pdf#page=77", "https://www.oregon.gov/ohcs/energy-weatherization/Documents/manuals/09-23-2027-PY-2027-EA-Operations-Policy-Manual.pdf#page=71", @@ -22,4 +27,15 @@ def formula(spm_unit, period, parameters): # which lifts a whole-dollar product above the integer and would add $1. # hhs_smi uses the requested year's SMI. smi = spm_unit("hhs_smi", period).astype(np.float64) - return np.ceil(np.round(smi * p.smi_rate, 2)) + published = np.ceil(np.round(smi * p.smi_rate, 2)) + # 42 U.S.C. 8624(b)(2)(B) pays no household above the greater of 60% of + # state median income, in the amounts HHS publishes by household size, + # and 150% of the poverty guideline. A published amount that rounds + # above that maximum stops there. + p_hhs = parameters(period).gov.hhs.liheap + size = spm_unit("spm_unit_size", period) + state = spm_unit.household("state_code_str", period) + state_group = spm_unit.household("state_group_str", period) + smi_maximum = liheap_smi_limit(size, state, p_hhs.smi_limit, period, parameters) + guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + return min_(published, max_(smi_maximum, guideline * p_hhs.fpg_limit)) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 9d02eda84fd..0c9827943c9 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -9219,6 +9219,50 @@ candidates: state: unreviewed note: PE-US applies the floor to the prior year's guideline, rounded to cents, with the statute's strict "less than" (or_liheap_eligible.py). +- id: us-or:liheap-income-limit-above-federal-ceiling + program: liheap + years: + from: 2025 + to: 2027 + type: federal-fiscal + question: Can Oregon's rounded-up LIHEAP income limits pay a household whose income exceeds both 150% of the poverty + guideline and HHS's 60% state median income amount? + sources: + - kind: statute + citation: 42 U.S.C. 8624(b)(2)(B) + url: https://www.law.cornell.edu/uscode/text/42/8624#b_2_B + - kind: guidance + citation: HHS LIHEAP IM 2025-02 Attachment 4, Mandatory Use in LIHEAP for FY26, Oregon, page 2 + url: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=2 + - kind: manual + citation: 2026 Energy Assistance Intake, Operations and Policy Manual, 60% of State Median Income by Household Size, + PDF page 77 + url: https://www.oregon.gov/ohcs/energy-weatherization/Documents/2026%20Final%20Energy%20Assistance%20Intake%20Operations%20%26%20Policy%20Manual.pdf#page=77 + - kind: manual + citation: PY2025 Energy Assistance Operations and Policy Manual, income limits, PDF page 57 + url: https://www.oregon.gov/ohcs/energy-weatherization/Documents/PY25%20EA%20Operations%20%20Policy%20Manual-%20FINAL%209-27-24.pdf#page=57 + readings: + statute: Payments go only to households whose income does not exceed the greater of 150% of the poverty guideline + and 60% of the state median income that HHS publishes and adjusts for household size. + other: The manuals print 60% of the size-adjusted median rounded up to the next dollar, $1 or $2 above HHS's amount + at most sizes. + example: In FY2026, two people with $50,195 of countable income and electric heat in Multnomah County are within the + printed $50,196 limit, which would pay $275, but exceed the $50,194 federal maximum and receive $0 in the PR. + pe_us: + follows: statute + code: + - policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10736 + state: ruled + note: 'Ruled under the 2026-10-19 statute-first rule. The PR stops each limit at the federal maximum. Printed and capped + annual limits: FY2026 size 1, $38,385 and $38,384; 2, $50,196 and $50,194; 3, $62,006 and $62,005; 4, $73,817 and + $73,816; 5, $85,627 and $85,626; 6, $97,438 and $97,437; sizes 7 to 11, $1 lower ($99,652 and $99,651 at 7); from + size 12 the printed amount stays, because 150% of the guideline is the higher maximum. PY2025, with the 60% amounts + computed from the $117,983 four-person median because HHS''s FY2025 table was not located: size 1, $36,811 and + $36,810; 3, $59,464 and $59,462; 5, $82,117 and $82,115. The PY2027 limits printed at sizes 1 to 6 are whole-dollar + products and equal HHS''s method. The last payment band for two people ends at $50,195, above the capped limit; see + us-or:liheap-final-payment-band-bound.' - id: us-pa:liheap-interest-dividend-threshold program: liheap years: From b408f163d11495597d2c0ecf12558a4f6f801ba6 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 11 Nov 2026 23:22:30 -0500 Subject: [PATCH 4/7] Cite HHS's FY2025 median income table for the capped limits Co-Authored-By: Claude Opus 5.5 --- source_conflicts/candidates.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 0c9827943c9..d51f6e0c978 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -9241,6 +9241,9 @@ candidates: - kind: manual citation: PY2025 Energy Assistance Operations and Policy Manual, income limits, PDF page 57 url: https://www.oregon.gov/ohcs/energy-weatherization/Documents/PY25%20EA%20Operations%20%20Policy%20Manual-%20FINAL%209-27-24.pdf#page=57 + - kind: guidance + citation: HHS LIHEAP IM 2024-02 Attachment 4, Mandatory Use in LIHEAP for FY25, Oregon, pages 2 and 5 + url: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM%202024-02_Att4SMITable.pdf#page=2 readings: statute: Payments go only to households whose income does not exceed the greater of 150% of the poverty guideline and 60% of the state median income that HHS publishes and adjusts for household size. @@ -9258,8 +9261,8 @@ candidates: note: 'Ruled under the 2026-10-19 statute-first rule. The PR stops each limit at the federal maximum. Printed and capped annual limits: FY2026 size 1, $38,385 and $38,384; 2, $50,196 and $50,194; 3, $62,006 and $62,005; 4, $73,817 and $73,816; 5, $85,627 and $85,626; 6, $97,438 and $97,437; sizes 7 to 11, $1 lower ($99,652 and $99,651 at 7); from - size 12 the printed amount stays, because 150% of the guideline is the higher maximum. PY2025, with the 60% amounts - computed from the $117,983 four-person median because HHS''s FY2025 table was not located: size 1, $36,811 and + size 12 the printed amount stays, because 150% of the guideline is the higher maximum. PY2025, from HHS''s FY2025 amounts + (LIHEAP IM 2024-02 Attachment 4): size 1, $36,811 and $36,810; 3, $59,464 and $59,462; 5, $82,117 and $82,115. The PY2027 limits printed at sizes 1 to 6 are whole-dollar products and equal HHS''s method. The last payment band for two people ends at $50,195, above the capped limit; see us-or:liheap-final-payment-band-bound.' From bbfe7a665044622f21f07837e5480f05331591f5 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 11 Nov 2026 23:24:37 -0500 Subject: [PATCH 5/7] Pin the PY2027 Oregon limits the federal cap lowers Co-Authored-By: Claude Opus 5.5 --- .../liheap/eligibility/or_liheap_income_limit.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.yaml index f2658a92402..4d31d323b1c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/ohcs/liheap/eligibility/or_liheap_income_limit.yaml @@ -63,3 +63,15 @@ # x 1.44 = 106,295). At size 12, 150% of the 2025 guideline (76,150 x 1.5 = # 114,225) is the higher federal maximum, so the printed amount stays. or_liheap_income_limit: [50_194, 73_816, 97_437, 101_866, 106_295, 110_725] + +- name: Case 5, PY2027 limits whose 60 percent product ends in 50 cents stop at the federal maximum. + period: 2027 + input: + state_code: [OR, OR, OR] + spm_unit_size: [7, 9, 11] + output: + # The FY2027 four-person median is $129,250, and 60% of it is $77,550. + # Times the size factors 1.35, 1.41 and 1.47 that is $104,692.50, + # $109,345.50 and $113,998.50. Rounded up they would be $104,693, + # $109,346 and $113,999; HHS rounds down, so each limit is $1 lower. + or_liheap_income_limit: [104_692, 109_345, 113_998] From a21697d7e9c2fbc92ce4fc6906eed3f29a0c250c Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 11 Nov 2026 23:25:02 -0500 Subject: [PATCH 6/7] List the PY2027 Oregon sizes in the federal-cap candidate Co-Authored-By: Claude Opus 5.5 --- source_conflicts/candidates.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index d51f6e0c978..5533e750ccf 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -9261,9 +9261,9 @@ candidates: note: 'Ruled under the 2026-10-19 statute-first rule. The PR stops each limit at the federal maximum. Printed and capped annual limits: FY2026 size 1, $38,385 and $38,384; 2, $50,196 and $50,194; 3, $62,006 and $62,005; 4, $73,817 and $73,816; 5, $85,627 and $85,626; 6, $97,438 and $97,437; sizes 7 to 11, $1 lower ($99,652 and $99,651 at 7); from - size 12 the printed amount stays, because 150% of the guideline is the higher maximum. PY2025, from HHS''s FY2025 amounts - (LIHEAP IM 2024-02 Attachment 4): size 1, $36,811 and - $36,810; 3, $59,464 and $59,462; 5, $82,117 and $82,115. The PY2027 limits printed at sizes 1 to 6 are whole-dollar + size 12 the printed amount stays, because 150% of the guideline is the higher maximum. PY2025, from HHS''s FY2025 + amounts (LIHEAP IM 2024-02 Attachment 4): size 1, $36,811 and $36,810; 3, $59,464 and $59,462; 5, $82,117 and + $82,115. PY2027: sizes 7, 9 and 11 are $1 lower ($104,693 and $104,692 at 7); the other sizes are whole-dollar products and equal HHS''s method. The last payment band for two people ends at $50,195, above the capped limit; see us-or:liheap-final-payment-band-bound.' - id: us-pa:liheap-interest-dividend-threshold From cfe1c6be84332eeb56eac42f8a1bac479e7a9b01 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 12 Nov 2026 12:09:21 -0500 Subject: [PATCH 7/7] Record Oregon's one-payment reading as a source-conflict candidate Co-Authored-By: Claude Opus 5.5 --- policyengine_us/programs.yaml | 2 +- source_conflicts/candidates.yaml | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index f8e69e20f26..ceba9779e77 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1330,7 +1330,7 @@ programs: variable: or_liheap parameter_prefix: gov.states.or.ohcs.liheap verified_years: "2025-2027" - notes: PY2025-PY2027 regular heating or cooling standard payment, with the two county regions, five fuel columns, the cooling column for households with no heating cost and the roomer half payment. Crisis, Fuel Payment, equipment and OEAP assistance are out of scope. + notes: PY2025-PY2027 regular heating or cooling standard payment, one a year, with the two county regions, five fuel columns, the cooling column for households with no heating cost and the roomer half payment. A cooling payment on top of a heating payment, crisis, Fuel Payment, equipment and OEAP assistance are not modeled. - state: SC status: partial name: South Carolina LIHEAP diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 5533e750ccf..792b22ec60e 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -9160,6 +9160,46 @@ candidates: state: ruled note: The code follows the statute and subtracts every federal refundable credit except the EITC, plus the premium tax credit, including credits the worksheet does not list, such as the additional child tax credit outside 2021. +- id: us-or:liheap-cooling-payment-after-heating-payment + program: liheap + years: + from: 2025 + to: 2027 + type: program + note: program year as the program defines it + question: Can an Oregon household that received a LIHEAP standard payment for heating also receive one for cooling in the + same program year? + sources: + - kind: manual + citation: 2026 Energy Assistance Intake, Operations and Policy Manual, separated households and standard payment, PDF + pages 31 and 61 + url: https://www.oregon.gov/ohcs/energy-weatherization/Documents/2026%20Final%20Energy%20Assistance%20Intake%20Operations%20%26%20Policy%20Manual.pdf#page=31 + - kind: plan + citation: Oregon FFY2026 LIHEAP State Plan, items 1.1 and 1.2 (PDF page 4) and the crisis explanation (PDF page 13) + url: https://liheapch.acf.gov/docs/2026/state-plans/OR_Plan_2026.pdf#page=4 + - kind: guidance + citation: Oregon Health Authority, OHOP Housing Services page, LIHEAP cooling season announcements (2024, 2025 and 2026 + seasons; 2026 capture of August 13, 2026) + url: https://web.archive.org/web/20260813121701/https://www.oregon.gov/oha/PH/DiseasesConditions/HIVSTDViralHepatitis/HIVCareTreatment/Pages/housing.aspx + readings: + statute: No statute is supplied; the manual pays one standard payment a program year, and a separated household's adults + may not "receive another standard payment during the current program year". + other: The Oregon Health Authority's OHOP page says "Clients who have already received a heating payment during the year + may still be eligible for a cooling payment!", and the plans fund heating and cooling as separate components. + example: In 2026, one person in Multnomah County with $26,000 of countable income, gas heat with a $960 bill, a cooling + cost and a $1,500 electric bill receives $435 under the one-payment reading, and $435 plus $300 from the COOLING column, + $735, if a cooling payment can follow a heating payment. + pe_us: + follows: gap-fill + code: + - policyengine_us/variables/gov/states/or/ohcs/liheap/or_liheap.py + - policyengine_us/variables/gov/states/or/ohcs/liheap/eligibility/or_liheap_eligible.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10736 + state: open + note: 'PE-US follows the manual: a household with a heating cost gets its heating fuel column, never a second cooling + payment. The OHOP page is a subgrantee notice and says "may". If OHCS confirms both are payable, Oregon needs a separate + cooling amount and a second entry in the national LIHEAP list.' - id: us-or:liheap-final-payment-band-bound program: liheap years: