From cc2b1045bc63254a771c300ea92864aac4ac7caa Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 19:24:30 -0400 Subject: [PATCH 1/5] Add Colorado LEAP regular heating assistance --- changelog.d/co-leap-wave2c.added.md | 1 + .../leap/eligibility/max_household_size.yaml | 11 + .../leap/income/additional_person_amount.yaml | 11 + .../income/additional_person_threshold.yaml | 11 + .../co/cdhs/leap/income/earned_min_age.yaml | 11 + .../states/co/cdhs/leap/income/smi_rate.yaml | 11 + .../co/cdhs/leap/income/sources/earned.yaml | 12 + .../co/cdhs/leap/income/sources/unearned.yaml | 17 + .../additional_person_amounts.yaml | 11 + .../leap/payment/contribution/fpg_rates.yaml | 11 + .../cdhs/leap/payment/contribution/rates.yaml | 11 + .../leap/payment/electric_heat_share.yaml | 29 ++ .../co/cdhs/leap/payment/fpg_year_lag.yaml | 12 + .../payment/heat_in_rent/electricity.yaml | 29 ++ .../payment/heat_in_rent/natural_gas.yaml | 29 ++ .../heat_in_rent/oil_kerosene_coal.yaml | 29 ++ .../leap/payment/heat_in_rent/propane.yaml | 29 ++ .../cdhs/leap/payment/heat_in_rent/wood.yaml | 29 ++ .../cdhs/leap/payment/initial_reduction.yaml | 13 + .../states/co/cdhs/leap/payment/maximum.yaml | 11 + .../states/co/cdhs/leap/payment/minimum.yaml | 11 + .../payment/subsidized_housing_deduction.yaml | 11 + policyengine_us/programs.yaml | 10 +- .../gov/states/co/cdhs/leap/co_leap.yaml | 320 ++++++++++++++++++ .../cdhs/leap/co_leap_countable_income.yaml | 66 ++++ .../leap/co_leap_countable_income_person.yaml | 316 +++++++++++++++++ .../states/co/cdhs/leap/co_leap_eligible.yaml | 43 +++ .../co/cdhs/leap/co_leap_heating_cost.yaml | 144 ++++++++ .../co/cdhs/leap/co_leap_household_size.yaml | 171 ++++++++++ .../co_leap_income_contribution_rate.yaml | 53 +++ .../co/cdhs/leap/co_leap_income_limit.yaml | 26 ++ .../gov/states/co/cdhs/leap/co_leap.py | 31 ++ .../co/cdhs/leap/co_leap_countable_income.py | 12 + .../leap/co_leap_countable_income_person.py | 31 ++ .../co/cdhs/leap/co_leap_dwelling_type.py | 25 ++ .../states/co/cdhs/leap/co_leap_eligible.py | 34 ++ .../co/cdhs/leap/co_leap_heating_cost.py | 50 +++ .../co/cdhs/leap/co_leap_household_size.py | 19 ++ .../leap/co_leap_income_contribution_rate.py | 45 +++ .../co/cdhs/leap/co_leap_income_limit.py | 28 ++ 40 files changed, 1773 insertions(+), 1 deletion(-) create mode 100644 changelog.d/co-leap-wave2c.added.md create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/eligibility/max_household_size.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/income/additional_person_amount.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/income/additional_person_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/income/earned_min_age.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/income/smi_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/additional_person_amounts.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/fpg_rates.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/rates.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/electric_heat_share.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/electricity.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/natural_gas.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/oil_kerosene_coal.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/propane.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/wood.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/initial_reduction.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/maximum.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/minimum.yaml create mode 100644 policyengine_us/parameters/gov/states/co/cdhs/leap/payment/subsidized_housing_deduction.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_household_size.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_limit.yaml create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income.py create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_dwelling_type.py create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_household_size.py create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.py create mode 100644 policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py diff --git a/changelog.d/co-leap-wave2c.added.md b/changelog.d/co-leap-wave2c.added.md new file mode 100644 index 00000000000..927c26bc92d --- /dev/null +++ b/changelog.d/co-leap-wave2c.added.md @@ -0,0 +1 @@ +Add Colorado LEAP regular heating assistance for fiscal year 2026 using reported heating costs and the heat-in-rent schedule. diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/eligibility/max_household_size.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/eligibility/max_household_size.yaml new file mode 100644 index 00000000000..8690a866da4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/eligibility/max_household_size.yaml @@ -0,0 +1,11 @@ +description: Colorado counts at most this many household members under the Low-income Energy Assistance Program. +values: + 2025-11-01: 15 + +metadata: + unit: person + period: year + label: Colorado LEAP maximum household size + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=29 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/additional_person_amount.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/additional_person_amount.yaml new file mode 100644 index 00000000000..49c63a0bf3b --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/additional_person_amount.yaml @@ -0,0 +1,11 @@ +description: Colorado increases the monthly income limit by this amount per additional person under the Low-income Energy Assistance Program. +values: + 2025-11-01: 208 + +metadata: + unit: currency-USD + period: month + label: Colorado LEAP additional person income limit + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/additional_person_threshold.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/additional_person_threshold.yaml new file mode 100644 index 00000000000..089b0d8330b --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/additional_person_threshold.yaml @@ -0,0 +1,11 @@ +description: Colorado tabulates income limits through this household size under the Low-income Energy Assistance Program. +values: + 2025-11-01: 8 + +metadata: + unit: person + period: year + label: Colorado LEAP maximum tabulated household size + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/earned_min_age.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/earned_min_age.yaml new file mode 100644 index 00000000000..20c5e53da9a --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/earned_min_age.yaml @@ -0,0 +1,11 @@ +description: Colorado counts earnings from household members at least this age under the Low-income Energy Assistance Program. +values: + 2025-11-01: 18 + +metadata: + unit: year + period: year + label: Colorado LEAP minimum age for countable earnings + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=51 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/smi_rate.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/smi_rate.yaml new file mode 100644 index 00000000000..bcfa0c17d83 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/smi_rate.yaml @@ -0,0 +1,11 @@ +description: Colorado limits income to this share of state median income under the Low-income Energy Assistance Program. +values: + 2025-11-01: 0.6 + +metadata: + unit: /1 + period: year + label: Colorado LEAP income limit SMI rate + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml new file mode 100644 index 00000000000..d5854f687d1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml @@ -0,0 +1,12 @@ +description: Colorado counts these earned income sources under the Low-income Energy Assistance Program. +# Existing net business income is used without another expense deduction. +values: + 2025-11-01: ["employment_income", "self_employment_income", "sstb_self_employment_income", "farm_operations_income", "partnership_s_corp_income"] + +metadata: + unit: list + period: year + label: Colorado LEAP earned income sources + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=46 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml new file mode 100644 index 00000000000..387001b6272 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml @@ -0,0 +1,17 @@ +description: Colorado counts these unearned income sources before separately rounding Social Security and SSI under the Low-income Energy Assistance Program. +# Social Security and SSI are separately truncated per recipient monthly. +# Colorado TANF is added once at SPM-unit level. Survivor benefits exclude +# SSA survivors; pension totals already include their public/private parts. +# Retirement distributions aggregate IRA, 401(k), SEP, 403(b), and Keogh. +# Generic gifts are limited to financial_assistance; irregular receipts, +# GI educational benefits and source-specific exclusions lack exact inputs. +values: + 2025-11-01: ["rental_income", "farm_rent_income", "interest_income", "dividend_income", "unemployment_compensation", "strike_benefits", "pension_income", "retirement_distributions", "survivor_benefits", "disability_benefits", "workers_compensation", "veterans_benefits", "general_assistance", "co_oap", "alimony_income", "child_support_received", "financial_assistance"] + +metadata: + unit: list + period: year + label: Colorado LEAP unearned income sources + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=47 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/additional_person_amounts.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/additional_person_amounts.yaml new file mode 100644 index 00000000000..434796d15f1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/additional_person_amounts.yaml @@ -0,0 +1,11 @@ +description: Colorado increases monthly contribution-group income boundaries by these amounts per additional person under the Low-income Energy Assistance Program. +values: + 2025-11-01: [344, 573, 802] + +metadata: + unit: list + period: month + label: Colorado LEAP contribution additional person amounts + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/fpg_rates.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/fpg_rates.yaml new file mode 100644 index 00000000000..e1471bc689b --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/fpg_rates.yaml @@ -0,0 +1,11 @@ +description: Colorado sets household contribution boundaries at these poverty guideline rates under the Low-income Energy Assistance Program. +values: + 2025-11-01: [0.75, 1.25, 1.75] + +metadata: + unit: list + period: year + label: Colorado LEAP household contribution poverty rates + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/rates.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/rates.yaml new file mode 100644 index 00000000000..e4e0c355e0a --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/contribution/rates.yaml @@ -0,0 +1,11 @@ +description: Colorado deducts these shares of estimated heating costs by income group under the Low-income Energy Assistance Program. +values: + 2025-11-01: [0, 0.1, 0.2, 0.3] + +metadata: + unit: list + period: year + label: Colorado LEAP household contribution rates + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=5 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/electric_heat_share.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/electric_heat_share.yaml new file mode 100644 index 00000000000..e6977230038 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/electric_heat_share.yaml @@ -0,0 +1,29 @@ +description: Colorado treats this share of direct electricity costs as heating by dwelling type under the Low-income Energy Assistance Program. +HOUSE_MODULAR: + 2025-11-01: 0.62 +MOBILE_HOME: + 2025-11-01: 0.62 +DUPLEX_TRIPLEX_FOURPLEX: + 2025-11-01: 0.48 +TOWNHOUSE: + 2025-11-01: 0.48 +APARTMENT_CONDO: + 2025-11-01: 0.43 +HOTEL_MOTEL: + 2025-11-01: 0.43 +CABIN: + 2025-11-01: 0.43 +TINY_HOME: + 2025-11-01: 0.43 +CAMPER_RV: + 2025-11-01: 0.5 + +metadata: + unit: /1 + period: year + label: Colorado LEAP electric heating share + breakdown: + - co_leap_dwelling_type + reference: + - title: Colorado FY2026 LEAP benefit methodology and annual rates + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml new file mode 100644 index 00000000000..09d198ffaf4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml @@ -0,0 +1,12 @@ +description: Colorado uses federal poverty guidelines from this many years before the heating season under the Low-income Energy Assistance Program. +# FY2026 uses the 2025 FPG; earlier backfilled years are unverified. +values: + 2025-11-01: 1 + +metadata: + unit: year + period: year + label: Colorado LEAP federal poverty guideline year lag + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/electricity.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/electricity.yaml new file mode 100644 index 00000000000..19bc28120f4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/electricity.yaml @@ -0,0 +1,29 @@ +description: Colorado estimates these electricity heating costs when included in rent under the Low-income Energy Assistance Program. +HOUSE_MODULAR: + 2025-11-01: 472 +MOBILE_HOME: + 2025-11-01: 440 +DUPLEX_TRIPLEX_FOURPLEX: + 2025-11-01: 343 +TOWNHOUSE: + 2025-11-01: 350 +APARTMENT_CONDO: + 2025-11-01: 227 +HOTEL_MOTEL: + 2025-11-01: 239 +CABIN: + 2025-11-01: 380 +TINY_HOME: + 2025-11-01: 357 +CAMPER_RV: + 2025-11-01: 393 + +metadata: + unit: currency-USD + period: year + label: Colorado LEAP electricity heating included in rent + breakdown: + - co_leap_dwelling_type + reference: + - title: Colorado FY2026 LEAP benefit methodology and annual rates + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/natural_gas.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/natural_gas.yaml new file mode 100644 index 00000000000..977c7dc2d9f --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/natural_gas.yaml @@ -0,0 +1,29 @@ +description: Colorado estimates these natural gas heating costs when included in rent under the Low-income Energy Assistance Program. +HOUSE_MODULAR: + 2025-11-01: 200 +MOBILE_HOME: + 2025-11-01: 177 +DUPLEX_TRIPLEX_FOURPLEX: + 2025-11-01: 156 +TOWNHOUSE: + 2025-11-01: 146 +APARTMENT_CONDO: + 2025-11-01: 110 +HOTEL_MOTEL: + 2025-11-01: 116 +CABIN: + 2025-11-01: 186 +TINY_HOME: + 2025-11-01: 271 +CAMPER_RV: + 2025-11-01: 151 + +metadata: + unit: currency-USD + period: year + label: Colorado LEAP natural gas heating included in rent + breakdown: + - co_leap_dwelling_type + reference: + - title: Colorado FY2026 LEAP benefit methodology and annual rates + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/oil_kerosene_coal.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/oil_kerosene_coal.yaml new file mode 100644 index 00000000000..14bb7cf2386 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/oil_kerosene_coal.yaml @@ -0,0 +1,29 @@ +description: Colorado estimates these oil kerosene coal heating costs when included in rent under the Low-income Energy Assistance Program. +HOUSE_MODULAR: + 2025-11-01: 378 +MOBILE_HOME: + 2025-11-01: 202 +DUPLEX_TRIPLEX_FOURPLEX: + 2025-11-01: 169 +TOWNHOUSE: + 2025-11-01: 444 +APARTMENT_CONDO: + 2025-11-01: 169 +HOTEL_MOTEL: + 2025-11-01: 169 +CABIN: + 2025-11-01: 169 +TINY_HOME: + 2025-11-01: 169 +CAMPER_RV: + 2025-11-01: 151 + +metadata: + unit: currency-USD + period: year + label: Colorado LEAP oil kerosene coal heating included in rent + breakdown: + - co_leap_dwelling_type + reference: + - title: Colorado FY2026 LEAP benefit methodology and annual rates + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/propane.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/propane.yaml new file mode 100644 index 00000000000..8989cf0a756 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/propane.yaml @@ -0,0 +1,29 @@ +description: Colorado estimates these propane heating costs when included in rent under the Low-income Energy Assistance Program. +HOUSE_MODULAR: + 2025-11-01: 405 +MOBILE_HOME: + 2025-11-01: 378 +DUPLEX_TRIPLEX_FOURPLEX: + 2025-11-01: 339 +TOWNHOUSE: + 2025-11-01: 240 +APARTMENT_CONDO: + 2025-11-01: 286 +HOTEL_MOTEL: + 2025-11-01: 301 +CABIN: + 2025-11-01: 375 +TINY_HOME: + 2025-11-01: 337 +CAMPER_RV: + 2025-11-01: 314 + +metadata: + unit: currency-USD + period: year + label: Colorado LEAP propane heating included in rent + breakdown: + - co_leap_dwelling_type + reference: + - title: Colorado FY2026 LEAP benefit methodology and annual rates + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/wood.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/wood.yaml new file mode 100644 index 00000000000..add43a05745 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/wood.yaml @@ -0,0 +1,29 @@ +description: Colorado estimates these wood heating costs when included in rent under the Low-income Energy Assistance Program. +HOUSE_MODULAR: + 2025-11-01: 480 +MOBILE_HOME: + 2025-11-01: 310 +DUPLEX_TRIPLEX_FOURPLEX: + 2025-11-01: 215 +TOWNHOUSE: + 2025-11-01: 215 +APARTMENT_CONDO: + 2025-11-01: 208 +HOTEL_MOTEL: + 2025-11-01: 208 +CABIN: + 2025-11-01: 208 +TINY_HOME: + 2025-11-01: 208 +CAMPER_RV: + 2025-11-01: 196 + +metadata: + unit: currency-USD + period: year + label: Colorado LEAP wood heating included in rent + breakdown: + - co_leap_dwelling_type + reference: + - title: Colorado FY2026 LEAP benefit methodology and annual rates + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/initial_reduction.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/initial_reduction.yaml new file mode 100644 index 00000000000..a4f8f4306a1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/initial_reduction.yaml @@ -0,0 +1,13 @@ +description: Colorado applies this initial statewide reduction to estimated heating costs under the Low-income Energy Assistance Program. +# Current-season statement governs; the later worked examples use a +# hypothetical 20 percent adjustment rather than the FY2026 value. +values: + 2025-11-01: 0 + +metadata: + unit: /1 + period: year + label: Colorado LEAP initial statewide reduction + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=92 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/maximum.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/maximum.yaml new file mode 100644 index 00000000000..b486a870ed5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/maximum.yaml @@ -0,0 +1,11 @@ +description: Colorado provides at most this regular heating benefit under the Low-income Energy Assistance Program. +values: + 2025-11-01: 1000 + +metadata: + unit: currency-USD + period: year + label: Colorado LEAP maximum benefit + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=5 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/minimum.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/minimum.yaml new file mode 100644 index 00000000000..f542036711a --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/minimum.yaml @@ -0,0 +1,11 @@ +description: Colorado provides at least this regular heating benefit to an eligible household under the Low-income Energy Assistance Program. +values: + 2025-11-01: 200 + +metadata: + unit: currency-USD + period: year + label: Colorado LEAP minimum benefit + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=5 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/subsidized_housing_deduction.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/subsidized_housing_deduction.yaml new file mode 100644 index 00000000000..6737fc892de --- /dev/null +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/subsidized_housing_deduction.yaml @@ -0,0 +1,11 @@ +description: Colorado deducts this amount after household cost sharing for subsidized housing under the Low-income Energy Assistance Program. +values: + 2025-11-01: 180 + +metadata: + unit: currency-USD + period: year + label: Colorado LEAP subsidized housing deduction + reference: + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=94 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 756dc2c4988..d9c75f6f508 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -802,7 +802,7 @@ programs: category: Benefits agency: HHS status: partial - coverage: OR, DC, Riverside County, MA, IL, KS, MS, TX + coverage: OR, DC, Riverside County, MA, IL, KS, MS, TX, CO state_implementations: - state: OR status: in_progress @@ -846,6 +846,14 @@ programs: variable: tx_ceap parameter_prefix: gov.states.tx.tdhca.ceap notes: Models the FPG income limit, the FY2024-only SMI limit, benefit amounts, and categorical eligibility through TANF enrollment, SNAP eligibility, and SSI receipt. Not modeled - net rather than gross gambling winnings, the Medicare premium deduction from counted Social Security, and the exclusion of means-tested veterans' pensions from counted income (10 TAC 6.4(c)) + - state: CO + status: partial + name: Colorado LEAP + full_name: Colorado Low-income Energy Assistance Program + variable: co_leap + parameter_prefix: gov.states.co.cdhs.leap + verified_years: "2026" + notes: Regular heating with reported annual primary-fuel costs used as a prior-heating-season proxy and the published heat-in-rent schedule. Includes income contribution, electric heating shares, household sharing and subsidized-housing adjustment. Missing-history/vendor fallback, actual meter sharing, rent surcharges and bottle/gathered-fuel distinctions are not fully represented. Earlier backfills and FY2027 benefits remain unverified. # --- SSA programs --- - id: ssi diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml new file mode 100644 index 00000000000..47ede50531a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml @@ -0,0 +1,320 @@ +# Source-derived FY 2026 Colorado regular heating checks. +# Benefit methodology and rates, PDF pages1-2,5-6: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=1,2,5,6 +# Current statewide reduction and calculation order, PDF pages92-95: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=92,93,94,95 +# Eligibility, PDF pages5,8: https://liheapch.acf.gov/docs/2026/state-plans/CO_Plan_2026.pdf#page=5,8 + +# Zero bill is ineligible. For positive costs clip(cost,200,1000): 1 and 199.99 receive 200;600 receives 600;1,000.01 and 5,000 receive 1,000. No expense cap removes the minimum. +- name: "Case 1, positive direct heating awards retain the minimum maximum and actual cost proxy." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + age: [35, 35, 35, 35, 35, 35, 35, 35] + ssi: [0, 0, 0, 0, 0, 0, 0, 0] + co_oap: [0, 0, 0, 0, 0, 0, 0, 0] + co_tanf: [0, 0, 0, 0, 0, 0, 0, 0] + gas_expense: [0, 1, 199.99, 200, 600, 1_000, 1000.01, 5_000] + output: + co_leap_household_size: [1, 1, 1, 1, 1, 1, 1, 1] + co_leap_countable_income_person: [0, 0, 0, 0, 0, 0, 0, 0] + co_leap_countable_income: [0, 0, 0, 0, 0, 0, 0, 0] + co_leap_income_limit: [43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284] + co_leap_income_contribution_rate: [0, 0, 0, 0, 0, 0, 0, 0] + co_leap_heating_cost: [0, 1, 199.99, 200, 600, 1_000, 1000.01, 5_000] + co_leap_eligible: [false, true, true, true, true, true, true, true] + co_leap: [0, 200, 200, 200, 600, 1_000, 1_000, 1_000] + +# Monthly wages at 978,1,630 and 2,282 retain the lower rate; +0.01/month moves up. Award=1,000*(1-contribution), with FY 2026 statewide adjustment 0%. +- name: "Case 2, all contribution boundary steps flow through the final award." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + age: [35, 35, 35, 35, 35, 35] + ssi: [0, 0, 0, 0, 0, 0] + co_oap: [0, 0, 0, 0, 0, 0] + co_tanf: [0, 0, 0, 0, 0, 0] + employment_income: [11_736, 11736.12, 19_560, 19560.12, 27_384, 27384.12] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + output: + co_leap_household_size: [1, 1, 1, 1, 1, 1] + co_leap_countable_income_person: [11_736, 11736.12, 19_560, 19560.12, 27_384, 27384.12] + co_leap_countable_income: [11_736, 11736.12, 19_560, 19560.12, 27_384, 27384.12] + co_leap_income_limit: [43_284, 43_284, 43_284, 43_284, 43_284, 43_284] + co_leap_income_contribution_rate: [0, 0.1, 0.1, 0.2, 0.2, 0.3] + co_leap_heating_cost: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + co_leap_eligible: [true, true, true, true, true, true] + co_leap: [1_000, 900, 900, 800, 800, 700] + +# Apply source electric shares exactly once to 1,000; all adjusted amounts lie within 200..1,000. +- name: "Case 3, electric heating costs receive one dwelling adjustment before the award." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY"] + age: [35, 35, 35, 35, 35, 35, 35, 35, 35] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0] + co_oap: [0, 0, 0, 0, 0, 0, 0, 0, 0] + co_tanf: [0, 0, 0, 0, 0, 0, 0, 0, 0] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_household_size: [1, 1, 1, 1, 1, 1, 1, 1, 1] + co_leap_countable_income: [0, 0, 0, 0, 0, 0, 0, 0, 0] + co_leap_income_limit: [43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284] + co_leap_income_contribution_rate: [0, 0, 0, 0, 0, 0, 0, 0, 0] + co_leap_heating_cost: [620, 620, 480, 480, 430, 430, 430, 430, 500] + co_leap_eligible: [true, true, true, true, true, true, true, true, true] + co_leap: [620, 620, 480, 480, 430, 430, 430, 430, 500] + +# Independent electric heat-in-rent table amounts 472..393 already represent heating. All exceed minimum; no second electric adjustment or half-year division. +- name: "Case 4, electric heat in unsubsidized rent uses each table value without another heat share." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY"] + age: [35, 35, 35, 35, 35, 35, 35, 35, 35] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0] + co_oap: [0, 0, 0, 0, 0, 0, 0, 0, 0] + co_tanf: [0, 0, 0, 0, 0, 0, 0, 0, 0] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_household_size: [1, 1, 1, 1, 1, 1, 1, 1, 1] + co_leap_countable_income: [0, 0, 0, 0, 0, 0, 0, 0, 0] + co_leap_income_limit: [43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284] + co_leap_income_contribution_rate: [0, 0, 0, 0, 0, 0, 0, 0, 0] + co_leap_heating_cost: [472, 440, 343, 350, 227, 239, 380, 357, 393] + co_leap_eligible: [true, true, true, true, true, true, true, true, true] + co_leap: [472, 440, 343, 350, 227, 239, 380, 357, 393] + +# Separate heating: clip(cost-180,200,1000) gives 200,420,820. Subsidized bundled heat without represented surcharge is ineligible despite a rent-table cost. +- name: "Case 5, subsidized housing deduction retains the minimum for low costs." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + age: [35, 35, 35, 35] + ssi: [0, 0, 0, 0] + co_oap: [0, 0, 0, 0] + co_tanf: [0, 0, 0, 0] + gas_expense: [100, 600, 1_000, 600] + receives_housing_assistance: [true, true, true, true] + heat_expense_included_in_rent: [false, false, false, true] + output: + co_leap_household_size: [1, 1, 1, 1] + co_leap_countable_income: [0, 0, 0, 0] + co_leap_income_limit: [43_284, 43_284, 43_284, 43_284] + co_leap_income_contribution_rate: [0, 0, 0, 0] + co_leap_heating_cost: [100, 600, 1_000, 200] + co_leap_eligible: [true, true, true, false] + co_leap: [200, 420, 820, 0] + +# Two separate units of 1 and 3 members report the same 734 shared-meter seasonal bill. Rates 20% and 10% yield 734*0.8/2=293.60 and 734*0.9/2=330.30; do not divide by 4 people. +- name: "Case 6, unequal-size economic units share costs by units rather than people." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 24_000 + ssi: 0 + co_oap: 0 + person2: + age: 40 + employment_income: 24_000 + ssi: 0 + co_oap: 0 + person3: + age: 8 + ssi: 0 + co_oap: 0 + person4: + age: 5 + ssi: 0 + co_oap: 0 + spm_units: + spm_unit1: + members: ["person1"] + heating_type: "NATURAL_GAS" + gas_expense: 734 + co_tanf: 0 + receives_housing_assistance: false + spm_unit2: + members: ["person2", "person3", "person4"] + heating_type: "NATURAL_GAS" + gas_expense: 734 + co_tanf: 0 + tax_units: + tax_unit1: + members: ["person1"] + tax_unit2: + members: ["person2", "person3", "person4"] + households: + household: + members: ["person1", "person2", "person3", "person4"] + state_code: "CO" + output: + co_leap_household_size: [1, 3] + co_leap_countable_income_person: [24_000, 24_000, 0, 0] + co_leap_countable_income: [24_000, 24_000] + co_leap_income_limit: [43_284, 69_924] + co_leap_income_contribution_rate: [0.2, 0.1] + co_leap_heating_cost: [734, 734] + co_leap_eligible: [true, true] + co_leap: [293.6, 330.3] + +# First unit income 1,000/month has 10% contribution. Divide by both units even though second fails income:1,000*0.9/2 -180 =270. Dividing after subsidy or counting only eligible units gives the wrong amount. +- name: "Case 7, an ineligible sharing unit still counts and housing deduction follows division." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 12_000 + ssi: 0 + co_oap: 0 + person2: + age: 40 + employment_income: 100_000 + ssi: 0 + co_oap: 0 + person3: + age: 8 + ssi: 0 + co_oap: 0 + person4: + age: 5 + ssi: 0 + co_oap: 0 + spm_units: + spm_unit1: + members: ["person1"] + heating_type: "NATURAL_GAS" + gas_expense: 1_000 + co_tanf: 0 + receives_housing_assistance: true + spm_unit2: + members: ["person2", "person3", "person4"] + heating_type: "NATURAL_GAS" + gas_expense: 1_000 + co_tanf: 0 + tax_units: + tax_unit1: + members: ["person1"] + tax_unit2: + members: ["person2", "person3", "person4"] + households: + household: + members: ["person1", "person2", "person3", "person4"] + state_code: "CO" + output: + co_leap_household_size: [1, 3] + co_leap_countable_income_person: [12_000, 100_000, 0, 0] + co_leap_countable_income: [12_000, 100_000] + co_leap_income_limit: [43_284, 69_924] + co_leap_income_contribution_rate: [0.1, 0.3] + co_leap_heating_cost: [1_000, 1_000] + co_leap_eligible: [true, false] + co_leap: [270, 0] + +# Qualified size 1 with parent income 1,000/month: rate 10%, award 1,000*0.9=900. Counting both people in size would wrongly produce the 0% rate. +- name: "Case 8, citizen child qualifies while nonqualified parent income remains included." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 0 + immigration_status: "UNDOCUMENTED" + employment_income: 12_000 + person2: + age: 8 + ssi: 0 + co_oap: 0 + immigration_status: "CITIZEN" + spm_units: + spm_unit: + members: ["person1", "person2"] + heating_type: "NATURAL_GAS" + gas_expense: 1_000 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2"] + households: + household: + members: ["person1", "person2"] + state_code: "CO" + output: + co_leap_household_size: 1 + co_leap_countable_income_person: [12_000, 0] + co_leap_countable_income: 12_000 + co_leap_income_limit: 43_284 + co_leap_income_contribution_rate: 0.1 + co_leap_heating_cost: 1_000 + co_leap_eligible: true + co_leap: 900 + +# The first CO household gets 600; other states remain outside CO scope, and the second CO row has no positive bill. Every flat input has four entries. +- name: "Case 9, mixed-state rows retain Colorado awards only in Colorado." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CA", "CO", "WV"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + age: [35, 35, 35, 35] + ssi: [0, 0, 0, 0] + co_oap: [0, 0, 0, 0] + co_tanf: [0, 0, 0, 0] + gas_expense: [600, 600, 0, 1_200] + output: + co_leap_household_size: [1, 0, 1, 0] + co_leap_countable_income: [0, 0, 0, 0] + co_leap_income_limit: [43_284, 0, 43_284, 0] + co_leap_heating_cost: [600, 0, 0, 0] + co_leap_eligible: [true, false, false, false] + co_leap: [600, 0, 0, 0] + +# A loss produces zero counted earnings under the scoped convention, not a negative contribution. The 5,000 bill still receives at most 1,000. +- name: "Case 10, a business loss cannot inflate the regular benefit above its cap." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 0 + self_employment_income: -1_000_000 + spm_units: + spm_unit: + members: ["person1"] + heating_type: "NATURAL_GAS" + gas_expense: 5_000 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1"] + households: + household: + members: ["person1"] + state_code: "CO" + output: + co_leap_household_size: 1 + co_leap_countable_income_person: 0 + co_leap_countable_income: 0 + co_leap_income_limit: 43_284 + co_leap_income_contribution_rate: 0 + co_leap_heating_cost: 5_000 + co_leap_eligible: true + co_leap: 1_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income.yaml new file mode 100644 index 00000000000..51cc341a3ba --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income.yaml @@ -0,0 +1,66 @@ +# Source-derived FY 2026 Colorado regular heating checks. +# Public assistance and exclusions, PDF pages47,50-51: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=47,50,51 + +# Annual TANF 3,600 =300/month for the unit. Count wages 12,000 + TANF 3,600 =15,600 once, not once for each member. +- name: "Case 1, Colorado TANF counts once for a parent and two children." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 0 + employment_income: 12_000 + person2: + age: 8 + ssi: 0 + co_oap: 0 + person3: + age: 5 + ssi: 0 + co_oap: 0 + spm_units: + spm_unit: + members: ["person1", "person2", "person3"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 3_600 + tax_units: + tax_unit: + members: ["person1", "person2", "person3"] + households: + household: + members: ["person1", "person2", "person3"] + state_code: "CO" + output: + co_leap_countable_income_person: [12_000, 0, 0] + co_leap_countable_income: 15_600 + +# SNAP 6,000 is noncash assistance; only 12,000 wages count. +- name: "Case 2, SNAP is excluded from gross cash income." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 0 + employment_income: 12_000 + spm_units: + spm_unit: + members: ["person1"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + snap: 6_000 + tax_units: + tax_unit: + members: ["person1"] + households: + household: + members: ["person1"] + state_code: "CO" + output: + co_leap_countable_income: 12_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml new file mode 100644 index 00000000000..4fd526cc897 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml @@ -0,0 +1,316 @@ +# Source-derived FY 2026 Colorado regular heating checks. +# Income and exemptions, PDF pages6-7,46-51,55-57: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=6,7,46,47,48,49,50,51,55,56,57 + +# Adult gross wages 1,000 + net nonfarm 2,000 + SSTB 3,000 + farm 4,000 + partnership 5,000 + S-corp 6,000 =21,000. No second business-expense deduction. +- name: "Case 1, adult wages and independent business streams count once." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 0 + employment_income: 1_000 + self_employment_income: 2_000 + sstb_self_employment_income: 3_000 + farm_operations_income: 4_000 + partnership_income: 5_000 + s_corp_income: 6_000 + spm_units: + spm_unit: + members: ["person1"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1"] + households: + household: + members: ["person1"] + state_code: "CO" + output: + co_leap_countable_income_person: 21_000 + co_leap_countable_income: 21_000 + +# Rent 3,000 + interest 150 + dividends 300 + UI 400 + strike 500 + pension 3,000 + non-SSA survivors 600 + disability 700 + workers 800 + VA 900 + GA 100 + OAP 200 + alimony 300 + child support 400 + family help 500 + retirement distributions 1,300 =13150. +# Pension survivor 900 and military 800 classify portions already reported within the 3,000 pension; they are not extra receipts. +- name: "Case 2, unearned sources and retirement aggregates count without pension classification duplication." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 200 + rental_income: 1_200 + farm_rent_income: 1_800 + taxable_interest_income: 100 + tax_exempt_interest_income: 50 + dividend_income: 300 + unemployment_compensation: 400 + strike_benefits: 500 + taxable_pension_income: 1_000 + tax_exempt_pension_income: 2_000 + pension_survivors: 900 + military_retirement_pay: 800 + survivor_benefits: 600 + disability_benefits: 700 + workers_compensation: 800 + veterans_benefits: 900 + general_assistance: 100 + alimony_income: 300 + child_support_received: 400 + financial_assistance: 500 + taxable_ira_distributions: 600 + tax_exempt_401k_distributions: 700 + spm_units: + spm_unit: + members: ["person1"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1"] + households: + household: + members: ["person1"] + state_code: "CO" + output: + co_leap_countable_income_person: 13_150 + co_leap_countable_income: 13_150 + +# Annual SSA survivors 12,011.88 =1,000.99/month; annual SSI 2,411.88 =200.99/month. Drop cents separately: (1,000+200)*12 =14,400. SSA survivors already enter the SSA aggregate. +- name: "Case 3, Social Security and SSI cents are discarded separately per monthly receipt." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 2411.88 + co_oap: 0 + social_security_survivors: 12011.88 + spm_units: + spm_unit: + members: ["person1"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1"] + households: + household: + members: ["person1"] + state_code: "CO" + output: + co_leap_countable_income_person: 14_400 + co_leap_countable_income: 14_400 + +# Separate recipients receive 1,000.99 and 500.99/month; (1,000+500)*12=18,000. Pooling before truncation would incorrectly count 18,012. +- name: "Case 4, rounding is per recipient rather than after pooling Social Security." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 68 + ssi: 0 + co_oap: 0 + social_security_retirement: 12011.88 + person2: + age: 67 + ssi: 0 + co_oap: 0 + social_security_retirement: 6011.88 + spm_units: + spm_unit: + members: ["person1", "person2"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2"] + households: + household: + members: ["person1", "person2"] + state_code: "CO" + output: + co_leap_countable_income_person: [12_000, 6_000] + co_leap_countable_income: 18_000 + +# Dependent child lives with parent. At age 17, count 0 wages plus 1,200 SSA survivors and 600 support; parent wages 12,000 count. +- name: "Case 5, minor earnings exclusion applies at seventeen." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ssi: 0 + co_oap: 0 + employment_income: 12_000 + person2: + age: 17 + ssi: 0 + co_oap: 0 + employment_income: 6_000 + social_security_survivors: 1_200 + child_support_received: 600 + spm_units: + spm_unit: + members: ["person1", "person2"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2"] + households: + household: + members: ["person1", "person2"] + state_code: "CO" + output: + co_leap_countable_income_person: [12_000, 1_800] + co_leap_countable_income: 13_800 + +# Dependent child lives with parent. At age 18, count 6000 wages plus 1,200 SSA survivors and 600 support; parent wages 12,000 count. +- name: "Case 6, minor earnings exclusion ends at eighteen." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ssi: 0 + co_oap: 0 + employment_income: 12_000 + person2: + age: 18 + ssi: 0 + co_oap: 0 + employment_income: 6_000 + social_security_survivors: 1_200 + child_support_received: 600 + spm_units: + spm_unit: + members: ["person1", "person2"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2"] + households: + household: + members: ["person1", "person2"] + state_code: "CO" + output: + co_leap_countable_income_person: [12_000, 7_800] + co_leap_countable_income: 19_800 + +# The foster member is outside the LEAP household. Neither their wages nor SSA receipt increases household income. +- name: "Case 7, known foster member earnings and unearned receipts are excluded." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ssi: 0 + co_oap: 0 + employment_income: 12_000 + person2: + age: 16 + ssi: 0 + co_oap: 0 + employment_income: 6_000 + social_security_survivors: 2_400 + is_in_foster_care: + 2026-01: true + spm_units: + spm_unit: + members: ["person1", "person2"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2"] + households: + household: + members: ["person1", "person2"] + state_code: "CO" + output: + co_leap_countable_income_person: [12_000, 0] + co_leap_countable_income: 12_000 + co_leap_household_size: 1 + +# The scoped nonnegative-source convention retains 12,000 wages when a business reports a loss. It cannot turn the benefit contribution negative. +- name: "Case 8, negative net business source does not offset positive wages." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 0 + employment_income: 12_000 + self_employment_income: -50_000 + spm_units: + spm_unit: + members: ["person1"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1"] + households: + household: + members: ["person1"] + state_code: "CO" + output: + co_leap_countable_income_person: 12_000 + co_leap_countable_income: 12_000 + +# All 12,000 parent income remains even though only the citizen child enters qualified size. +- name: "Case 9, nonqualified parent income remains counted." + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 0 + immigration_status: "UNDOCUMENTED" + employment_income: 12_000 + person2: + age: 8 + ssi: 0 + co_oap: 0 + immigration_status: "CITIZEN" + spm_units: + spm_unit: + members: ["person1", "person2"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2"] + households: + household: + members: ["person1", "person2"] + state_code: "CO" + output: + co_leap_countable_income_person: [12_000, 0] + co_leap_countable_income: 12_000 + co_leap_household_size: 1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_eligible.yaml new file mode 100644 index 00000000000..98165dd192d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_eligible.yaml @@ -0,0 +1,43 @@ +# Source-derived FY 2026 Colorado regular heating checks. +# Eligibility and categorical rules, PDF pages5,8: https://liheapch.acf.gov/docs/2026/state-plans/CO_Plan_2026.pdf#page=5,8 +# Income table, PDF page5: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=5 + +# For each size 1-15 compare annualized monthly income at the table limit and $0.01/month above. All other eligibility facts are held supported; no categorical bypass. +- name: "Case 1, all source SMI boundaries are inclusive with the next cent excluded." + period: 2026 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + co_leap_household_size: [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15] + co_leap_countable_income: [43_284, 43284.12, 56_604, 56604.12, 69_924, 69924.12, 83_256, 83256.12, 96_576, 96576.12, 109_896, 109896.12, 112_392, 112392.12, 114_888, 114888.12, 117_384, 117384.12, 119_880, 119880.12, 122_376, 122376.12, 124_872, 124872.12, 127_368, 127368.12, 129_864, 129864.12, 132_360, 132360.12] + gas_expense: [600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600] + output: + co_leap_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +# No heat, unknown separate fuel and zero bills are unsupported. Positive gas and unsubsidized heat-in-rent qualify. Subsidized bundled heat and no qualified member fail. Electric heat-in-rent needs no separate bill. +- name: "Case 2, heating responsibility housing support and qualified membership gate eligibility." + period: 2026 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NONE", "UNSPECIFIED", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "ELECTRICITY"] + co_leap_household_size: [1, 1, 1, 1, 1, 1, 0, 1] + co_leap_countable_income: [0, 0, 0, 0, 0, 0, 0, 0] + gas_expense: [600, 600, 0, 600, 0, 0, 600, 0] + heat_expense_included_in_rent: [false, false, false, false, true, true, false, true] + receives_housing_assistance: [false, false, false, false, false, true, false, false] + output: + co_leap_eligible: [false, false, false, true, true, false, false, true] + +# Both rows exceed the 43,284 annual size 1 ceiling despite categorical-program receipt. +- name: "Case 3, SNAP and SSI do not bypass the income ceiling." + period: 2026 + input: + state_code: ["CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS"] + co_leap_household_size: [1, 1] + co_leap_countable_income: [50_000, 50_000] + gas_expense: [600, 600] + snap: [6_000, 0] + ssi: [0, 12_000] + output: + co_leap_eligible: [false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml new file mode 100644 index 00000000000..8a114e0413c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml @@ -0,0 +1,144 @@ +# Source-derived FY 2026 Colorado regular heating checks. +# Heating-cost methodology and annual dwelling tables, PDF pages1,5-6: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=1,5,6 +# Actual electricity instruction, PDF page94: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=94 + +# A 1,000 direct electric bill uses shares 62%,62%,48%,48%,43%,43%,43%,43%,50%; no extra half-year division. +- name: "Case 1, actual electric bills receive all nine dwelling-specific heating shares." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY"] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_heating_cost: [620, 620, 480, 480, 430, 430, 430, 430, 500] + +# Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. +# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +- name: "Case 2, all nine natural gas heat-in-rent rates match the annual handout." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_heating_cost: [200, 177, 156, 146, 110, 116, 186, 271, 151] + +# Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. +# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +- name: "Case 3, all nine propane heat-in-rent rates match the annual handout." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["PROPANE", "PROPANE", "PROPANE", "PROPANE", "PROPANE", "PROPANE", "PROPANE", "PROPANE", "PROPANE"] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_heating_cost: [405, 378, 339, 240, 286, 301, 375, 337, 314] + +# Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. +# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +- name: "Case 4, all nine electricity heat-in-rent rates match the annual handout." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY", "ELECTRICITY"] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_heating_cost: [472, 440, 343, 350, 227, 239, 380, 357, 393] + +# Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. +# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +- name: "Case 5, all nine wood heat-in-rent rates match the annual handout." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["WOOD", "WOOD", "WOOD", "WOOD", "WOOD", "WOOD", "WOOD", "WOOD", "WOOD"] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_heating_cost: [480, 310, 215, 215, 208, 208, 208, 208, 196] + +# Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. +# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +- name: "Case 6, all nine fuel oil heat-in-rent rates match the annual handout." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["FUEL_OIL", "FUEL_OIL", "FUEL_OIL", "FUEL_OIL", "FUEL_OIL", "FUEL_OIL", "FUEL_OIL", "FUEL_OIL", "FUEL_OIL"] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_heating_cost: [378, 202, 169, 444, 169, 169, 169, 169, 151] + +# Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. +# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +- name: "Case 7, all nine kerosene heat-in-rent rates match the annual handout." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["KEROSENE", "KEROSENE", "KEROSENE", "KEROSENE", "KEROSENE", "KEROSENE", "KEROSENE", "KEROSENE", "KEROSENE"] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_heating_cost: [378, 202, 169, 444, 169, 169, 169, 169, 151] + +# Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. +# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +- name: "Case 8, all nine coal heat-in-rent rates match the annual handout." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["COAL", "COAL", "COAL", "COAL", "COAL", "COAL", "COAL", "COAL", "COAL"] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] + output: + co_leap_heating_cost: [378, 202, 169, 444, 169, 169, 169, 169, 151] + +# Each household reports 600 for its matching primary fuel; seasonal-cost proxy=600 directly, not annual 600/2. OTHER has an actual-bill route without an invented rent table. +- name: "Case 9, positive actual costs use each primary non-electric fuel bill." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "PROPANE", "FUEL_OIL", "KEROSENE", "WOOD", "COAL", "OTHER"] + gas_expense: [600, 0, 0, 0, 0, 0, 0] + other_heating_fuel_expense: [0, 0, 0, 0, 0, 0, 600] + wood_expense: [0, 0, 0, 0, 600, 0, 0] + fuel_oil_expense: [0, 0, 600, 600, 0, 0, 0] + bottled_gas_expense: [0, 600, 0, 0, 0, 0, 0] + coal_expense: [0, 0, 0, 0, 0, 600, 0] + output: + co_leap_heating_cost: [600, 600, 600, 600, 600, 600, 600] + +# Ordinary zero defaults cannot distinguish missing records from no expense. Explicit zero has no inferred flat-rate award; negative bills are bounded at zero. +- name: "Case 10, zero and negative direct bills never trigger missing-history flat rates." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "UNSPECIFIED"] + gas_expense: [0, -100, 0] + output: + co_leap_heating_cost: [0, 0, 0] + +# The published rent table has no NONE, unspecified, solar or other-fuel column; these zeros describe unsupported input classifications, not sourced legal exclusions. +- name: "Case 11, unsupported heat-in-rent fuel classifications do not borrow a table." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO"] + heating_type: ["NONE", "UNSPECIFIED", "SOLAR", "OTHER"] + heat_expense_included_in_rent: [true, true, true, true] + output: + co_leap_heating_cost: [0, 0, 0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_household_size.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_household_size.yaml new file mode 100644 index 00000000000..ba5c641c751 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_household_size.yaml @@ -0,0 +1,171 @@ +# Source-derived FY 2026 Colorado regular heating checks. +# Household and immigration rules, PDF pages29,51,55-57,90: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=29,51,55,56,57,90 + +# Six residents: citizen child + permanent resident + refugee =3; undocumented, DACA and known foster member excluded. +- name: "Case 1, citizen child and qualified adults count while nonqualified adults and foster child do not." + period: 2026 + input: + people: + person1: + age: 36 + ssi: 0 + co_oap: 0 + immigration_status: "UNDOCUMENTED" + person2: + age: 34 + ssi: 0 + co_oap: 0 + immigration_status: "DACA" + person3: + age: 8 + ssi: 0 + co_oap: 0 + immigration_status: "CITIZEN" + person4: + age: 31 + ssi: 0 + co_oap: 0 + immigration_status: "LEGAL_PERMANENT_RESIDENT" + person5: + age: 30 + ssi: 0 + co_oap: 0 + immigration_status: "REFUGEE" + person6: + age: 15 + ssi: 0 + co_oap: 0 + immigration_status: "CITIZEN" + is_in_foster_care: + 2026-01: true + spm_units: + spm_unit: + members: ["person1", "person2", "person3", "person4", "person5", "person6"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2", "person3", "person4", "person5", "person6"] + households: + household: + members: ["person1", "person2", "person3", "person4", "person5", "person6"] + state_code: "CO" + output: + co_leap_household_size: 3 + +# The manual caps the counted unit at 15 despite 16 actual qualified members. +- name: "Case 2, sixteen actual qualified members are capped at fifteen." + period: 2026 + input: + people: + person1: + age: 40 + ssi: 0 + co_oap: 0 + person2: + age: 39 + ssi: 0 + co_oap: 0 + person3: + age: 17 + ssi: 0 + co_oap: 0 + person4: + age: 16 + ssi: 0 + co_oap: 0 + person5: + age: 15 + ssi: 0 + co_oap: 0 + person6: + age: 14 + ssi: 0 + co_oap: 0 + person7: + age: 13 + ssi: 0 + co_oap: 0 + person8: + age: 12 + ssi: 0 + co_oap: 0 + person9: + age: 11 + ssi: 0 + co_oap: 0 + person10: + age: 10 + ssi: 0 + co_oap: 0 + person11: + age: 9 + ssi: 0 + co_oap: 0 + person12: + age: 8 + ssi: 0 + co_oap: 0 + person13: + age: 7 + ssi: 0 + co_oap: 0 + person14: + age: 6 + ssi: 0 + co_oap: 0 + person15: + age: 5 + ssi: 0 + co_oap: 0 + person16: + age: 4 + ssi: 0 + co_oap: 0 + spm_units: + spm_unit: + members: ["person1", "person2", "person3", "person4", "person5", "person6", "person7", "person8", "person9", "person10", "person11", "person12", "person13", "person14", "person15", "person16"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2", "person3", "person4", "person5", "person6", "person7", "person8", "person9", "person10", "person11", "person12", "person13", "person14", "person15", "person16"] + households: + household: + members: ["person1", "person2", "person3", "person4", "person5", "person6", "person7", "person8", "person9", "person10", "person11", "person12", "person13", "person14", "person15", "person16"] + state_code: "CO" + output: + co_leap_household_size: 15 + +# Neither nonqualified adult contributes a qualifying member. +- name: "Case 3, no qualified household member gives a zero counted size." + period: 2026 + input: + people: + person1: + age: 35 + ssi: 0 + co_oap: 0 + immigration_status: "UNDOCUMENTED" + person2: + age: 35 + ssi: 0 + co_oap: 0 + immigration_status: "DACA" + spm_units: + spm_unit: + members: ["person1", "person2"] + heating_type: "NATURAL_GAS" + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: ["person1", "person2"] + households: + household: + members: ["person1", "person2"] + state_code: "CO" + output: + co_leap_household_size: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.yaml new file mode 100644 index 00000000000..85dd8286775 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.yaml @@ -0,0 +1,53 @@ +# Source-derived FY 2026 Colorado regular heating checks. +# FPG table and contribution schedule, PDF pages5-6: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=5,6 + +# Each size 1-15 appears twice: at the published monthly upper bound, then $0.01/month above it. +# Sizes 1-8 use the printed table; later sizes add the printed per-person increments. Annual input = monthly boundary*12, then +$0.12. +- name: "Case 1, every 75 percent FPG boundary retains the lower contribution through the exact cent edge." + period: 2026 + absolute_error_margin: 0.001 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + co_leap_household_size: [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15] + co_leap_countable_income: [11_736, 11736.12, 15_864, 15864.12, 19_992, 19992.12, 24_108, 24108.12, 28_248, 28248.12, 32_364, 32364.12, 36_492, 36492.12, 40_620, 40620.12, 44_748, 44748.12, 48_876, 48876.12, 53_004, 53004.12, 57_132, 57132.12, 61_260, 61260.12, 65_388, 65388.12, 69_516, 69516.12] + output: + co_leap_income_contribution_rate: [0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1, 0, 0.1] + +# Each size 1-15 appears twice: at the published monthly upper bound, then $0.01/month above it. +# Sizes 1-8 use the printed table; later sizes add the printed per-person increments. Annual input = monthly boundary*12, then +$0.12. +- name: "Case 2, every 125 percent FPG boundary retains the lower contribution through the exact cent edge." + period: 2026 + absolute_error_margin: 0.001 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + co_leap_household_size: [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15] + co_leap_countable_income: [19_560, 19560.12, 26_448, 26448.12, 33_312, 33312.12, 40_188, 40188.12, 47_076, 47076.12, 53_940, 53940.12, 60_816, 60816.12, 67_692, 67692.12, 74_568, 74568.12, 81_444, 81444.12, 88_320, 88320.12, 95_196, 95196.12, 102_072, 102072.12, 108_948, 108948.12, 115_824, 115824.12] + output: + co_leap_income_contribution_rate: [0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2] + +# Each size 1-15 appears twice: at the published monthly upper bound, then $0.01/month above it. +# Sizes 1-8 use the printed table; later sizes add the printed per-person increments. Annual input = monthly boundary*12, then +$0.12. +- name: "Case 3, every 175 percent FPG boundary retains the lower contribution through the exact cent edge." + period: 2026 + absolute_error_margin: 0.001 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + co_leap_household_size: [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15] + co_leap_countable_income: [27_384, 27384.12, 37_020, 37020.12, 46_644, 46644.12, 56_256, 56256.12, 65_904, 65904.12, 75_516, 75516.12, 85_140, 85140.12, 94_776, 94776.12, 104_400, 104400.12, 114_024, 114024.12, 123_648, 123648.12, 133_272, 133272.12, 142_896, 142896.12, 152_520, 152520.12, 162_144, 162144.12] + output: + co_leap_income_contribution_rate: [0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.3] + +# Zero, negative and $100/month income remain in the 0% contribution band. +- name: "Case 4, zero and negative income cannot create a negative contribution." + period: 2026 + absolute_error_margin: 0.001 + input: + state_code: ["CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + co_leap_household_size: [1, 1, 1] + co_leap_countable_income: [0, -1_200, 1_200] + output: + co_leap_income_contribution_rate: [0, 0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_limit.yaml new file mode 100644 index 00000000000..b85b46a7211 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_limit.yaml @@ -0,0 +1,26 @@ +# Source-derived FY 2026 Colorado regular heating checks. +# Income table, PDF page5: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=5 +# Qualified household, PDF pages29,55: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=29,55 + +# Sizes 1-8 use the published monthly table. Sizes 9-15 add $208 per person to $9,574. +# Expected annual limits are each authoritative monthly dollar amount multiplied by 12. +- name: "Case 1, all printed monthly SMI limits and additional-person amounts annualize exactly." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + co_leap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + output: + co_leap_income_limit: [43_284, 56_604, 69_924, 83_256, 96_576, 109_896, 112_392, 114_888, 117_384, 119_880, 122_376, 124_872, 127_368, 129_864, 132_360] + +# No qualified member provides no supported household income allowance. +- name: "Case 2, zero qualified household size has no income allowance." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO"] + heating_type: ["NATURAL_GAS"] + co_leap_household_size: [0] + output: + co_leap_income_limit: [0] diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py new file mode 100644 index 00000000000..da2944324d1 --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class co_leap(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Colorado LEAP regular heating assistance" + defined_for = "co_leap_eligible" + reference = "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=92,93,94,95" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.co.cdhs.leap.payment + heating_cost = spm_unit("co_leap_heating_cost", period) + contribution = spm_unit("co_leap_income_contribution_rate", period) + # Every SPM unit at the address counts, including ineligible units. + # This approximates economic units sharing a meter; actual separate + # meters and the administrative nine-household limit are not observed. + shared_households = add(spm_unit.household, period, ["spm_unit_count"]) + shared_cost = ( + heating_cost + * (1 - p.initial_reduction) + * (1 - contribution) + / max_(shared_households, 1) + ) + subsidized = spm_unit("receives_housing_assistance", period) + adjusted = shared_cost - subsidized * p.subsidized_housing_deduction + # FY2026 verified policy; parameter backfilling does not verify prior + # years. The minimum applies even when adjusted costs are smaller. + return clip(adjusted, p.minimum, p.maximum) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income.py new file mode 100644 index 00000000000..953276e29fe --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class co_leap_countable_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Colorado LEAP countable household income" + defined_for = StateCode.CO + reference = "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=46,47,48,49,50,51" + adds = ["co_leap_countable_income_person", "co_tanf"] diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py new file mode 100644 index 00000000000..9c20b97c4d5 --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class co_leap_countable_income_person(Variable): + value_type = float + entity = Person + definition_period = YEAR + unit = USD + label = "Colorado LEAP countable person income" + defined_for = StateCode.CO + reference = "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=46,47,48,51" + + def formula(person, period, parameters): + p = parameters(period).gov.states.co.cdhs.leap.income + earned = 0 + for source in p.sources.earned: + earned = earned + max_(person(source, period), 0) + age = person("age", period) + earned = where(age >= p.earned_min_age, earned, 0) + unearned = add(person, period, p.sources.unearned) + # Annual flows approximate ongoing application-month income. The + # monthly SSA and SSI amounts lose cents separately for each person. + # Medicare premiums remain in gross SSA income under Colorado rules. + social_security = np.floor(person("social_security", period) / MONTHS_IN_YEAR) + ssi = np.floor(person("ssi", period, options=[ADD]) / MONTHS_IN_YEAR) + income = earned + unearned + (social_security + ssi) * MONTHS_IN_YEAR + foster = person("is_in_foster_care", period.first_month) + # Known foster individuals are outside the LEAP household; income of + # nonqualified immigrants remains included. Rental income is assumed + # nonnegative, and existing business inputs are already net of costs. + return where(foster, 0, max_(income, 0)) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_dwelling_type.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_dwelling_type.py new file mode 100644 index 00000000000..c53acbe3652 --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_dwelling_type.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class COLEAPDwellingType(Enum): + MOBILE_HOME = "Mobile home" + DUPLEX_TRIPLEX_FOURPLEX = "Duplex, triplex or fourplex" + TOWNHOUSE = "Townhouse" + APARTMENT_CONDO = "Apartment or condominium" + HOTEL_MOTEL = "Hotel or motel" + CABIN = "Cabin" + TINY_HOME = "Tiny home" + CAMPER_RV = "Camper, fifth wheel or recreational vehicle" + HOUSE_MODULAR = "House or modular home" + + +class co_leap_dwelling_type(Variable): + value_type = Enum + entity = SPMUnit + possible_values = COLEAPDwellingType + default_value = COLEAPDwellingType.HOUSE_MODULAR + definition_period = YEAR + label = "Colorado LEAP dwelling type" + defined_for = StateCode.CO + # House/modular is the modeling fallback when dwelling type is unknown. + reference = "https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=6" diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py new file mode 100644 index 00000000000..6ffa28c4b88 --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class co_leap_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Eligible for Colorado LEAP regular heating assistance" + defined_for = StateCode.CO + reference = ( + "https://liheapch.acf.gov/docs/2026/state-plans/CO_Plan_2026.pdf#page=5,8", + "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=46,51,52,53,55", + ) + + def formula(spm_unit, period, parameters): + size = spm_unit("co_leap_household_size", period) + income = spm_unit("co_leap_countable_income", period) + limit = spm_unit("co_leap_income_limit", period) + cost = spm_unit("co_leap_heating_cost", period) + included = spm_unit("heat_expense_included_in_rent", period) + subsidized = spm_unit("receives_housing_assistance", period) + fuel = spm_unit("heating_type", period) + fuels = fuel.possible_values + # Subsidized rent-included heat can qualify with a separate surcharge; + # that fact is unavailable, so this exception is not represented. + # Application timing, vendor approval and prior receipt are not modeled. + return ( + (size > 0) + & (income <= limit) + & (cost > 0) + & (fuel != fuels.NONE) + & (fuel != fuels.UNSPECIFIED) + & ~(included & subsidized) + ) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py new file mode 100644 index 00000000000..c607989a570 --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py @@ -0,0 +1,50 @@ +from policyengine_us.model_api import * + + +class co_leap_heating_cost(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Colorado LEAP estimated heating cost" + defined_for = StateCode.CO + reference = "https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=1,2,6" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.co.cdhs.leap.payment + dwelling = spm_unit("co_leap_dwelling_type", period) + fuel = spm_unit("heating_type", period) + fuels = fuel.possible_values + included = spm_unit("heat_expense_included_in_rent", period) + # Existing annual expense proxies the covered heating-season bill. + # It cannot identify actual prior November-April history or vendor + # approval. Explicit zero does not trigger a missing-history flat rate. + expense = max_(spm_unit("heating_expense", period), 0) + electric_share = where( + fuel == fuels.ELECTRICITY, p.electric_heat_share[dwelling], 1 + ) + table = p.heat_in_rent + included_cost = select( + [ + fuel == fuels.NATURAL_GAS, + fuel == fuels.PROPANE, + fuel == fuels.ELECTRICITY, + fuel == fuels.WOOD, + (fuel == fuels.FUEL_OIL) + | (fuel == fuels.KEROSENE) + | (fuel == fuels.COAL), + ], + [ + table.natural_gas[dwelling], + table.propane[dwelling], + table.electricity[dwelling], + table.wood[dwelling], + table.oil_kerosene_coal[dwelling], + ], + default=0, + ) + # The actual-electric-cost instruction governs the direct bill only; + # rent-included amounts already represent heat. Propane uses bulk rates + # and wood purchased rates; bottle/gathered distinctions lack inputs. + # Unknown rent-included fuels have no supported rate and remain a gap. + return where(included, included_cost, expense * electric_share) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_household_size.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_household_size.py new file mode 100644 index 00000000000..bf4de9e0eb5 --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_household_size.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class co_leap_household_size(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "Colorado LEAP eligible household size" + defined_for = StateCode.CO + reference = "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=29,51,55" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.co.cdhs.leap.eligibility + person = spm_unit.members + qualified = person("is_citizen_or_legal_immigrant", period) + foster = person("is_in_foster_care", period.first_month) + # SPM membership approximates the energy-sharing economic unit; + # kinship status and later changes in foster status are not represented. + return min_(spm_unit.sum(qualified & ~foster), p.max_household_size) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.py new file mode 100644 index 00000000000..eb00fc19663 --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.py @@ -0,0 +1,45 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class co_leap_income_contribution_rate(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = "/1" + label = "Colorado LEAP household income contribution rate" + defined_for = StateCode.CO + reference = "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4,5,93" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.co.cdhs.leap + size = spm_unit("co_leap_household_size", period) + capped_size = min_(size, p.income.additional_person_threshold) + extra = max_(size - p.income.additional_person_threshold, 0) + state_group = spm_unit.household("state_group_str", period) + monthly_fpg = ( + fpg( + capped_size, + state_group, + period, + parameters, + year_lag=p.payment.fpg_year_lag, + ) + / MONTHS_IN_YEAR + ) + # Inferred rounding order reproduces every published FY2026 boundary: + # half-up monthly FPG first, then half-up each percentage of that value. + rounded_fpg = np.floor(monthly_fpg + 0.5) + monthly_income = spm_unit("co_leap_countable_income", period) / MONTHS_IN_YEAR + contribution = p.payment.contribution + conditions = [ + monthly_income <= np.floor(rounded_fpg * rate + 0.5) + extra * increment + for rate, increment in zip( + contribution.fpg_rates, contribution.additional_person_amounts + ) + ] + return select( + conditions, + contribution.rates[:-1], + default=contribution.rates[-1], + ) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py new file mode 100644 index 00000000000..1d6b4392f8d --- /dev/null +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class co_leap_income_limit(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Colorado LEAP annual income limit" + defined_for = StateCode.CO + reference = ( + "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4" + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.co.cdhs.leap.income + size = spm_unit("co_leap_household_size", period) + capped_size = min_(size, p.additional_person_threshold) + state = spm_unit.household("state_code_str", period) + monthly = np.floor( + p.smi_rate * smi(capped_size, state, period, parameters) / MONTHS_IN_YEAR + ) + extra = max_(size - p.additional_person_threshold, 0) + # Flooring reproduces all eight FY2026 published SMI rows; the + # independently printed increment governs additional members. + annual_limit = (monthly + extra * p.additional_person_amount) * MONTHS_IN_YEAR + return where(size > 0, annual_limit, 0) From 0ea2937558df0f31fc15acc7974d14fed6a81f61 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 20:01:14 -0400 Subject: [PATCH 2/5] Correct Colorado LEAP electric rent hotel and lottery rules --- .../leap/eligibility/max_household_size.yaml | 2 +- .../co/cdhs/leap/income/sources/unearned.yaml | 4 +-- .../gov/states/co/cdhs/leap/co_leap.yaml | 35 ++++++++++++++---- .../leap/co_leap_countable_income_person.yaml | 36 +++++++++++++++++++ .../co/cdhs/leap/co_leap_heating_cost.yaml | 18 +++++----- .../states/co/cdhs/leap/co_leap_eligible.py | 5 +++ .../co/cdhs/leap/co_leap_heating_cost.py | 9 ++--- 7 files changed, 86 insertions(+), 23 deletions(-) diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/eligibility/max_household_size.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/eligibility/max_household_size.yaml index 8690a866da4..25aed6126a0 100644 --- a/policyengine_us/parameters/gov/states/co/cdhs/leap/eligibility/max_household_size.yaml +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/eligibility/max_household_size.yaml @@ -8,4 +8,4 @@ metadata: label: Colorado LEAP maximum household size reference: - title: Colorado 2025–26 LEAP Training Operations Manual - href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=29 + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=31 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml index 387001b6272..598af7f8b69 100644 --- a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml @@ -6,7 +6,7 @@ description: Colorado counts these unearned income sources before separately rou # Generic gifts are limited to financial_assistance; irregular receipts, # GI educational benefits and source-specific exclusions lack exact inputs. values: - 2025-11-01: ["rental_income", "farm_rent_income", "interest_income", "dividend_income", "unemployment_compensation", "strike_benefits", "pension_income", "retirement_distributions", "survivor_benefits", "disability_benefits", "workers_compensation", "veterans_benefits", "general_assistance", "co_oap", "alimony_income", "child_support_received", "financial_assistance"] + 2025-11-01: ["rental_income", "farm_rent_income", "interest_income", "dividend_income", "unemployment_compensation", "strike_benefits", "pension_income", "retirement_distributions", "survivor_benefits", "disability_benefits", "workers_compensation", "veterans_benefits", "general_assistance", "co_oap", "alimony_income", "child_support_received", "financial_assistance", "gambling_winnings"] metadata: unit: list @@ -14,4 +14,4 @@ metadata: label: Colorado LEAP unearned income sources reference: - title: Colorado 2025–26 LEAP Training Operations Manual - href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=47 + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=46,47 diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml index 47ede50531a..65bbaa91d8a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml @@ -48,7 +48,7 @@ co_leap_eligible: [true, true, true, true, true, true] co_leap: [1_000, 900, 900, 800, 800, 700] -# Apply source electric shares exactly once to 1,000; all adjusted amounts lie within 200..1,000. +# Apply electric shares once to 1,000. Direct-billed hotels are ineligible under section 3.752.25(B)(8). - name: "Case 3, electric heating costs receive one dwelling adjustment before the award." period: 2026 absolute_error_margin: 0.01 @@ -67,11 +67,11 @@ co_leap_income_limit: [43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284] co_leap_income_contribution_rate: [0, 0, 0, 0, 0, 0, 0, 0, 0] co_leap_heating_cost: [620, 620, 480, 480, 430, 430, 430, 430, 500] - co_leap_eligible: [true, true, true, true, true, true, true, true, true] - co_leap: [620, 620, 480, 480, 430, 430, 430, 430, 500] + co_leap_eligible: [true, true, true, true, true, false, true, true, true] + co_leap: [620, 620, 480, 480, 430, 0, 430, 430, 500] -# Independent electric heat-in-rent table amounts 472..393 already represent heating. All exceed minimum; no second electric adjustment or half-year division. -- name: "Case 4, electric heat in unsubsidized rent uses each table value without another heat share." +# Published rent standards 472..393 receive the Step C share under Step G. Then apply the 200 minimum; no half-year division. +- name: "Case 4, electric heat in unsubsidized rent receives the share and minimum." period: 2026 absolute_error_margin: 0.01 input: @@ -88,9 +88,9 @@ co_leap_countable_income: [0, 0, 0, 0, 0, 0, 0, 0, 0] co_leap_income_limit: [43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284, 43_284] co_leap_income_contribution_rate: [0, 0, 0, 0, 0, 0, 0, 0, 0] - co_leap_heating_cost: [472, 440, 343, 350, 227, 239, 380, 357, 393] + co_leap_heating_cost: [292.64, 272.8, 164.64, 168, 97.61, 102.77, 163.4, 153.51, 196.5] co_leap_eligible: [true, true, true, true, true, true, true, true, true] - co_leap: [472, 440, 343, 350, 227, 239, 380, 357, 393] + co_leap: [292.64, 272.8, 200, 200, 200, 200, 200, 200, 200] # Separate heating: clip(cost-180,200,1000) gives 200,420,820. Subsidized bundled heat without represented surcharge is ineligible despite a rent-table cost. - name: "Case 5, subsidized housing deduction retains the minimum for low costs." @@ -318,3 +318,24 @@ co_leap_heating_cost: 5_000 co_leap_eligible: true co_leap: 1_000 + +# Review C3: monthly wages 3,500 plus a 200 lottery annuity produce +# annual countable income 44,400, above the published 43,284 one-person limit. +# Accepted plan page6 includes lottery winnings; manual page46 counts prizes. +- name: Case 11, regular lottery receipts count toward the income eligibility limit. + period: 2026 + input: + state_code: CO + age: 35 + employment_income: 42_000 + gambling_winnings: 2_400 + ssi: 0 + co_oap: 0 + co_tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_000 + output: + co_leap_countable_income: 44_400 + co_leap_income_limit: 43_284 + co_leap_eligible: false + co_leap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml index 4fd526cc897..e0d6eb355b5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml @@ -314,3 +314,39 @@ co_leap_countable_income_person: [12_000, 0] co_leap_countable_income: 12_000 co_leap_household_size: 1 + +# Review C3: the plan's lottery inclusion and manual prize category are +# unearned income, including a child's receipts. Foster-member income remains +# excluded by the separate household rule. No monthly-to-annual double count. +- name: Lottery annuity receipts count for adults and children but not foster members. + period: 2026 + input: + people: + adult: + age: 35 + gambling_winnings: 2_400 + ssi: 0 + co_oap: 0 + child: + age: 17 + gambling_winnings: 1_200 + ssi: 0 + co_oap: 0 + foster_child: + age: 16 + gambling_winnings: 1_200 + is_in_foster_care: true + ssi: 0 + co_oap: 0 + spm_units: + family: + members: [adult, child, foster_child] + co_tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_000 + households: + household: + members: [adult, child, foster_child] + state_code: CO + output: + co_leap_countable_income_person: [2_400, 1_200, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml index 8a114e0413c..4dfc0ba88fe 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml @@ -15,7 +15,7 @@ co_leap_heating_cost: [620, 620, 480, 480, 430, 430, 430, 430, 500] # Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. -# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +# Step G applies the relevant adjustments to all cost bases; electricity receives its Step C dwelling share. - name: "Case 2, all nine natural gas heat-in-rent rates match the annual handout." period: 2026 absolute_error_margin: 0.01 @@ -28,7 +28,7 @@ co_leap_heating_cost: [200, 177, 156, 146, 110, 116, 186, 271, 151] # Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. -# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +# Step G applies the relevant adjustments to all cost bases; electricity receives its Step C dwelling share. - name: "Case 3, all nine propane heat-in-rent rates match the annual handout." period: 2026 absolute_error_margin: 0.01 @@ -41,8 +41,8 @@ co_leap_heating_cost: [405, 378, 339, 240, 286, 301, 375, 337, 314] # Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. -# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. -- name: "Case 4, all nine electricity heat-in-rent rates match the annual handout." +# Step G applies the relevant adjustments to all cost bases; electricity receives its Step C dwelling share. +- name: "Case 4, all nine electric rent standards receive the required heating share." period: 2026 absolute_error_margin: 0.01 input: @@ -51,10 +51,10 @@ heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true] co_leap_dwelling_type: ["HOUSE_MODULAR", "MOBILE_HOME", "DUPLEX_TRIPLEX_FOURPLEX", "TOWNHOUSE", "APARTMENT_CONDO", "HOTEL_MOTEL", "CABIN", "TINY_HOME", "CAMPER_RV"] output: - co_leap_heating_cost: [472, 440, 343, 350, 227, 239, 380, 357, 393] + co_leap_heating_cost: [292.64, 272.8, 164.64, 168, 97.61, 102.77, 163.4, 153.51, 196.5] # Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. -# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +# Step G applies the relevant adjustments to all cost bases; electricity receives its Step C dwelling share. - name: "Case 5, all nine wood heat-in-rent rates match the annual handout." period: 2026 absolute_error_margin: 0.01 @@ -67,7 +67,7 @@ co_leap_heating_cost: [480, 310, 215, 215, 208, 208, 208, 208, 196] # Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. -# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +# Step G applies the relevant adjustments to all cost bases; electricity receives its Step C dwelling share. - name: "Case 6, all nine fuel oil heat-in-rent rates match the annual handout." period: 2026 absolute_error_margin: 0.01 @@ -80,7 +80,7 @@ co_leap_heating_cost: [378, 202, 169, 444, 169, 169, 169, 169, 151] # Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. -# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +# Step G applies the relevant adjustments to all cost bases; electricity receives its Step C dwelling share. - name: "Case 7, all nine kerosene heat-in-rent rates match the annual handout." period: 2026 absolute_error_margin: 0.01 @@ -93,7 +93,7 @@ co_leap_heating_cost: [378, 202, 169, 444, 169, 169, 169, 169, 151] # Read the independent heat-in-rent table in dwelling order house, mobile, duplex, townhouse, apartment, hotel, cabin, tiny home, RV. -# These are already heating amounts, so electric entries are not multiplied by dwelling electric shares a second time. +# Step G applies the relevant adjustments to all cost bases; electricity receives its Step C dwelling share. - name: "Case 8, all nine coal heat-in-rent rates match the annual handout." period: 2026 absolute_error_margin: 0.01 diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py index 6ffa28c4b88..dcc0b5f00b8 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py @@ -21,8 +21,12 @@ def formula(spm_unit, period, parameters): subsidized = spm_unit("receives_housing_assistance", period) fuel = spm_unit("heating_type", period) fuels = fuel.possible_values + dwelling = spm_unit("co_leap_dwelling_type", period) + hotel = dwelling == dwelling.possible_values.HOTEL_MOTEL # Subsidized rent-included heat can qualify with a separate surcharge; # that fact is unavailable, so this exception is not represented. + # Hotels require heat included in rent. Their additional continuous + # 30-day residence requirement cannot be identified by existing inputs. # Application timing, vendor approval and prior receipt are not modeled. return ( (size > 0) @@ -31,4 +35,5 @@ def formula(spm_unit, period, parameters): & (fuel != fuels.NONE) & (fuel != fuels.UNSPECIFIED) & ~(included & subsidized) + & (~hotel | included) ) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py index c607989a570..1769e6ed6b8 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py @@ -43,8 +43,9 @@ def formula(spm_unit, period, parameters): ], default=0, ) - # The actual-electric-cost instruction governs the direct bill only; - # rent-included amounts already represent heat. Propane uses bulk rates - # and wood purchased rates; bottle/gathered distinctions lack inputs. + # Step G applies the relevant adjustments to every Step A cost basis, + # including rent standards. Apply the electric share exactly once. + # Propane uses bulk rates and wood purchased rates; bottle/gathered + # distinctions lack inputs. # Unknown rent-included fuels have no supported rate and remain a gap. - return where(included, included_cost, expense * electric_share) + return where(included, included_cost, expense) * electric_share From 891370fcb0362a8e25d62c5a8b580b8c4df3d669 Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 2 Nov 2026 11:53:56 -0500 Subject: [PATCH 3/5] Apply Wave 2C sweep and review fixes Co-Authored-By: Claude Opus 5.5 --- .../co/cdhs/leap/income/sources/earned.yaml | 5 +- .../co/cdhs/leap/income/sources/unearned.yaml | 13 ++- .../leap/payment/electric_heat_share.yaml | 2 +- .../heat_in_rent/oil_kerosene_coal.yaml | 2 + policyengine_us/programs.yaml | 2 +- .../gov/states/co/cdhs/leap/co_leap.yaml | 87 ++++++++++++++-- .../leap/co_leap_countable_income_person.yaml | 99 ++++++++++++++++++- .../co/cdhs/leap/co_leap_heating_cost.yaml | 23 ++++- .../gov/states/co/cdhs/leap/co_leap.py | 7 +- .../leap/co_leap_countable_income_person.py | 5 +- .../states/co/cdhs/leap/co_leap_eligible.py | 6 +- .../co/cdhs/leap/co_leap_heating_cost.py | 18 ++-- .../co/cdhs/leap/co_leap_household_size.py | 2 +- .../co/cdhs/leap/co_leap_income_limit.py | 5 +- source_conflicts/candidates.yaml | 60 +++++++++++ 15 files changed, 295 insertions(+), 41 deletions(-) diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml index d5854f687d1..9241b968f83 100644 --- a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml @@ -1,5 +1,6 @@ description: Colorado counts these earned income sources under the Low-income Energy Assistance Program. # Existing net business income is used without another expense deduction. +# partnership_s_corp_income nets the two business types before the source floor. values: 2025-11-01: ["employment_income", "self_employment_income", "sstb_self_employment_income", "farm_operations_income", "partnership_s_corp_income"] @@ -8,5 +9,5 @@ metadata: period: year label: Colorado LEAP earned income sources reference: - - title: Colorado 2025–26 LEAP Training Operations Manual - href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=46 + - title: "Colorado 2025–26 LEAP Training Operations Manual #page 48-49,51,61-62,79-80" + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=48 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml index 74d465cdfbd..f4588648cbf 100644 --- a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml @@ -2,11 +2,16 @@ description: Colorado counts these unearned income sources before separately rou # Social Security and SSI are separately truncated per recipient monthly. # Take-up-gated TANF is added once at SPM-unit level. Survivor benefits exclude # SSA survivors; pension totals already include their public/private parts. +# Military retirement includes Survivor Benefit Plan annuities. # Retirement distributions aggregate IRA, 401(k), SEP, 403(b), and Keogh. -# Generic gifts are limited to financial_assistance; irregular receipts, -# GI educational benefits and source-specific exclusions lack exact inputs. +# OAP and the AND state supplement are public assistance income (3.752.21 L). +# Railroad retirement and trust payments are periodic payments (3.752.211 G, K). +# miscellaneous_income and gi_cash_assistance fall under the catch-all for +# payments from any other source (3.752.21). Generic gifts are limited to +# financial_assistance. GI educational benefits and source-specific exclusions +# lack exact inputs. values: - 2025-11-01: ["rental_income", "farm_rent_income", "interest_income", "dividend_income", "total_unemployment_compensation", "strike_benefits", "pension_income", "military_retirement_pay", "retirement_distributions", "survivor_benefits", "disability_benefits", "workers_compensation", "veterans_benefits", "general_assistance", "co_oap", "alimony_income", "child_support_received", "financial_assistance", "gambling_winnings"] + 2025-11-01: ["rental_income", "farm_rent_income", "interest_income", "ordinary_dividend_income", "total_unemployment_compensation", "strike_benefits", "pension_income", "military_retirement_income", "railroad_benefits", "retirement_distributions", "survivor_benefits", "disability_benefits", "workers_compensation", "veterans_benefits", "general_assistance", "co_oap", "co_state_supplement", "estate_income", "alimony_income", "child_support_received", "financial_assistance", "gambling_winnings", "miscellaneous_income", "gi_cash_assistance"] metadata: unit: list @@ -14,4 +19,4 @@ metadata: label: Colorado LEAP unearned income sources reference: - title: "Colorado 2025–26 LEAP Training Operations Manual #page 46-48" - href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=46 \ No newline at end of file + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=46 diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/electric_heat_share.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/electric_heat_share.yaml index e6977230038..33347942f14 100644 --- a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/electric_heat_share.yaml +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/electric_heat_share.yaml @@ -1,4 +1,4 @@ -description: Colorado treats this share of direct electricity costs as heating by dwelling type under the Low-income Energy Assistance Program. +description: Colorado treats this share of electricity costs as heating by dwelling type under the Low-income Energy Assistance Program. HOUSE_MODULAR: 2025-11-01: 0.62 MOBILE_HOME: diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/oil_kerosene_coal.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/oil_kerosene_coal.yaml index 14bb7cf2386..834f78f73f6 100644 --- a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/oil_kerosene_coal.yaml +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/heat_in_rent/oil_kerosene_coal.yaml @@ -27,3 +27,5 @@ metadata: reference: - title: Colorado FY2026 LEAP benefit methodology and annual rates href: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=6 + - title: Colorado 2025–26 LEAP Training Operations Manual + href: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=92 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index c7a6d4a0081..690ba466e57 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -967,7 +967,7 @@ programs: variable: co_leap parameter_prefix: gov.states.co.cdhs.leap verified_years: "2026" - notes: Regular heating with reported annual primary-fuel costs used as a prior-heating-season proxy and the published heat-in-rent schedule. Includes income contribution, electric heating shares, household sharing and subsidized-housing adjustment. Counts received UI and take-up-gated TANF, prevents source losses from cancelling other receipts, and preserves strict federal income protection for the actual qualified household before the state size cap. Missing-history/vendor fallback, actual meter sharing, rent surcharges and bottle/gathered-fuel distinctions are not fully represented. Earlier backfills and FY2027 benefits remain unverified. + notes: FY2026 regular heating assistance, including heat-in-rent costs, income contribution rates and the subsidized-housing deduction. Crisis, cooling, weatherization and equipment assistance are out of scope. # --- SSA programs --- - id: ssi diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml index e84ef56448d..58e6f358a70 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap.yaml @@ -170,7 +170,8 @@ co_leap_eligible: [true, true] co_leap: [293.6, 330.3] -# First unit income 1,000/month has 10% contribution. Divide by both units even though second fails income:1,000*0.9/2 -180 =270. Dividing after subsidy or counting only eligible units gives the wrong amount. +# First unit income 1,000/month has a 10% contribution. Divide by both units even though the second fails +# income, then take the allowance last, in the manual's order (pp. 90, 94): 1,000 x 0.9 / 2 - 180 = 270. - name: "Case 7, an ineligible sharing unit still counts and housing deduction follows division." period: 2026 absolute_error_margin: 0.01 @@ -319,7 +320,7 @@ co_leap_eligible: true co_leap: 1_000 -# Review C3: monthly wages 3,500 plus a 200 lottery annuity produce +# Monthly wages 3,500 plus a 200 lottery annuity produce # annual countable income 44,400, above the published 43,284 one-person limit. # Accepted plan page6 includes lottery winnings; manual page46 counts prizes. - name: Case 11, regular lottery receipts count toward the income eligibility limit. @@ -401,14 +402,14 @@ co_leap_eligible: true co_leap: 1_000 -# Two actual 25-member sharing households retain the ordinary state size cap15 -# and income ceiling132,360. The 2025 FPG for25 is15,650+24*5,500=147,650; -# its cent-rounded110% protection ends strictly below162,415. At150,000income, -# the20%contribution applies and the1,000heatingbill produces800. Exact162,415 -# is not protected. Members are actual qualified nonfoster people, not a size -# override; the state cap does not replace their legal sharing-household size. -# Manual pages4-5: size15 monthly125%upper=5,641+7*573=9,652; -#175%upper=7,898+7*802=13,512. Thus12,500/month requires20%, not30%. +# Two actual 25-member sharing households retain the ordinary state size cap of +# 15 and income ceiling of 132,360. The 2025 FPG for 25 is 15,650 + 24 x 5,500 = +# 147,650; its cent-rounded 110% protection ends strictly below 162,415. At 150,000 +# of income the 20% contribution applies and the 1,000 heating bill produces 800. +# Exactly 162,415 is not protected. Members are actual qualified nonfoster people, +# not a size override; the state cap does not replace their sharing-household size. +# Manual pages 4-5: size 15 monthly 125% upper = 5,641 + 7 x 573 = 9,652; 175% upper +# = 7,898 + 7 x 802 = 13,512. Thus 12,500 a month requires 20%, not 30%. - name: Case 14, actual large households retain strict federal income protection. period: 2026 input: @@ -741,3 +742,69 @@ co_leap_income_contribution_rate: [0.2, 0.3] co_leap_eligible: [true, false] co_leap: [800, 0] + +# Public housing receives the subsidized-housing treatment without a voucher: +# clip(600 - 180, 200, 1,000) = 420, and public housing with heat in rent is +# ineligible, as in Case 5. +- name: Case 15, public housing receives the subsidized-housing treatment. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [CO, CO] + heating_type: [NATURAL_GAS, NATURAL_GAS] + age: [35, 35] + ssi: [0, 0] + co_oap: [0, 0] + co_tanf: [0, 0] + gas_expense: [600, 600] + receives_housing_assistance: [false, false] + is_in_public_housing: [true, true] + heat_expense_included_in_rent: [false, true] + output: + co_leap_eligible: [true, false] + co_leap: [420, 0] + +# First unit: 50,000 / 12 = 4,167 a month, above the 3,607 limit and the 17,215 +# floor: ineligible. Second unit: 15,000 / 12 = 1,250 a month, the 10% band +# (above 978, at most 1,630): 1,000 x 0.9 = 900. +- name: Case 16, miscellaneous income counts toward the limit and the contribution. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ssi: 0 + co_oap: 0 + miscellaneous_income: 50_000 + person2: + age: 40 + ssi: 0 + co_oap: 0 + miscellaneous_income: 15_000 + spm_units: + spm_unit1: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + co_tanf: 0 + spm_unit2: + members: [person2] + heating_type: NATURAL_GAS + gas_expense: 1_000 + co_tanf: 0 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household1: + members: [person1] + state_code: CO + household2: + members: [person2] + state_code: CO + output: + co_leap_eligible: [false, true] + co_leap: [0, 900] diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml index f305d317812..bdbc06e3191 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml @@ -50,7 +50,7 @@ farm_rent_income: 1_800 taxable_interest_income: 100 tax_exempt_interest_income: 50 - dividend_income: 300 + ordinary_dividend_income: 300 unemployment_compensation: 400 strike_benefits: 500 taxable_pension_income: 1_000 @@ -316,10 +316,10 @@ co_leap_countable_income: 12_000 co_leap_household_size: 1 -# Review C3: the plan's lottery inclusion and manual prize category are +# The plan's lottery inclusion and manual prize category are # unearned income, including a child's receipts. Foster-member income remains # excluded by the separate household rule. No monthly-to-annual double count. -- name: Lottery annuity receipts count for adults and children but not foster members. +- name: Case 10, lottery annuity receipts count for adults and children but not foster members. period: 2026 input: people: @@ -353,7 +353,7 @@ co_leap_countable_income_person: [2_400, 1_200, 0] -# Contract control: Colorado has no modeled state UI implementation yet. Supply +# Colorado has no modeled state UI implementation yet. Supply # the existing modeled aggregate to test the shared fallback, not a new income # input or an assumed Colorado weekly benefit. Reported UI takes precedence. - name: Case 11, modeled unemployment fallback and reported precedence count once. @@ -370,3 +370,94 @@ total_unemployment_compensation: [1_200, 400] co_leap_countable_income_person: [1_200, 400] co_leap_countable_income: [1_200, 400] + +# 9 CCR 2503-7 3.752.21(L) counts Aid to the Needy Disabled. SSI reduced to +# 700/month by in-kind support plus the AND-CS supplement to the 994 grant +# standard (294/month): 700*12 + 294*12 = 8,400 + 3,528 = 11,928. +- name: Case 12, the AND state supplement counts with SSI. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + is_disabled: true + ssi: 8_400 + co_state_supplement: 3_528 + co_oap: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: CO + output: + co_leap_countable_income_person: 11_928 + co_leap_countable_income: 11_928 + +# 9 CCR 2503-7 3.752.211 G and K count railroad retirement and trust payments: +# 4,800 + 1,200 = 6,000. +- name: Case 13, railroad retirement and trust payments count. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 66 + ssi: 0 + co_oap: 0 + railroad_benefits: 4_800 + estate_income: 1_200 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: CO + output: + co_leap_countable_income_person: 6_000 + co_leap_countable_income: 6_000 + +# 9 CCR 2503-7 3.752.21 counts payments from any other source that are a gain or +# benefit to the applicant: 1,200 + 2,400 = 3,600. +- name: Case 14, miscellaneous income and guaranteed-income cash count. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ssi: 0 + co_oap: 0 + miscellaneous_income: 1_200 + gi_cash_assistance: 2_400 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 600 + co_tanf: 0 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: CO + output: + co_leap_countable_income_person: 3_600 + co_leap_countable_income: 3_600 diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml index 84fe018f2f5..ae9551eeacc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_heating_cost.yaml @@ -132,13 +132,26 @@ output: co_leap_heating_cost: [0, 0, 0] -# The published rent table has no NONE, unspecified, solar or other-fuel column; these zeros describe unsupported input classifications, not sourced legal exclusions. +# The published rent table has no NONE, unspecified or other-fuel column; these zeros describe unsupported input classifications, not sourced legal exclusions. - name: "Case 11, unsupported heat-in-rent fuel classifications do not borrow a table." period: 2026 absolute_error_margin: 0.01 input: - state_code: ["CO", "CO", "CO", "CO"] - heating_type: ["NONE", "UNSPECIFIED", "SOLAR", "OTHER"] - heat_expense_included_in_rent: [true, true, true, true] + state_code: ["CO", "CO", "CO"] + heating_type: ["NONE", "UNSPECIFIED", "OTHER"] + heat_expense_included_in_rent: [true, true, true] + output: + co_leap_heating_cost: [0, 0, 0] + +# No source lists solar heat; a solar home is treated as electric. A house's 1,000 direct electric bill takes the 62% share: 620. A house's 472 electric heat-in-rent standard takes it too: 472 x 0.62 = 292.64. +- name: "Case 12, solar heat takes the electric share and the electric rent standard." + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO"] + heating_type: ["SOLAR", "SOLAR"] + pre_subsidy_electricity_expense: [1_000, 0] + heat_expense_included_in_rent: [false, true] + co_leap_dwelling_type: ["HOUSE_MODULAR", "HOUSE_MODULAR"] output: - co_leap_heating_cost: [0, 0, 0, 0] + co_leap_heating_cost: [620, 292.64] diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py index cc398a4023d..ef281b03b81 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py @@ -8,7 +8,7 @@ class co_leap(Variable): unit = USD label = "Colorado LEAP regular heating assistance" defined_for = "co_leap_eligible" - # PDF pages 92-95 + # PDF pages 90,92-95 reference = ( "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=92" ) @@ -27,7 +27,10 @@ def formula(spm_unit, period, parameters): * (1 - contribution) / max_(shared_households, 1) ) - subsidized = spm_unit("receives_housing_assistance", period) + subsidized = spm_unit( + "receives_housing_assistance", period + ) | spm_unit.household("is_in_public_housing", period) + # The allowance comes off last, following the order at manual pp. 90, 94. adjusted = shared_cost - subsidized * p.subsidized_housing_deduction # FY2026 verified policy; parameter backfilling does not verify prior # years. The minimum applies even when adjusted costs are smaller. diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py index a98605333ea..4f1914ecbdd 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py @@ -20,7 +20,10 @@ def formula(person, period, parameters): earned = earned + max_(person(source, period), 0) age = person("age", period) earned = where(age >= p.earned_min_age, earned, 0) - unearned = sum(max_(person(source, period), 0) for source in p.sources.unearned) + unearned = 0 + for source in p.sources.unearned: + # add() annualizes monthly sources such as the AND state supplement. + unearned = unearned + max_(add(person, period, [source]), 0) # Annual flows approximate ongoing application-month income. The # monthly SSA and SSI amounts lose cents separately for each person. # Medicare premiums remain in gross SSA income under Colorado rules. diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py index 388d102074f..0072fb08176 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py @@ -12,7 +12,7 @@ class co_leap_eligible(Variable): "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", # PDF pages 5,8 "https://liheapch.acf.gov/docs/2026/state-plans/CO_Plan_2026.pdf#page=5", - # PDF pages 29,31,46,51-53,55 + # PDF pages 29,31,46,51-53,55,57 "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=29", ) @@ -37,7 +37,9 @@ def formula(spm_unit, period, parameters): federal_floor = np.round(guideline * p.gov.hhs.liheap.fpg_floor, 2) cost = spm_unit("co_leap_heating_cost", period) included = spm_unit("heat_expense_included_in_rent", period) - subsidized = spm_unit("receives_housing_assistance", period) + subsidized = spm_unit( + "receives_housing_assistance", period + ) | spm_unit.household("is_in_public_housing", period) fuel = spm_unit("heating_type", period) fuels = fuel.possible_values dwelling = spm_unit("co_leap_dwelling_type", period) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py index 260fb267805..13549f7ac9c 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_heating_cost.py @@ -21,15 +21,18 @@ def formula(spm_unit, period, parameters): # It cannot identify actual prior November-April history or vendor # approval. Explicit zero does not trigger a missing-history flat rate. expense = max_(spm_unit("heating_expense", period), 0) - electric_share = where( - fuel == fuels.ELECTRICITY, p.electric_heat_share[dwelling], 1 - ) + # No Colorado source lists solar heat. A solar home is treated as + # electric: heating_expense reads its electric bill, and the rate + # tables have no solar column, so it takes the electric share and + # the electric rent standard. + electric = (fuel == fuels.ELECTRICITY) | (fuel == fuels.SOLAR) + electric_share = where(electric, p.electric_heat_share[dwelling], 1) table = p.heat_in_rent included_cost = select( [ fuel == fuels.NATURAL_GAS, fuel == fuels.PROPANE, - fuel == fuels.ELECTRICITY, + electric, fuel == fuels.WOOD, (fuel == fuels.FUEL_OIL) | (fuel == fuels.KEROSENE) @@ -44,8 +47,11 @@ def formula(spm_unit, period, parameters): ], default=0, ) - # Step G applies the relevant adjustments to every Step A cost basis, - # including rent standards. Apply the electric share exactly once. + # Inference: Step G reaches every Step A cost and the Step C table covers + # total electric costs, so the electric rent standard also takes the + # share, applied exactly once. Fuel oil reads the rate column headed Fuel + # Oil/Kerosene (inference); the rate tables also print a column headed + # Propane Fuel Oil. # Propane uses bulk rates and wood purchased rates; bottle/gathered # distinctions lack inputs. # Unknown rent-included fuels have no supported rate and remain a gap. diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_household_size.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_household_size.py index 54548aff375..d0c38840b92 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_household_size.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_household_size.py @@ -7,7 +7,7 @@ class co_leap_household_size(Variable): definition_period = YEAR label = "Colorado LEAP eligible household size" defined_for = StateCode.CO - # PDF pages 29,51,55 + # PDF pages 29,51,55,57 reference = ( "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=29" ) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py index 1d6b4392f8d..26f4d0e6eaf 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py @@ -1,5 +1,5 @@ from policyengine_us.model_api import * -from policyengine_us.variables.gov.hhs.hhs_smi import smi +from policyengine_us.variables.gov.hhs.hhs_smi import liheap_smi_limit class co_leap_income_limit(Variable): @@ -19,7 +19,8 @@ def formula(spm_unit, period, parameters): capped_size = min_(size, p.additional_person_threshold) state = spm_unit.household("state_code_str", period) monthly = np.floor( - p.smi_rate * smi(capped_size, state, period, parameters) / MONTHS_IN_YEAR + liheap_smi_limit(capped_size, state, p.smi_rate, period, parameters) + / MONTHS_IN_YEAR ) extra = max_(size - p.additional_person_threshold, 0) # Flooring reproduces all eight FY2026 published SMI rows; the diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 7d8c41658c6..fdfa660e904 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -1052,6 +1052,66 @@ candidates: state: ruled note: The October 2026 ruling retains the statutory bar; verify the weak literal joint-return interpretation and obtain a corresponding 2025 example. +- id: us-co:leap-subsidized-allowance-order + program: liheap + years: + from: 2026 + to: 2026 + type: federal-fiscal + question: Does Colorado's $180 subsidized-housing allowance come off the heating cost remaining after Step B, before + the electric, income and sharing adjustments, or last, after them? + sources: + - kind: regulation + citation: 9 CCR 2503-7 3.758.47 Steps F and G, p.43 + url: https://www.sos.state.co.us/CCR/GenerateRulePdf.do?ruleVersionId=12221&fileName=9%20CCR%202503-7#page=43 + - kind: plan + citation: Colorado FY2026 LIHEAP plan attachment, benefit methodology, p.2 + url: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=2 + - kind: manual + citation: 2025-26 LEAP Training and Operations Manual, pp.90, 94 + url: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=90 + readings: + statute: Step F deducts the allowance from the cost remaining after Step B, and Step G applies Steps B-F. The + plan attachment repeats this text. + other: The manual applies the adjustments in its listed order, with the allowance last. + example: A subsidized household sharing a $1,000 bill with one other household, at a 10% contribution, receives $270 + with the allowance last (1,000 x 0.9 / 2 - 180) and $369 with it first ((1,000 - 180) x 0.9 / 2). + pe_us: + follows: conflicting-source + code: + - policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py + state: unreviewed + note: PE-US takes the allowance last. Step F is lettered after Steps C-E, and the same words sat under the 2017 rule's + Step E, after the electric and sharing steps. +- id: us-co:liheap-income-floor-vs-smi-limit + program: liheap + years: + from: 2026 + to: 2026 + type: federal-fiscal + question: Can Colorado's LEAP income limit, which stops growing at 15 members, exclude a household of 21 or more whose + income is below the federal 110% poverty-guideline floor? + 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: manual + citation: Colorado 2025-26 LEAP Training Operations Manual, income guidelines and household size, pp.4, 31 + url: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4 + readings: + statute: Income below 110% of the poverty guideline cannot by itself exclude the household. + other: The manual caps household size at 15, so the $132,360 limit falls below the floor from 21 actual members. + example: Twenty-five people with $150,000 exceed the $132,360 size-15 limit but are below the $162,415 floor (2025 + guideline, one-year lag), so they keep the 20% contribution and an $800 award on a $1,000 bill. + pe_us: + follows: statute + code: + - policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py + - policyengine_us/parameters/gov/hhs/liheap/fpg_floor.yaml + - policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml + state: unreviewed + note: PE-US applies the floor to the actual qualified household, before the state size cap, rounded to cents with + the statute's strict "less than" (co_leap_eligible.py). - id: us-co:oap-initial-application-income-test program: old-age-pension years: From 23d7f879826553db9e14e92cb2e980ab8827e660 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 3 Nov 2026 16:43:07 -0500 Subject: [PATCH 4/5] Apply review fixes to Colorado LEAP Co-Authored-By: Claude Opus 5.5 --- .../co/cdhs/leap/income/sources/earned.yaml | 3 +- .../co/cdhs/leap/payment/fpg_year_lag.yaml | 2 +- policyengine_us/programs.yaml | 16 +-- .../leap/co_leap_countable_income_person.yaml | 30 ++++++ .../gov/states/co/cdhs/leap/co_leap.py | 2 +- .../leap/co_leap_countable_income_person.py | 2 +- .../states/co/cdhs/leap/co_leap_eligible.py | 4 - source_conflicts/candidates.yaml | 99 ++++++++++++++++++- 8 files changed, 138 insertions(+), 20 deletions(-) diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml index 9241b968f83..df08b970d57 100644 --- a/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/earned.yaml @@ -1,8 +1,9 @@ description: Colorado counts these earned income sources under the Low-income Energy Assistance Program. # Existing net business income is used without another expense deduction. # partnership_s_corp_income nets the two business types before the source floor. +# Enter basic pay in military_basic_pay or employment_income, not both. values: - 2025-11-01: ["employment_income", "self_employment_income", "sstb_self_employment_income", "farm_operations_income", "partnership_s_corp_income"] + 2025-11-01: ["employment_income", "military_basic_pay", "self_employment_income", "sstb_self_employment_income", "farm_operations_income", "partnership_s_corp_income"] metadata: unit: list diff --git a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml index 09d198ffaf4..e9dfbd89c59 100644 --- a/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml +++ b/policyengine_us/parameters/gov/states/co/cdhs/leap/payment/fpg_year_lag.yaml @@ -1,4 +1,4 @@ -description: Colorado uses federal poverty guidelines from this many years before the heating season under the Low-income Energy Assistance Program. +description: Colorado uses federal poverty guidelines from this many years before the calendar year in which the heating season ends under the Low-income Energy Assistance Program. # FY2026 uses the 2025 FPG; earlier backfilled years are unverified. values: 2025-11-01: 1 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 76a0e928588..090872dbd48 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1020,6 +1020,14 @@ programs: parameter_prefix: gov.states.az.des.liheap verified_years: "2026" notes: FY2026 Standard benefit covering heating and cooling bills from the point-based benefit matrix. Crisis assistance, water for evaporative cooling and weatherization are out of scope. + - state: CO + status: partial + name: Colorado LEAP + full_name: Colorado Low-income Energy Assistance Program + variable: co_leap + parameter_prefix: gov.states.co.cdhs.leap + verified_years: "2026" + notes: FY2026 regular heating assistance, including heat-in-rent costs, income contribution rates and the subsidized-housing deduction. Crisis, cooling, weatherization and equipment assistance are out of scope. - state: GA status: partial name: Georgia LIHEAP @@ -1314,14 +1322,6 @@ programs: parameter_prefix: gov.states.wy.dfs.lieap verified_years: "2026" notes: FY2026 regular heating from the published fuel cost standards. Crisis, cooling, weatherization and equipment assistance are out of scope. - - state: CO - status: partial - name: Colorado LEAP - full_name: Colorado Low-income Energy Assistance Program - variable: co_leap - parameter_prefix: gov.states.co.cdhs.leap - verified_years: "2026" - notes: FY2026 regular heating assistance, including heat-in-rent costs, income contribution rates and the subsidized-housing deduction. Crisis, cooling, weatherization and equipment assistance are out of scope. # --- SSA programs --- - id: ssi diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml index bdbc06e3191..6e25b92902e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_countable_income_person.yaml @@ -461,3 +461,33 @@ output: co_leap_countable_income_person: 3_600 co_leap_countable_income: 3_600 + +# $30,000 is $2,500 a month, above the $2,282 band top at 175% for one person, +# so 30% comes off a $1,000 bill: $700. +- name: Case 15, military basic pay counts as earned income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ssi: 0 + co_oap: 0 + military_basic_pay: 30_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + co_tanf: 0 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: CO + output: + co_leap_countable_income_person: 30_000 + co_leap_countable_income: 30_000 + co_leap: 700 diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py index ef281b03b81..344caf26bcb 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py @@ -10,7 +10,7 @@ class co_leap(Variable): defined_for = "co_leap_eligible" # PDF pages 90,92-95 reference = ( - "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=92" + "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=90" ) def formula(spm_unit, period, parameters): diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py index 4f1914ecbdd..a6d89fc3e8d 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_countable_income_person.py @@ -34,4 +34,4 @@ def formula(person, period, parameters): # Known foster individuals are outside the LEAP household; income of # nonqualified immigrants remains included. Each received income source # is nonnegative, and existing business inputs are already net of costs. - return where(foster, 0, max_(income, 0)) + return where(foster, 0, income) diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py index 0072fb08176..65672eb7ad5 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_eligible.py @@ -40,8 +40,6 @@ def formula(spm_unit, period, parameters): subsidized = spm_unit( "receives_housing_assistance", period ) | spm_unit.household("is_in_public_housing", period) - fuel = spm_unit("heating_type", period) - fuels = fuel.possible_values dwelling = spm_unit("co_leap_dwelling_type", period) hotel = dwelling == dwelling.possible_values.HOTEL_MOTEL # Subsidized rent-included heat can qualify with a separate surcharge; @@ -53,8 +51,6 @@ def formula(spm_unit, period, parameters): (size > 0) & ((income <= limit) | (income < federal_floor)) & (cost > 0) - & (fuel != fuels.NONE) - & (fuel != fuels.UNSPECIFIED) & ~(included & subsidized) & (~hotel | included) ) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 263f3e83fbf..3f8e0c742c0 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -1602,6 +1602,60 @@ candidates: state: ruled note: The October 2026 ruling retains the statutory bar; verify the weak literal joint-return interpretation and obtain a corresponding 2025 example. +- id: us-co:leap-catch-all-income + program: liheap + years: + from: 2026 + to: 2026 + type: federal-fiscal + question: Does Colorado LEAP count miscellaneous receipts and guaranteed-income cash under the rule's catch-all, + although the FY2026 plan's section 1.9 leaves Other unchecked? + sources: + - kind: regulation + citation: 9 CCR 2503-7 3.752.21, p.20 + url: https://www.sos.state.co.us/CCR/GenerateRulePdf.do?ruleVersionId=12221&fileName=9%20CCR%202503-7#page=20 + - kind: plan + citation: Colorado FY2026 LIHEAP State Plan, section 1.9, pp.5-7 + url: https://liheapch.acf.gov/docs/2026/state-plans/CO_Plan_2026.pdf#page=5 + readings: + statute: Countable unearned income includes "payments from any other source, which is considered to be a gain or + benefit to the applicant or recipient". + other: Plan 1.9 leaves Other unchecked. + example: One adult with $50,000 of miscellaneous_income and a $1,000 gas bill receives $0 under the rule and $1,000 + if the receipt stays out. + pe_us: + follows: statute + code: + - policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml + state: ruled + note: 'Ruled 2026-11-02: follow the rule over the plan.' +- id: us-co:leap-prizes-lump-sums + program: liheap + years: + from: 2026 + to: 2026 + type: federal-fiscal + question: Do gambling winnings count as prizes under the rule, or does the manual's exemption for one-time lump sums + reach them? + sources: + - kind: regulation + citation: 9 CCR 2503-7 3.752.21 A, p.20 + url: https://www.sos.state.co.us/CCR/GenerateRulePdf.do?ruleVersionId=12221&fileName=9%20CCR%202503-7#page=20 + - kind: manual + citation: 2025-26 LEAP Training and Operations Manual, p.82 + url: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=82 + readings: + statute: Countable unearned income includes "Inheritance, gifts, and prizes". + other: The manual exempts "All one-time non-recurring lump sum benefits received", citing 3.752.23 EE. + example: One adult with $50,000 of gambling winnings and a $1,000 gas bill receives $0 under the rule and $1,000 if + the winnings are an exempt lump sum. + pe_us: + follows: statute + code: + - policyengine_us/parameters/gov/states/co/cdhs/leap/income/sources/unearned.yaml + state: unreviewed + note: PE-US counts gambling_winnings as prizes. The regulation's own exemption, 3.752.23 EE, lists lump sums for income + tax refunds, rebates or credits and retroactive Social Security, SSI and public assistance payments. - id: us-co:leap-subsidized-allowance-order program: liheap years: @@ -1627,12 +1681,49 @@ candidates: example: A subsidized household sharing a $1,000 bill with one other household, at a 10% contribution, receives $270 with the allowance last (1,000 x 0.9 / 2 - 180) and $369 with it first ((1,000 - 180) x 0.9 / 2). pe_us: - follows: conflicting-source + follows: gap-fill code: - policyengine_us/variables/gov/states/co/cdhs/leap/co_leap.py - state: unreviewed - note: PE-US takes the allowance last. Step F is lettered after Steps C-E, and the same words sat under the 2017 rule's - Step E, after the electric and sharing steps. + state: ruled + note: 'Ruled 2026-11-02: take the allowance last, in the manual''s order. The rule''s text does not settle the order: + Step F is lettered after Steps C-E, Step G subtracts "Steps B-F", and the same words sat under the 2017 rule''s Step + E, after the electric and sharing steps.' +- id: us-co:leap-whole-dollar-income-tables + program: liheap + years: + from: 2026 + to: 2026 + type: federal-fiscal + question: Do Colorado's LEAP contribution bands and income limits use exact percentages of the poverty guideline and + state median income, or the whole-dollar monthly tables the plan attachment and manual print? + sources: + - kind: regulation + citation: 9 CCR 2503-7 3.752.22 D, p.23, and 3.758.47 Step D, p.43 + url: https://www.sos.state.co.us/CCR/GenerateRulePdf.do?ruleVersionId=12221&fileName=9%20CCR%202503-7#page=23 + - kind: plan + citation: Colorado FY2026 LIHEAP plan attachment, rates tables, p.5 + url: https://liheapch.acf.gov/docs/2026/benefits-matricies/CO_BenefitMatrix_Heat-Crisis_2026.pdf#page=5 + - kind: manual + citation: 2025-26 LEAP Training and Operations Manual, rates handout, p.4 + url: https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4 + readings: + statute: No statute is supplied; Step D sets the contribution by "0 – 75% FPL", "75.01 – 125% FPL", "125.01 – 175% FPL" + and "175.01% +", and 3.752.22 D sets the limit at 60 percent of state median income. + other: The plan attachment and manual print whole-dollar monthly amounts, $978 at 75% FPL and $3,607 at 60% of state + median income for one person, and the attachment says Colorado "uses the FPL chart". + example: One adult with wages of $11,737.20 ($978.10 a month, 74.998% of the guideline) and a $1,000 gas bill receives + $900 under the printed $978 and $1,000 under Step D's 75%. One adult with $43,290 and the same bill receives $0 + under the printed $3,607 and $700 within 60% of state median income ($43,293). + pe_us: + follows: gap-fill + code: + - policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_contribution_rate.py + - policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py + state: ruled + note: 'Ruled 2026-11-03: keep the printed tables. The rule states no dollar conversion, and PE-US reproduces the tables + by rounding the monthly guideline and each percentage half up and flooring 60% of state median income to the month. + The rule''s next sentence lets the department "adjust the income limits annually based on funds available and the + state median income guidelines".' - id: us-co:liheap-income-floor-vs-smi-limit program: liheap years: From 80916be8822bbe21a176138b219aa440e85ec3fe Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 5 Nov 2026 11:42:25 -0500 Subject: [PATCH 5/5] Cap Colorado LEAP income limit at the federal maximum Stops the backfilled period 2025 limits for sizes 9-13 at the greater of 60% of SMI and 150% of the guideline. FY2026 printed limits are unchanged. Co-Authored-By: Claude Opus 5.5 --- .../co/cdhs/leap/co_leap_income_limit.yaml | 15 ++++++++++++ .../co/cdhs/leap/co_leap_income_limit.py | 24 ++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_limit.yaml index 65c9d20750b..08e47d53307 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/cdhs/leap/co_leap_income_limit.yaml @@ -24,3 +24,18 @@ co_leap_household_size: [0] output: co_leap_income_limit: [0] + +# Period 2025 adds FY2026's printed $208 to FY2025's lower SMI ($130,104 for four; 60% is $78,062). +# 42 U.S.C. 8624(b)(2)(B) stops the limit at the greater of 60% of SMI and 150% of the 2024 guideline. +# Size 9: $110,220 stops at $78,062 x 1.41 = $110,067. +# Size 13: $120,204 stops at $78,062 x 1.53 = $119,434, above 150% of the guideline ($119,430). +# Size 14: ($8,977 + 6 x $208) x 12 = $122,700 stays under 150% of the guideline ($127,500). +- name: "Case 3, backfilled period 2025 limits stop at the federal maximum." + period: 2025 + absolute_error_margin: 0.01 + input: + state_code: ["CO", "CO", "CO"] + heating_type: ["NATURAL_GAS", "NATURAL_GAS", "NATURAL_GAS"] + co_leap_household_size: [9, 13, 14] + output: + co_leap_income_limit: [110_067, 119_434, 122_700] diff --git a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py index 26f4d0e6eaf..957894c6539 100644 --- a/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py +++ b/policyengine_us/variables/gov/states/co/cdhs/leap/co_leap_income_limit.py @@ -1,5 +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 co_leap_income_limit(Variable): @@ -10,11 +11,14 @@ class co_leap_income_limit(Variable): label = "Colorado LEAP annual income limit" defined_for = StateCode.CO reference = ( - "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4" + "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", + "https://drive.google.com/file/d/1G3XKsXyKoPZmsA5-P6NI6w3svP99xOZd/view#page=4", ) def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.co.cdhs.leap.income + gov = parameters(period).gov + leap = gov.states.co.cdhs.leap + p = leap.income size = spm_unit("co_leap_household_size", period) capped_size = min_(size, p.additional_person_threshold) state = spm_unit.household("state_code_str", period) @@ -26,4 +30,18 @@ def formula(spm_unit, period, parameters): # Flooring reproduces all eight FY2026 published SMI rows; the # independently printed increment governs additional members. annual_limit = (monthly + extra * p.additional_person_amount) * MONTHS_IN_YEAR - return where(size > 0, annual_limit, 0) + # 42 U.S.C. 8624(b)(2)(B) pays no household above the greater of 60% of SMI + # and 150% of the guideline. The printed FY2026 increment stays within that, + # but it can overshoot in a year with a lower SMI. + ceiling = max_( + liheap_smi_limit(size, state, gov.hhs.liheap.smi_limit, period, parameters), + gov.hhs.liheap.fpg_limit + * fpg( + size, + spm_unit.household("state_group_str", period), + period, + parameters, + year_lag=leap.payment.fpg_year_lag, + ), + ) + return where(size > 0, min_(annual_limit, ceiling), 0)