From 4f9eb5de8a97303819cd512e9d02c545b84921de Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 30 Sep 2026 15:52:47 -0400 Subject: [PATCH 1/9] Add Indiana EAP regular heating assistance --- changelog.d/in-eap.added.md | 1 + .../gov/states/in/ihcda/eap/adult_age.yaml | 9 + .../states/in/ihcda/eap/amount_per_point.yaml | 9 + .../gov/states/in/ihcda/eap/elderly_age.yaml | 9 + .../gov/states/in/ihcda/eap/fuel_points.yaml | 31 ++++ .../eap/higher_income_electric_payment.yaml | 9 + .../in/ihcda/eap/higher_income_points.yaml | 9 + .../gov/states/in/ihcda/eap/income_limit.yaml | 9 + .../states/in/ihcda/eap/income_sources.yaml | 24 +++ .../eap/lower_income_electric_payment.yaml | 9 + .../in/ihcda/eap/lower_income_points.yaml | 9 + .../in/ihcda/eap/lower_income_rate.yaml | 9 + .../eap/middle_income_electric_payment.yaml | 9 + .../in/ihcda/eap/middle_income_points.yaml | 9 + .../in/ihcda/eap/middle_income_rate.yaml | 9 + .../in/ihcda/eap/minimum_monthly_rent.yaml | 9 + .../in/ihcda/eap/single_family_points.yaml | 9 + .../in/ihcda/eap/student_age_limit.yaml | 9 + .../in/ihcda/eap/vulnerability_points.yaml | 9 + .../in/ihcda/eap/young_child_age_limit.yaml | 9 + policyengine_us/programs.yaml | 9 +- .../gov/states/in/ihcda/eap/in_eap.yaml | 165 ++++++++++++++++++ .../states/in/ihcda/eap/in_eap_eligible.yaml | 56 ++++++ .../states/in/ihcda/eap/in_eap_income.yaml | 77 ++++++++ .../gov/states/in/ihcda/eap/integration.yaml | 88 ++++++++++ .../gov/states/in/ihcda/eap/in_eap.py | 91 ++++++++++ .../states/in/ihcda/eap/in_eap_eligible.py | 24 +++ .../in/ihcda/eap/in_eap_household_size.py | 20 +++ .../gov/states/in/ihcda/eap/in_eap_income.py | 48 +++++ .../gov/states/in/ihcda/eap/in_eap_smi.py | 20 +++ 30 files changed, 806 insertions(+), 1 deletion(-) create mode 100644 changelog.d/in-eap.added.md create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/adult_age.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/amount_per_point.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/elderly_age.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/fuel_points.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_electric_payment.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_points.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/income_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/income_sources.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_electric_payment.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_points.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_electric_payment.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_points.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/minimum_monthly_rent.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/single_family_points.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/student_age_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/vulnerability_points.yaml create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/young_child_age_limit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml create mode 100644 policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py create mode 100644 policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py create mode 100644 policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py create mode 100644 policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py create mode 100644 policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py diff --git a/changelog.d/in-eap.added.md b/changelog.d/in-eap.added.md new file mode 100644 index 00000000000..d0696f2ee72 --- /dev/null +++ b/changelog.d/in-eap.added.md @@ -0,0 +1 @@ +Added partial Indiana EAP regular heating assistance using existing inputs, with unsupported dwelling and income details documented. diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/adult_age.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/adult_age.yaml new file mode 100644 index 00000000000..3ef246b1141 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/adult_age.yaml @@ -0,0 +1,9 @@ +description: Indiana counts income beginning at this age, subject to student and Social Security exceptions under the Energy Assistance Program. +values: + 2025-10-01: 18 +metadata: + unit: year + label: Indiana EAP adult age + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,57,58 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/amount_per_point.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/amount_per_point.yaml new file mode 100644 index 00000000000..5c14a1774e3 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/amount_per_point.yaml @@ -0,0 +1,9 @@ +description: Indiana pays this regular heating amount per matrix point under the Energy Assistance Program. +values: + 2025-10-01: 25 +metadata: + unit: currency-USD + label: Indiana EAP amount per point + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=77 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/elderly_age.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/elderly_age.yaml new file mode 100644 index 00000000000..178323bfb00 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/elderly_age.yaml @@ -0,0 +1,9 @@ +description: Indiana awards vulnerability points beginning at this age under the Energy Assistance Program. +values: + 2025-10-01: 60 +metadata: + unit: year + label: Indiana EAP elderly age + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26,27,71,72 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/fuel_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/fuel_points.yaml new file mode 100644 index 00000000000..f6fa948ec31 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/fuel_points.yaml @@ -0,0 +1,31 @@ +description: Indiana awards these regular heating points by primary fuel under the Energy Assistance Program. +UNSPECIFIED: + 2025-10-01: 0 +ELECTRICITY: + 2025-10-01: 1 +NATURAL_GAS: + 2025-10-01: 1 +FUEL_OIL: + 2025-10-01: 6 +KEROSENE: + 2025-10-01: 6 +PROPANE: + 2025-10-01: 6 +WOOD: + 2025-10-01: 6 +COAL: + 2025-10-01: 6 +SOLAR: + 2025-10-01: 0 +OTHER: + 2025-10-01: 0 +NONE: + 2025-10-01: 0 +metadata: + unit: /1 + breakdown: + - heating_type + label: Indiana EAP heating fuel points + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.5 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=71 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_electric_payment.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_electric_payment.yaml new file mode 100644 index 00000000000..375f8e09655 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_electric_payment.yaml @@ -0,0 +1,9 @@ +description: Indiana pays this regular electric supplement in the highest income band or when electricity is included in rent under the Energy Assistance Program. +values: + 2025-10-01: 50 +metadata: + unit: currency-USD + label: Indiana EAP higher income electric payment + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72,73 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_points.yaml new file mode 100644 index 00000000000..d2ffb8a1263 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_points.yaml @@ -0,0 +1,9 @@ +description: Indiana awards these income points in the highest income band or when heat is included in rent under the Energy Assistance Program. +values: + 2025-10-01: 2 +metadata: + unit: /1 + label: Indiana EAP higher income points + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income_limit.yaml new file mode 100644 index 00000000000..63d4193a064 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income_limit.yaml @@ -0,0 +1,9 @@ +description: Indiana limits countable income to this share of state median income under the Energy Assistance Program. +values: + 2025-10-01: 0.6 +metadata: + unit: /1 + label: Indiana EAP income limit + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23,69,70 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income_sources.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income_sources.yaml new file mode 100644 index 00000000000..78ed48c5557 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income_sources.yaml @@ -0,0 +1,24 @@ +description: Indiana counts these available income sources for adults who are not exempt students under the Energy Assistance Program; Social Security and SSI are handled separately because benefits paid for children also count. +values: + 2025-10-01: + - employment_income + - self_employment_income + - unemployment_compensation + - pension_income + - retirement_distributions + - railroad_benefits + - alimony_income + - veterans_benefits + - workers_compensation + - disability_benefits + - financial_assistance + - dividend_income + - interest_income + - rental_income + - gambling_winnings +metadata: + unit: list + label: Indiana EAP adult income sources + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 6.1 and 6.2 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,48,49,50,51,52,53,54,55,56,57,58,59,60,61 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_electric_payment.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_electric_payment.yaml new file mode 100644 index 00000000000..e4617d32351 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_electric_payment.yaml @@ -0,0 +1,9 @@ +description: Indiana pays this regular electric supplement in the lowest income band under the Energy Assistance Program. +values: + 2025-10-01: 125 +metadata: + unit: currency-USD + label: Indiana EAP lower income electric payment + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72,73 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_points.yaml new file mode 100644 index 00000000000..7e4a234b275 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_points.yaml @@ -0,0 +1,9 @@ +description: Indiana awards these income points in the lowest income band under the Energy Assistance Program. +values: + 2025-10-01: 9 +metadata: + unit: /1 + label: Indiana EAP lower income points + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_rate.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_rate.yaml new file mode 100644 index 00000000000..c9dd4772bfd --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_rate.yaml @@ -0,0 +1,9 @@ +description: Indiana sets the upper limit of the lowest income band at this share of state median income under the Energy Assistance Program. +values: + 2025-10-01: 0.3 +metadata: + unit: /1 + label: Indiana EAP lower income rate + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_electric_payment.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_electric_payment.yaml new file mode 100644 index 00000000000..055659b5b9d --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_electric_payment.yaml @@ -0,0 +1,9 @@ +description: Indiana pays this regular electric supplement in the middle income band under the Energy Assistance Program. +values: + 2025-10-01: 100 +metadata: + unit: currency-USD + label: Indiana EAP middle income electric payment + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72,73 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_points.yaml new file mode 100644 index 00000000000..efca228a427 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_points.yaml @@ -0,0 +1,9 @@ +description: Indiana awards these income points in the middle income band under the Energy Assistance Program. +values: + 2025-10-01: 5 +metadata: + unit: /1 + label: Indiana EAP middle income points + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_rate.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_rate.yaml new file mode 100644 index 00000000000..f5cff533a18 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_rate.yaml @@ -0,0 +1,9 @@ +description: Indiana sets the upper limit of the middle income band at this share of state median income under the Energy Assistance Program. +values: + 2025-10-01: 0.45 +metadata: + unit: /1 + label: Indiana EAP middle income rate + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/minimum_monthly_rent.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/minimum_monthly_rent.yaml new file mode 100644 index 00000000000..172de95f516 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/minimum_monthly_rent.yaml @@ -0,0 +1,9 @@ +description: Indiana requires at least this monthly out-of-pocket rent when utilities are included under the Energy Assistance Program. +values: + 2025-10-01: 1 +metadata: + unit: currency-USD + label: Indiana EAP minimum monthly rent + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=32 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/single_family_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/single_family_points.yaml new file mode 100644 index 00000000000..926b9f54e58 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/single_family_points.yaml @@ -0,0 +1,9 @@ +description: Indiana awards these dwelling points to a site-built single-family home under the Energy Assistance Program. +values: + 2025-10-01: 3 +metadata: + unit: /1 + label: Indiana EAP single family points + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70,71 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/student_age_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/student_age_limit.yaml new file mode 100644 index 00000000000..0c299780e20 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/student_age_limit.yaml @@ -0,0 +1,9 @@ +description: Indiana excludes dependent full-time college student income through this age under the Energy Assistance Program. +values: + 2025-10-01: 23 +metadata: + unit: year + label: Indiana EAP student age limit + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=58 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/vulnerability_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/vulnerability_points.yaml new file mode 100644 index 00000000000..29597462130 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/vulnerability_points.yaml @@ -0,0 +1,9 @@ +description: Indiana awards these additional points once per household with a vulnerable member under the Energy Assistance Program. +values: + 2025-10-01: 2 +metadata: + unit: /1 + label: Indiana EAP vulnerability points + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=71,72 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/young_child_age_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/young_child_age_limit.yaml new file mode 100644 index 00000000000..37970e8d37b --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/young_child_age_limit.yaml @@ -0,0 +1,9 @@ +description: Indiana awards vulnerability points for children through this age under the Energy Assistance Program. +values: + 2025-10-01: 5 +metadata: + unit: year + label: Indiana EAP young child age limit + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26,71,72 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 81c10bc47b6..05f409a0d25 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, TX + coverage: OR, DC, Riverside County, MA, IL, TX, IN state_implementations: - state: OR status: in_progress @@ -823,6 +823,13 @@ programs: name: Illinois LIHEAP full_name: Illinois Low Income Home Energy Assistance Program variable: il_liheap + - state: IN + status: partial + name: Indiana EAP + full_name: Indiana Energy Assistance Program + variable: in_eap + parameter_prefix: gov.states.in.ihcda.eap + notes: FY2026 regular heating and ordinary winter electric allowance only. Uses existing inputs and the site-built single-family schedule. Other dwelling types, gross business income, detailed household/income classifications, electricity-only inclusion in rent, account credits and administrative checks remain incomplete. - state: TX status: partial name: Texas CEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml new file mode 100644 index 00000000000..f58f0b01a3f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml @@ -0,0 +1,165 @@ +- name: Published quarterly band 1 ceilings, at the boundary + period: 2_026 + input: + state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + social_security: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false, false, false, false, false] + rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + in_eap_eligible: [true, true, true, true, true, true, true, true, true, true] + in_eap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + in_eap_income: [16_776, 21_940, 27_100, 32_264, 37_428, 42_588, 43_556, 44_524, 45_492, 46_460] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + output: + in_eap: [450, 450, 450, 450, 450, 450, 450, 450, 450, 450] +- name: Published quarterly band 1 ceilings, one dollar above + period: 2_026 + input: + state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + social_security: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false, false, false, false, false] + rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + in_eap_eligible: [true, true, true, true, true, true, true, true, true, true] + in_eap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + in_eap_income: [16_780, 21_944, 27_104, 32_268, 37_432, 42_592, 43_560, 44_528, 45_496, 46_464] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + output: + in_eap: [325, 325, 325, 325, 325, 325, 325, 325, 325, 325] +- name: Published quarterly band 2 ceilings, at the boundary + period: 2_026 + input: + state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + social_security: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false, false, false, false, false] + rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + in_eap_eligible: [true, true, true, true, true, true, true, true, true, true] + in_eap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + in_eap_income: [25_164, 32_908, 40_652, 48_396, 56_140, 63_884, 65_336, 66_788, 68_240, 69_692] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + output: + in_eap: [325, 325, 325, 325, 325, 325, 325, 325, 325, 325] +- name: Published quarterly band 2 ceilings, one dollar above + period: 2_026 + input: + state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + social_security: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false, false, false, false, false] + rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + in_eap_eligible: [true, true, true, true, true, true, true, true, true, true] + in_eap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + in_eap_income: [25_168, 32_912, 40_656, 48_400, 56_144, 63_888, 65_340, 66_792, 68_244, 69_696] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + output: + in_eap: [200, 200, 200, 200, 200, 200, 200, 200, 200, 200] +- name: Regular heating fuel points and excluded unspecified fuels + period: 2_026 + input: + state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + social_security: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false, false, false, false, false, false] + rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + in_eap_eligible: [true, true, true, true, true, true, true, true, true, true, true] + in_eap_income: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + heating_type: [ELECTRICITY, NATURAL_GAS, PROPANE, FUEL_OIL, KEROSENE, COAL, WOOD, OTHER, SOLAR, UNSPECIFIED, + NONE] + heating_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + output: + in_eap: [450, 450, 575, 575, 575, 575, 575, 125, 125, 125, 125] +- name: Vulnerability points are awarded once across age, disability, military and pregnancy categories + period: 2_026 + input: + state_code: [IN, IN, IN, IN, IN, IN, IN, IN] + age: [59, 60, 40, 40, 40, 40, 40, 60] + ssi: [0, 0, 0, 0, 0, 1, 0, 1] + social_security: [0, 0, 0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false, true, true] + rent: [0, 0, 0, 0, 0, 0, 0, 0] + in_eap_eligible: [true, true, true, true, true, true, true, true] + in_eap_income: [0, 0, 0, 0, 0, 0, 0, 0] + heating_type: [PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE] + heating_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + is_veteran: [false, false, true, false, false, false, false, true] + is_military: [false, false, false, true, false, false, false, true] + current_pregnancies: [0, 0, 0, 0, 1, 0, 0, 0] + is_disabled: [false, false, false, false, false, false, true, true] + output: + in_eap: [575, 625, 625, 625, 625, 625, 625, 625] +- name: Utilities included in rent require one dollar monthly out-of-pocket rent + period: 2_026 + input: + state_code: [IN, IN, IN] + age: [40, 40, 40] + ssi: [0, 0, 0] + social_security: [0, 0, 0] + receives_ssi: [false, false, false] + receives_medicaid: [false, false, false] + rent: [0, 11, 12] + in_eap_eligible: [true, true, true] + in_eap_income: [0, 0, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + heat_expense_included_in_rent: [true, true, true] + tenant_pays_utilities: [false, false, false] + output: + in_eap: [0, 0, 100] +- name: Heat in rent with separately billed electricity preserves the income-based electric supplement + period: 2_026 + input: + state_code: [IN, IN, IN] + age: [40, 40, 40] + ssi: [0, 0, 0] + social_security: [0, 0, 0] + receives_ssi: [false, false, false] + receives_medicaid: [false, false, false] + rent: [1_200, 1_200, 1_200] + in_eap_eligible: [true, true, true] + in_eap_income: [0, 20_000, 30_000] + heat_expense_included_in_rent: [true, true, true] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000] + output: + in_eap: [175, 150, 100] +- name: Regular benefits are not capped at current bills, and absent electric service receives no supplement + period: 2_026 + input: + state_code: [IN, IN] + age: [40, 40] + ssi: [0, 0] + social_security: [0, 0] + receives_ssi: [false, false] + receives_medicaid: [false, false] + rent: [0, 0] + in_eap_eligible: [true, true] + in_eap_income: [0, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [10, 10] + pre_subsidy_electricity_expense: [0, 1] + output: + in_eap: [325, 450] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml new file mode 100644 index 00000000000..ca110e548c7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml @@ -0,0 +1,56 @@ +- name: Published annual sixty percent SMI limits, at the boundary + period: 2_026 + input: + state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + social_security: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false, false, false, false, false] + rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + in_eap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + in_eap_income: [33_556, 43_882, 54_207, 64_533, 74_857, 85_183, 87_119, 89_055, 90_991, 92_927] + output: + in_eap_eligible: [true, true, true, true, true, true, true, true, true, true] +- name: Published annual sixty percent SMI limits, one dollar above + period: 2_026 + input: + state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + social_security: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false, false, false, false, false] + rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + in_eap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + in_eap_income: [33_557, 43_883, 54_208, 64_534, 74_858, 85_184, 87_120, 89_056, 90_992, 92_928] + output: + in_eap_eligible: [false, false, false, false, false, false, false, false, false, false] +- name: Federal household adjustment extends to households larger than the printed chart + period: 2_026 + input: + state_code: [IN, IN] + age: [40, 40] + ssi: [0, 0] + social_security: [0, 0] + receives_ssi: [false, false] + receives_medicaid: [false, false] + rent: [0, 0] + in_eap_household_size: [11, 11] + in_eap_income: [94_863, 94_864] + output: + in_eap_eligible: [true, false] +- name: Household eligibility requires an adult and an eligible member, independently of a utility bill + period: 2_026 + input: + state_code: [IN, IN, IN] + age: [17, 18, 18] + ssi: [0, 0, 0] + social_security: [0, 0, 0] + receives_ssi: [false, false, false] + receives_medicaid: [false, false, false] + rent: [0, 0, 0] + immigration_status: [CITIZEN, CITIZEN, UNDOCUMENTED] + in_eap_income: [0, 0, 0] + output: + in_eap_eligible: [false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml new file mode 100644 index 00000000000..26df5d54fdb --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml @@ -0,0 +1,77 @@ +- name: Existing net business income remains an approximation without a new business deduction + period: 2_026 + input: + state_code: IN + age: 40 + ssi: 0 + social_security: 0 + receives_ssi: false + receives_medicaid: false + rent: 0 + employment_income: 12_000 + self_employment_income: 6_000 + output: + in_eap_income: 18_000 +- name: Adult dependent secondary and college student exemptions do not extend past age twenty-three for college + period: 2_026 + input: + state_code: [IN, IN, IN, IN] + age: [18, 23, 24, 23] + ssi: [0, 0, 0, 0] + social_security: [0, 0, 0, 0] + receives_ssi: [false, false, false, false] + receives_medicaid: [false, false, false, false] + rent: [0, 0, 0, 0] + is_tax_unit_dependent: [true, true, true, false] + is_in_secondary_school: [true, false, false, false] + is_full_time_college_student: [false, true, true, true] + employment_income: [12_000, 12_000, 12_000, 12_000] + interest_income: [1_000, 1_000, 1_000, 1_000] + output: + in_eap_income: [0, 0, 13_000, 13_000] +- name: Reported Medicare premium and support paid reduce income, while TANF, support received and capital gains + are excluded + period: 2_026 + input: + state_code: IN + age: 40 + ssi: 1_200 + social_security: 12_000 + receives_ssi: false + receives_medicaid: false + rent: 0 + employment_income: 12_000 + medicare_part_b_premiums_reported: 2_400 + child_support_expense: 2_400 + child_support_received: 4_000 + tanf: 4_000 + long_term_capital_gains: 4_000 + output: + in_eap_income: 20_400 +- name: Immigration excludes an adult from size but counts earnings, and child SSA counts despite excluded child + wages + period: 2_026 + input: + people: + adult: + age: 35 + immigration_status: UNDOCUMENTED + employment_income: 12_000 + ssi: 0 + social_security: 0 + child: + age: 10 + employment_income: 6_000 + social_security: 2_400 + ssi: 1_200 + spm_units: + unit: + members: [adult, child] + households: + home: + members: [adult, child] + state_code: IN + output: + in_eap_household_size: 1 + in_eap_income: 15_600 + in_eap_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml new file mode 100644 index 00000000000..11da4442930 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml @@ -0,0 +1,88 @@ +- name: Pregnancy increases household size and supplies a single vulnerability bonus + period: 2_026 + input: + state_code: IN + age: 40 + ssi: 0 + social_security: 0 + receives_ssi: false + receives_medicaid: false + rent: 0 + current_pregnancies: 1 + employment_income: 0 + heating_type: PROPANE + bottled_gas_expense: 1_000 + pre_subsidy_electricity_expense: 1_000 + output: + in_eap_household_size: 2 + in_eap: 625 +- name: Young-child vulnerability stops after age five + period: 2_026 + input: + people: + adult1: + age: 40 + ssi: 0 + social_security: 0 + child1: + age: 5 + ssi: 0 + social_security: 0 + adult2: + age: 40 + ssi: 0 + social_security: 0 + child2: + age: 6 + ssi: 0 + social_security: 0 + spm_units: + unit1: + members: [adult1, child1] + heating_type: PROPANE + bottled_gas_expense: 1_000 + pre_subsidy_electricity_expense: 1_000 + unit2: + members: [adult2, child2] + heating_type: PROPANE + bottled_gas_expense: 1_000 + pre_subsidy_electricity_expense: 1_000 + households: + home1: + members: [adult1, child1] + state_code: IN + home2: + members: [adult2, child2] + state_code: IN + output: + in_eap: [625, 575] +- name: Mixed-state and over-income households receive zero + period: 2_026 + input: + state_code: [IN, IN, IL] + age: [40, 40, 40] + ssi: [0, 0, 0] + social_security: [0, 0, 0] + receives_ssi: [false, false, false] + receives_medicaid: [false, false, false] + rent: [0, 0, 0] + employment_income: [0, 33_557, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000] + output: + in_eap: [450, 0, 0] +- name: Unresearched earlier years have no formula + period: 2_022 + input: + state_code: IN + age: 40 + ssi: 0 + social_security: 0 + receives_ssi: false + receives_medicaid: false + rent: 0 + heating_type: NATURAL_GAS + gas_expense: 1_000 + output: + in_eap: 0 diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py new file mode 100644 index 00000000000..8c132c5f399 --- /dev/null +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py @@ -0,0 +1,91 @@ +from policyengine_us.model_api import * + + +class in_eap(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Indiana EAP regular heating assistance" + defined_for = "in_eap_eligible" + reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26,27,32,33,69,70,71,72,73,74,75,77,78" + + def formula_2026(spm_unit, period, parameters): + # FY2026 is the beginning of researched coverage, not the program's inception. + p = parameters(period).gov.states["in"].ihcda.eap + person = spm_unit.members + smi_amount = spm_unit("in_eap_smi", period) + quarterly_income = spm_unit("in_eap_income", period) / 4 + low = quarterly_income <= np.floor(smi_amount * p.lower_income_rate / 4) + middle = quarterly_income <= np.floor(smi_amount * p.middle_income_rate / 4) + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + # The shared tenant flag identifies all utilities included in rent. It does not + # identify electricity alone included in rent while other utilities are separate; + # that mixed arrangement remains unsupported without an electricity-specific input. + electric_in_rent = ~spm_unit.household("tenant_pays_utilities", period) + rent_paid = add(spm_unit, period, ["rent"]) >= p.minimum_monthly_rent * 12 + fuel = spm_unit("heating_type", period) + fuel_points = p.fuel_points[fuel] + heating_bill = spm_unit("heating_expense", period) > 0 + heating_burden = where( + heat_in_rent, rent_paid, heating_bill & (fuel_points > 0) + ) + income_points = select( + [heat_in_rent, low, middle], + [p.higher_income_points, p.lower_income_points, p.middle_income_points], + default=p.higher_income_points, + ) + # No existing input identifies site-built, mobile, and multi-unit dwellings. + # This draft uses the site-built single-family schedule, overestimating mobile + # homes by $25 and multi-unit homes by $50 when heat is billed separately. + # Heat included in rent receives zero dwelling and fuel points for every type. + dwelling_points = where(heat_in_rent, 0, p.single_family_points) + fuel_points = where(heat_in_rent, 0, fuel_points) + age = person("age", period) + # Reuse available benefit-receipt evidence. Doctor certification with a pending + # SSA claim, vocational rehabilitation and black-lung receipt lack exact inputs. + # Disability with Medicaid receipt approximates the specified Medicaid pathways. + disability = ( + (person("ssi", period) > 0) + | person("receives_ssi", period) + | (person("social_security_disability", period) > 0) + | (person("is_disabled", period) & person("receives_medicaid", period)) + ) + vulnerable = spm_unit.any( + (age >= p.elderly_age) + | (age <= p.young_child_age_limit) + | disability + | person("is_veteran", period) + | person("is_military", period) + | (person("current_pregnancies", period) > 0) + ) + points = ( + income_points + + dwelling_points + + fuel_points + + vulnerable * p.vulnerability_points + ) + heating = points * p.amount_per_point * heating_burden + # Section 8.7 expressly treats this winter electric allowance as supporting the + # heating system. Section 8.11 denies it when there is no electric utility service. + electric_bill = (spm_unit("pre_subsidy_electricity_expense", period) > 0) | ( + (fuel == fuel.possible_values.ELECTRICITY) & heating_bill + ) + electric_burden = where(electric_in_rent, rent_paid, electric_bill) + electric = ( + select( + [electric_in_rent, low, middle], + [ + p.higher_income_electric_payment, + p.lower_income_electric_payment, + p.middle_income_electric_payment, + ], + default=p.higher_income_electric_payment, + ) + * electric_burden + ) + # Regular awards can create credits and are not capped at the current bill. + # Existing credit balances, account coding/ownership, unsafe or broken equipment, + # prior awards and discretionary supplements are not identified by current inputs. + # Excludes all crisis, cooling, weatherization and equipment payments. + return heating + electric diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py new file mode 100644 index 00000000000..b6d96c45c5c --- /dev/null +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class in_eap_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Indiana EAP household eligibility" + defined_for = StateCode.IN + reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23,29,69,70,73,74,75" + + def formula_2026(spm_unit, period, parameters): + p = parameters(period).gov.states["in"].ihcda.eap + income = spm_unit("in_eap_income", period) + limit = np.floor(spm_unit("in_eap_smi", period) * p.income_limit) + # Section 4.4 permits an ineligible adult to apply for eligible household members. + # Emancipated minors, residency duration, eviction writs, SSNs, and sanctions + # cannot be determined here. Section 8.8 separates household eligibility from + # whether each utility can receive a benefit; burden is checked in in_eap. + return ( + spm_unit.any(spm_unit.members("is_citizen_or_legal_immigrant", period)) + & spm_unit.any(spm_unit.members("age", period) >= p.adult_age) + & (income <= limit) + ) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py new file mode 100644 index 00000000000..494922a1165 --- /dev/null +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class in_eap_household_size(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "Indiana EAP eligible household size" + defined_for = StateCode.IN + reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23,24,25,29,30" + + def formula_2026(spm_unit, period, parameters): + # SPM units approximate the residence-based unit. Current inputs cannot identify + # all excluded foster children, exchange students, transient guests, or changes + # in residence during the three-month budget period. Citizenship is approximated + # by the existing qualified-status flag; SSN/document verification is not modeled. + # Reported pregnancies count under Section 3.2. + return add( + spm_unit, period, ["is_citizen_or_legal_immigrant", "current_pregnancies"] + ) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py new file mode 100644 index 00000000000..cd7b82fc3e2 --- /dev/null +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py @@ -0,0 +1,48 @@ +from policyengine_us.model_api import * + + +class in_eap_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Indiana EAP annual countable income" + defined_for = StateCode.IN + reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,48,49,50,51,52,53,54,55,56,57,58,59,60,61" + + def formula_2026(spm_unit, period, parameters): + p = parameters(period).gov.states["in"].ihcda.eap + person = spm_unit.members + age = person("age", period) + dependent = person("is_tax_unit_dependent", period) + student = ( + person("is_in_secondary_school", period) + | person("is_in_k12_school", period) + | ( + person("is_full_time_college_student", period) + & (age <= p.student_age_limit) + ) + ) + counted = (age >= p.adult_age) & ~(dependent & student) + # Use annual inputs as an approximation to the annualized preceding three months. + # Section 6.1 prefers paystub federal taxable gross when supplied; current wages + # do not identify that paystub field. Existing self_employment_income is net, + # whereas the manual asks for Schedule C gross profit (line 5) and Schedule F + # gross income. Keep the existing net-income approximation: no new gross inputs + # or separate business/work-expense adjustments are introduced in this project. + other = max_(add(person, period, p.income_sources), 0) * counted + # Child SSA benefits count despite the general under-18 exclusion. Only reported + # Part B premiums are available to approximate the required net SSA payment; + # Part D, withholding, overpayment recovery, and exact garnishment are unavailable. + ssa = max_( + person("social_security", period) + - person("medicare_part_b_premiums_reported", period), + 0, + ) + ssa = ssa + person("ssi", period) + # Actual support paid is deductible. Child support received, TANF, capital gains, + # tax refunds, and educational assistance are excluded. Recurring versus lump-sum + # receipts, royalties, protected employment, and specific VA/insurance exclusions + # cannot all be distinguished from existing inputs. + support = max_(person("child_support_expense", period), 0) + return max_(spm_unit.sum(other + ssa - support), 0) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py new file mode 100644 index 00000000000..13061bae26f --- /dev/null +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class in_eap_smi(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Indiana EAP household-adjusted state median income" + defined_for = StateCode.IN + reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70,72,73" + + def formula_2026(spm_unit, period, parameters): + size = spm_unit("in_eap_household_size", period) + state = spm_unit.household("state_code_str", period) + # Truncate household-adjusted 100% SMI before applying each income-band rate. + # This numerical pattern reproduces all 90 published monthly, quarterly and + # annual table values; the manual does not state an explicit rounding rule. + return where(size > 0, np.floor(smi(size, state, period, parameters)), 0) From 94da19288931d3eeb3eaeb3d6424dcf0dfef0b1b Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 30 Sep 2026 19:59:25 -0400 Subject: [PATCH 2/9] Apply LIHEAP review fixes and shared guideline convention --- changelog.d/in-eap.added.md | 2 +- .../states/in/ihcda/eap/dwelling_points.yaml | 16 +++++++ .../in/ihcda/eap/single_family_points.yaml | 9 ---- policyengine_us/programs.yaml | 3 +- .../gov/states/in/ihcda/eap/in_eap.yaml | 45 +++++++++++++++++++ .../gov/states/in/ihcda/eap/integration.yaml | 10 ++++- .../gov/states/in/ihcda/eap/in_eap.py | 15 ++++--- .../in/ihcda/eap/in_eap_dwelling_type.py | 23 ++++++++++ .../states/in/ihcda/eap/in_eap_eligible.py | 2 +- .../in/ihcda/eap/in_eap_household_size.py | 2 +- .../gov/states/in/ihcda/eap/in_eap_income.py | 2 +- .../gov/states/in/ihcda/eap/in_eap_smi.py | 4 +- 12 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/dwelling_points.yaml delete mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/single_family_points.yaml create mode 100644 policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_dwelling_type.py diff --git a/changelog.d/in-eap.added.md b/changelog.d/in-eap.added.md index d0696f2ee72..9b8c50148c8 100644 --- a/changelog.d/in-eap.added.md +++ b/changelog.d/in-eap.added.md @@ -1 +1 @@ -Added partial Indiana EAP regular heating assistance using existing inputs, with unsupported dwelling and income details documented. +Added partial Indiana EAP regular heating assistance with state-specific dwelling types for single-family homes, mobile homes, and multi-unit dwellings, with remaining income and administrative gaps documented. diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/dwelling_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/dwelling_points.yaml new file mode 100644 index 00000000000..fd05826de52 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/dwelling_points.yaml @@ -0,0 +1,16 @@ +description: Indiana awards these regular heating points by dwelling type under the Energy Assistance Program. +SINGLE_FAMILY: + 2025-10-01: 3 +MOBILE_HOME: + 2025-10-01: 2 +MULTI_UNIT: + 2025-10-01: 1 +metadata: + unit: /1 + period: year + breakdown: + - in_eap_dwelling_type + label: Indiana EAP dwelling points + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.4 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70,71 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/single_family_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/single_family_points.yaml deleted file mode 100644 index 926b9f54e58..00000000000 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/single_family_points.yaml +++ /dev/null @@ -1,9 +0,0 @@ -description: Indiana awards these dwelling points to a site-built single-family home under the Energy Assistance Program. -values: - 2025-10-01: 3 -metadata: - unit: /1 - label: Indiana EAP single family points - reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70,71 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 05f409a0d25..63ea087868c 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -829,7 +829,8 @@ programs: full_name: Indiana Energy Assistance Program variable: in_eap parameter_prefix: gov.states.in.ihcda.eap - notes: FY2026 regular heating and ordinary winter electric allowance only. Uses existing inputs and the site-built single-family schedule. Other dwelling types, gross business income, detailed household/income classifications, electricity-only inclusion in rent, account credits and administrative checks remain incomplete. + verified_years: "2026" + notes: FY2026 regular heating and ordinary winter electric allowance only. A state-specific dwelling-type input selects single-family, mobile-home, or multi-unit points, defaulting to single-family when omitted; heat included in rent receives zero dwelling points for every type. Gross business income, detailed household/income classifications, electricity-only inclusion in rent, account credits and administrative checks remain incomplete. Earlier results use parameter backfilling and are unverified historical estimates. - state: TX status: partial name: Texas CEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml index f58f0b01a3f..5cb7f1fc235 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml @@ -163,3 +163,48 @@ pre_subsidy_electricity_expense: [0, 1] output: in_eap: [325, 450] + +- name: Dwelling type applies the published three, two, and one point awards + # Section 8.4: single-family 3, mobile home 2, multi-unit 1; $25 per point. + # Low band: (9 + dwelling + 1 gas) * $25 + $125 electricity. + # High band: (2 + dwelling + 1 gas) * $25 + $50 electricity. + period: 2026 + input: + state_code: [IN, IN, IN, IN, IN, IN] + age: [40, 40, 40, 40, 40, 40] + ssi: [0, 0, 0, 0, 0, 0] + social_security: [0, 0, 0, 0, 0, 0] + receives_ssi: [false, false, false, false, false, false] + receives_medicaid: [false, false, false, false, false, false] + rent: [0, 0, 0, 0, 0, 0] + in_eap_eligible: [true, true, true, true, true, true] + in_eap_household_size: [1, 1, 1, 1, 1, 1] + in_eap_income: [0, 0, 0, 30_000, 30_000, 30_000] + in_eap_dwelling_type: [SINGLE_FAMILY, MOBILE_HOME, MULTI_UNIT, + SINGLE_FAMILY, MOBILE_HOME, MULTI_UNIT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000] + output: + in_eap: [450, 425, 400, 200, 175, 150] + +- name: Dwelling type does not change zero dwelling points when heat is in rent + # Section 8.4: zero dwelling points for every type when heat is in rent. + # Two income points * $25 plus the $50 electricity-in-rent allowance. + period: 2026 + input: + state_code: [IN, IN, IN] + age: [40, 40, 40] + ssi: [0, 0, 0] + social_security: [0, 0, 0] + receives_ssi: [false, false, false] + receives_medicaid: [false, false, false] + rent: [1_200, 1_200, 1_200] + in_eap_eligible: [true, true, true] + in_eap_income: [0, 0, 0] + in_eap_dwelling_type: [SINGLE_FAMILY, MOBILE_HOME, MULTI_UNIT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + heat_expense_included_in_rent: [true, true, true] + tenant_pays_utilities: [false, false, false] + output: + in_eap: [100, 100, 100] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml index 11da4442930..7bcaddd71bf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml @@ -72,7 +72,9 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000] output: in_eap: [450, 0, 0] -- name: Unresearched earlier years have no formula +# Backfilling checks the model convention, not verified historical Indiana policy. +# 2022 uses FY2022 SMI, with the earliest available state benefit schedule. +- name: Parameter backfill uses period-specific SMI for a 2022 estimate period: 2_022 input: state_code: IN @@ -82,7 +84,11 @@ receives_ssi: false receives_medicaid: false rent: 0 + employment_income: 0 heating_type: NATURAL_GAS gas_expense: 1_000 output: - in_eap: 0 + in_eap: 325 + in_eap_household_size: 1 + in_eap_smi: 45_020 + in_eap_eligible: true diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py index 8c132c5f399..b1ac37717e6 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py @@ -7,11 +7,14 @@ class in_eap(Variable): definition_period = YEAR unit = USD label = "Indiana EAP regular heating assistance" + documentation = ( + "Verified for FY2026. Earlier years use model parameter backfilling " + "and are unverified historical estimates." + ) defined_for = "in_eap_eligible" reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26,27,32,33,69,70,71,72,73,74,75,77,78" - def formula_2026(spm_unit, period, parameters): - # FY2026 is the beginning of researched coverage, not the program's inception. + def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].ihcda.eap person = spm_unit.members smi_amount = spm_unit("in_eap_smi", period) @@ -35,11 +38,9 @@ def formula_2026(spm_unit, period, parameters): [p.higher_income_points, p.lower_income_points, p.middle_income_points], default=p.higher_income_points, ) - # No existing input identifies site-built, mobile, and multi-unit dwellings. - # This draft uses the site-built single-family schedule, overestimating mobile - # homes by $25 and multi-unit homes by $50 when heat is billed separately. - # Heat included in rent receives zero dwelling and fuel points for every type. - dwelling_points = where(heat_in_rent, 0, p.single_family_points) + dwelling = spm_unit("in_eap_dwelling_type", period) + # Section 8.4 awards zero dwelling points whenever heat is included in rent. + dwelling_points = where(heat_in_rent, 0, p.dwelling_points[dwelling]) fuel_points = where(heat_in_rent, 0, fuel_points) age = person("age", period) # Reuse available benefit-receipt evidence. Doctor certification with a pending diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_dwelling_type.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_dwelling_type.py new file mode 100644 index 00000000000..adc7fa619f1 --- /dev/null +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_dwelling_type.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class INEAPDwellingType(Enum): + MOBILE_HOME = "Mobile home" + MULTI_UNIT = "Multi-unit dwelling (duplex or larger)" + SINGLE_FAMILY = "Site-built single-family or manufactured home on a foundation" + + +class in_eap_dwelling_type(Variable): + value_type = Enum + entity = SPMUnit + possible_values = INEAPDwellingType + default_value = INEAPDwellingType.SINGLE_FAMILY + definition_period = YEAR + label = "Dwelling type for Indiana EAP" + documentation = ( + "Section 8.4 classifies a manufactured home on a foundation as " + "single-family. Multi-unit includes duplexes and apartments. If omitted, " + "the model assumes single-family; report the type to apply the correct " + "dwelling points. Heat included in rent is reported separately." + ) + reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70,71" diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py index b6d96c45c5c..fa13e2c3536 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py @@ -9,7 +9,7 @@ class in_eap_eligible(Variable): defined_for = StateCode.IN reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23,29,69,70,73,74,75" - def formula_2026(spm_unit, period, parameters): + def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].ihcda.eap income = spm_unit("in_eap_income", period) limit = np.floor(spm_unit("in_eap_smi", period) * p.income_limit) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py index 494922a1165..fd1b6d58036 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py @@ -9,7 +9,7 @@ class in_eap_household_size(Variable): defined_for = StateCode.IN reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23,24,25,29,30" - def formula_2026(spm_unit, period, parameters): + def formula(spm_unit, period, parameters): # SPM units approximate the residence-based unit. Current inputs cannot identify # all excluded foster children, exchange students, transient guests, or changes # in residence during the three-month budget period. Citizenship is approximated diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py index cd7b82fc3e2..5c1bbc964cf 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py @@ -10,7 +10,7 @@ class in_eap_income(Variable): defined_for = StateCode.IN reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,48,49,50,51,52,53,54,55,56,57,58,59,60,61" - def formula_2026(spm_unit, period, parameters): + def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].ihcda.eap person = spm_unit.members age = person("age", period) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py index 13061bae26f..e3a159681b4 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py @@ -11,10 +11,12 @@ class in_eap_smi(Variable): defined_for = StateCode.IN reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70,72,73" - def formula_2026(spm_unit, period, parameters): + def formula(spm_unit, period, parameters): size = spm_unit("in_eap_household_size", period) state = spm_unit.household("state_code_str", period) # Truncate household-adjusted 100% SMI before applying each income-band rate. # This numerical pattern reproduces all 90 published monthly, quarterly and # annual table values; the manual does not state an explicit rounding rule. + # Mississippi's base-first truncation would raise the FY2026 60% limits + # for sizes 1 and 5 by $1. Keep this ordering in state code. return where(size > 0, np.floor(smi(size, state, period, parameters)), 0) From 33e96e5d3e79cc556e0a96ffece9a724bef0dbfc Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 30 Sep 2026 20:50:24 -0400 Subject: [PATCH 3/9] Organize Indiana EAP parameters by policy component --- .../eap/{ => benefit}/amount_per_point.yaml | 0 .../eap/{ => benefit}/dwelling_points.yaml | 0 .../electricity/higher_income.yaml} | 0 .../electricity/lower_income.yaml} | 0 .../electricity/middle_income.yaml} | 0 .../ihcda/eap/{ => benefit}/fuel_points.yaml | 0 .../income/higher_points.yaml} | 0 .../income/lower_points.yaml} | 0 .../income/lower_rate.yaml} | 0 .../income/middle_points.yaml} | 0 .../income/middle_rate.yaml} | 0 .../vulnerability}/elderly_age.yaml | 0 .../vulnerability/points.yaml} | 0 .../vulnerability}/young_child_age_limit.yaml | 0 .../eap/{ => eligibility}/adult_age.yaml | 0 .../eap/{ => eligibility}/income_limit.yaml | 0 .../minimum_monthly_rent.yaml | 0 .../sources.yaml} | 0 .../eap/{ => income}/student_age_limit.yaml | 0 .../gov/states/in/ihcda/eap/in_eap.py | 38 +++++++++++-------- .../states/in/ihcda/eap/in_eap_eligible.py | 4 +- .../gov/states/in/ihcda/eap/in_eap_income.py | 6 +-- 22 files changed, 28 insertions(+), 20 deletions(-) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => benefit}/amount_per_point.yaml (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => benefit}/dwelling_points.yaml (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{higher_income_electric_payment.yaml => benefit/electricity/higher_income.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{lower_income_electric_payment.yaml => benefit/electricity/lower_income.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{middle_income_electric_payment.yaml => benefit/electricity/middle_income.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => benefit}/fuel_points.yaml (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{higher_income_points.yaml => benefit/income/higher_points.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{lower_income_points.yaml => benefit/income/lower_points.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{lower_income_rate.yaml => benefit/income/lower_rate.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{middle_income_points.yaml => benefit/income/middle_points.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{middle_income_rate.yaml => benefit/income/middle_rate.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => benefit/vulnerability}/elderly_age.yaml (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{vulnerability_points.yaml => benefit/vulnerability/points.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => benefit/vulnerability}/young_child_age_limit.yaml (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => eligibility}/adult_age.yaml (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => eligibility}/income_limit.yaml (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => eligibility}/minimum_monthly_rent.yaml (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{income_sources.yaml => income/sources.yaml} (100%) rename policyengine_us/parameters/gov/states/in/ihcda/eap/{ => income}/student_age_limit.yaml (100%) diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/amount_per_point.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/amount_per_point.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/dwelling_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/dwelling_points.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/dwelling_points.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/dwelling_points.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_electric_payment.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_electric_payment.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_electric_payment.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_electric_payment.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_electric_payment.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_electric_payment.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/fuel_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/fuel_points.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/higher_income_points.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_points.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_rate.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/lower_income_rate.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_points.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_rate.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/middle_income_rate.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/elderly_age.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/elderly_age.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/vulnerability_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/vulnerability_points.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/young_child_age_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/young_child_age_limit.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/adult_age.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/adult_age.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/income_limit.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/minimum_monthly_rent.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/minimum_monthly_rent.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income_sources.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/income_sources.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/student_age_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/in/ihcda/eap/student_age_limit.yaml rename to policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py index b1ac37717e6..aba798c0660 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py @@ -19,28 +19,36 @@ def formula(spm_unit, period, parameters): person = spm_unit.members smi_amount = spm_unit("in_eap_smi", period) quarterly_income = spm_unit("in_eap_income", period) / 4 - low = quarterly_income <= np.floor(smi_amount * p.lower_income_rate / 4) - middle = quarterly_income <= np.floor(smi_amount * p.middle_income_rate / 4) + low = quarterly_income <= np.floor(smi_amount * p.benefit.income.lower_rate / 4) + middle = quarterly_income <= np.floor( + smi_amount * p.benefit.income.middle_rate / 4 + ) heat_in_rent = spm_unit("heat_expense_included_in_rent", period) # The shared tenant flag identifies all utilities included in rent. It does not # identify electricity alone included in rent while other utilities are separate; # that mixed arrangement remains unsupported without an electricity-specific input. electric_in_rent = ~spm_unit.household("tenant_pays_utilities", period) - rent_paid = add(spm_unit, period, ["rent"]) >= p.minimum_monthly_rent * 12 + rent_paid = ( + add(spm_unit, period, ["rent"]) >= p.eligibility.minimum_monthly_rent * 12 + ) fuel = spm_unit("heating_type", period) - fuel_points = p.fuel_points[fuel] + fuel_points = p.benefit.fuel_points[fuel] heating_bill = spm_unit("heating_expense", period) > 0 heating_burden = where( heat_in_rent, rent_paid, heating_bill & (fuel_points > 0) ) income_points = select( [heat_in_rent, low, middle], - [p.higher_income_points, p.lower_income_points, p.middle_income_points], - default=p.higher_income_points, + [ + p.benefit.income.higher_points, + p.benefit.income.lower_points, + p.benefit.income.middle_points, + ], + default=p.benefit.income.higher_points, ) dwelling = spm_unit("in_eap_dwelling_type", period) # Section 8.4 awards zero dwelling points whenever heat is included in rent. - dwelling_points = where(heat_in_rent, 0, p.dwelling_points[dwelling]) + dwelling_points = where(heat_in_rent, 0, p.benefit.dwelling_points[dwelling]) fuel_points = where(heat_in_rent, 0, fuel_points) age = person("age", period) # Reuse available benefit-receipt evidence. Doctor certification with a pending @@ -53,8 +61,8 @@ def formula(spm_unit, period, parameters): | (person("is_disabled", period) & person("receives_medicaid", period)) ) vulnerable = spm_unit.any( - (age >= p.elderly_age) - | (age <= p.young_child_age_limit) + (age >= p.benefit.vulnerability.elderly_age) + | (age <= p.benefit.vulnerability.young_child_age_limit) | disability | person("is_veteran", period) | person("is_military", period) @@ -64,9 +72,9 @@ def formula(spm_unit, period, parameters): income_points + dwelling_points + fuel_points - + vulnerable * p.vulnerability_points + + vulnerable * p.benefit.vulnerability.points ) - heating = points * p.amount_per_point * heating_burden + heating = points * p.benefit.amount_per_point * heating_burden # Section 8.7 expressly treats this winter electric allowance as supporting the # heating system. Section 8.11 denies it when there is no electric utility service. electric_bill = (spm_unit("pre_subsidy_electricity_expense", period) > 0) | ( @@ -77,11 +85,11 @@ def formula(spm_unit, period, parameters): select( [electric_in_rent, low, middle], [ - p.higher_income_electric_payment, - p.lower_income_electric_payment, - p.middle_income_electric_payment, + p.benefit.electricity.higher_income, + p.benefit.electricity.lower_income, + p.benefit.electricity.middle_income, ], - default=p.higher_income_electric_payment, + default=p.benefit.electricity.higher_income, ) * electric_burden ) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py index fa13e2c3536..4a25639f48d 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py @@ -12,13 +12,13 @@ class in_eap_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].ihcda.eap income = spm_unit("in_eap_income", period) - limit = np.floor(spm_unit("in_eap_smi", period) * p.income_limit) + limit = np.floor(spm_unit("in_eap_smi", period) * p.eligibility.income_limit) # Section 4.4 permits an ineligible adult to apply for eligible household members. # Emancipated minors, residency duration, eviction writs, SSNs, and sanctions # cannot be determined here. Section 8.8 separates household eligibility from # whether each utility can receive a benefit; burden is checked in in_eap. return ( spm_unit.any(spm_unit.members("is_citizen_or_legal_immigrant", period)) - & spm_unit.any(spm_unit.members("age", period) >= p.adult_age) + & spm_unit.any(spm_unit.members("age", period) >= p.eligibility.adult_age) & (income <= limit) ) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py index 5c1bbc964cf..8d1debff9e2 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py @@ -20,17 +20,17 @@ def formula(spm_unit, period, parameters): | person("is_in_k12_school", period) | ( person("is_full_time_college_student", period) - & (age <= p.student_age_limit) + & (age <= p.income.student_age_limit) ) ) - counted = (age >= p.adult_age) & ~(dependent & student) + counted = (age >= p.eligibility.adult_age) & ~(dependent & student) # Use annual inputs as an approximation to the annualized preceding three months. # Section 6.1 prefers paystub federal taxable gross when supplied; current wages # do not identify that paystub field. Existing self_employment_income is net, # whereas the manual asks for Schedule C gross profit (line 5) and Schedule F # gross income. Keep the existing net-income approximation: no new gross inputs # or separate business/work-expense adjustments are introduced in this project. - other = max_(add(person, period, p.income_sources), 0) * counted + other = max_(add(person, period, p.income.sources), 0) * counted # Child SSA benefits count despite the general under-18 exclusion. Only reported # Part B premiums are available to approximate the required net SSA payment; # Part D, withholding, overpayment recovery, and exact garnishment are unavailable. From 0fe642ec7701193357617b8a0bd9f87abac54537 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 30 Sep 2026 23:05:57 -0400 Subject: [PATCH 4/9] Fix issues from review: Indiana EAP income sources, fuel points and utilities in rent - Count farm, partnership and S corporation, estate, farm rental, strike and military retirement income (manual section 6.1) - Give kerosene no bulk-fuel points (manual sections 1.1 and 8.5) and give other fuels the bulk-fuel points - Treat all utilities in rent as heat in rent as well as electricity in rent - Floor each income source at zero per person - Replace hardcoded month and quarter literals; add income/calculation_months - Add metadata.period to parameters - Add tests for the new sources, fuel points, the single tenant flag, per-source floors and raw-input integration households; send heating_type explicitly in every eligibility or payment case Co-Authored-By: Claude Fable 5.1 --- .../ihcda/eap/benefit/amount_per_point.yaml | 1 + .../benefit/electricity/higher_income.yaml | 1 + .../eap/benefit/electricity/lower_income.yaml | 1 + .../benefit/electricity/middle_income.yaml | 1 + .../in/ihcda/eap/benefit/fuel_points.yaml | 14 +- .../eap/benefit/income/higher_points.yaml | 1 + .../eap/benefit/income/lower_points.yaml | 1 + .../ihcda/eap/benefit/income/lower_rate.yaml | 1 + .../eap/benefit/income/middle_points.yaml | 1 + .../ihcda/eap/benefit/income/middle_rate.yaml | 1 + .../benefit/vulnerability/elderly_age.yaml | 1 + .../eap/benefit/vulnerability/points.yaml | 1 + .../vulnerability/young_child_age_limit.yaml | 1 + .../in/ihcda/eap/eligibility/adult_age.yaml | 1 + .../ihcda/eap/eligibility/income_limit.yaml | 1 + .../eap/eligibility/minimum_monthly_rent.yaml | 1 + .../ihcda/eap/income/calculation_months.yaml | 10 + .../states/in/ihcda/eap/income/sources.yaml | 11 ++ .../ihcda/eap/income/student_age_limit.yaml | 1 + policyengine_us/programs.yaml | 2 +- .../gov/states/in/ihcda/eap/in_eap.yaml | 60 +++++- .../states/in/ihcda/eap/in_eap_eligible.yaml | 38 ++++ .../states/in/ihcda/eap/in_eap_income.yaml | 46 +++++ .../gov/states/in/ihcda/eap/integration.yaml | 182 ++++++++++++++++++ .../gov/states/in/ihcda/eap/in_eap.py | 30 ++- .../gov/states/in/ihcda/eap/in_eap_income.py | 16 +- 26 files changed, 403 insertions(+), 22 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/income/calculation_months.yaml diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml index 5c14a1774e3..20fb7809d0c 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 25 metadata: unit: currency-USD + period: year label: Indiana EAP amount per point reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml index 375f8e09655..380aad97e34 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 50 metadata: unit: currency-USD + period: year label: Indiana EAP higher income electric payment reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml index e4617d32351..b2270416f6f 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 125 metadata: unit: currency-USD + period: year label: Indiana EAP lower income electric payment reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml index 055659b5b9d..1cb821b8369 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 100 metadata: unit: currency-USD + period: year label: Indiana EAP middle income electric payment reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml index f6fa948ec31..db1d3080c8f 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml @@ -7,8 +7,10 @@ NATURAL_GAS: 2025-10-01: 1 FUEL_OIL: 2025-10-01: 6 +# Section 1.1 bars EAP funds for kerosene, and Section 8.5 does not list it as a +# bulk fuel, so a kerosene-primary household receives the electric allowance only. KEROSENE: - 2025-10-01: 6 + 2025-10-01: 0 PROPANE: 2025-10-01: 6 WOOD: @@ -17,15 +19,19 @@ COAL: 2025-10-01: 6 SOLAR: 2025-10-01: 0 +# Section 8.5 has no zero-point fuel outside rent. The remaining named fuels (wood +# pellets, corn and biofuels) are bulk fuels that the heating type input cannot +# separate within OTHER, so OTHER receives the bulk-fuel points. OTHER: - 2025-10-01: 0 + 2025-10-01: 6 NONE: 2025-10-01: 0 metadata: unit: /1 + period: year breakdown: - heating_type label: Indiana EAP heating fuel points reference: - - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.5 - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=71 + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 1.1 and 8.5 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=10,71 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml index d2ffb8a1263..7055b51d4df 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 2 metadata: unit: /1 + period: year label: Indiana EAP higher income points reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml index 7e4a234b275..ce0decdc4a8 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 9 metadata: unit: /1 + period: year label: Indiana EAP lower income points reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml index c9dd4772bfd..52a72da1651 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 0.3 metadata: unit: /1 + period: year label: Indiana EAP lower income rate reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml index efca228a427..4b5e2de4ade 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 5 metadata: unit: /1 + period: year label: Indiana EAP middle income points reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml index f5cff533a18..a1d7266c007 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 0.45 metadata: unit: /1 + period: year label: Indiana EAP middle income rate reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml index 178323bfb00..36679b9e5e6 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 60 metadata: unit: year + period: year label: Indiana EAP elderly age reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml index 29597462130..cfe8c449b59 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 2 metadata: unit: /1 + period: year label: Indiana EAP vulnerability points reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml index 37970e8d37b..63d653a787e 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 5 metadata: unit: year + period: year label: Indiana EAP young child age limit reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml index 3ef246b1141..b450cd8c4b0 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 18 metadata: unit: year + period: year label: Indiana EAP adult age reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml index 63d4193a064..ffa089d1622 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 0.6 metadata: unit: /1 + period: year label: Indiana EAP income limit reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml index 172de95f516..fb5c8799552 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 1 metadata: unit: currency-USD + period: month label: Indiana EAP minimum monthly rent reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/calculation_months.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/calculation_months.yaml new file mode 100644 index 00000000000..20ae52a7838 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/calculation_months.yaml @@ -0,0 +1,10 @@ +description: Indiana sets the income calculation period to this number of months under the Energy Assistance Program. +values: + 2025-10-01: 3 +metadata: + unit: month + period: year + label: Indiana EAP income calculation months + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 6 and 8.3 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,69 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml index 78ed48c5557..e99d095cc62 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml @@ -3,8 +3,18 @@ values: 2025-10-01: - employment_income - self_employment_income + # Section 6.1 defines self-employment to include farming (Schedule F) and lists + # the Schedule E partnership and S corporation, estate and trust, and farm + # rental lines. + - farm_operations_income + - partnership_s_corp_income + - estate_income + - farm_rent_income - unemployment_compensation + - strike_benefits - pension_income + # Military retirement pay is a separate input from pension_income. + - military_retirement_pay - retirement_distributions - railroad_benefits - alimony_income @@ -18,6 +28,7 @@ values: - gambling_winnings metadata: unit: list + period: year label: Indiana EAP adult income sources reference: - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 6.1 and 6.2 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml index 0c299780e20..e81d876f2fb 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: 23 metadata: unit: year + period: year label: Indiana EAP student age limit reference: - title: Indiana PY2026 EAP Intake and Operations Manual diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 63ea087868c..a253e0403e3 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -830,7 +830,7 @@ programs: variable: in_eap parameter_prefix: gov.states.in.ihcda.eap verified_years: "2026" - notes: FY2026 regular heating and ordinary winter electric allowance only. A state-specific dwelling-type input selects single-family, mobile-home, or multi-unit points, defaulting to single-family when omitted; heat included in rent receives zero dwelling points for every type. Gross business income, detailed household/income classifications, electricity-only inclusion in rent, account credits and administrative checks remain incomplete. Earlier results use parameter backfilling and are unverified historical estimates. + notes: FY2026 regular heating and ordinary winter electric allowance only. A state-specific dwelling-type input selects single-family, mobile-home, or multi-unit points, defaulting to single-family when omitted; heat included in rent receives zero dwelling points for every type. Kerosene earns no heating award, and the residual other-fuel category receives bulk-fuel points because wood pellets, corn and biofuels cannot be separated within it. Gross business income, detailed household/income classifications, electricity-only inclusion in rent, account credits and administrative checks remain incomplete. Earlier results use parameter backfilling and are unverified historical estimates. - state: TX status: partial name: Texas CEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml index 5cb7f1fc235..7620917a443 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml @@ -74,7 +74,13 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] output: in_eap: [200, 200, 200, 200, 200, 200, 200, 200, 200, 200] -- name: Regular heating fuel points and excluded unspecified fuels +- name: Regular heating fuel points, with kerosene, solar, unspecified and no heating limited to the electric allowance + # One person, $0 income: band 1 (9 income points, $125 electric); single-family: 3 points. + # Section 8.5 (page 71): natural gas and electricity 1 point, bulk fuels 6 points. + # Electricity, natural gas: (9 + 3 + 1) x $25 + $125 = $450. + # Propane, fuel oil, coal, wood and other (pellets, corn, biofuels): (9 + 3 + 6) x $25 + $125 = $575. + # Kerosene (Section 1.1, page 10, bars EAP funds for it), solar, unspecified and no + # heating earn zero fuel points and no heating award: the $125 electric payment only. period: 2_026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] @@ -91,7 +97,7 @@ heating_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] output: - in_eap: [450, 450, 575, 575, 575, 575, 575, 125, 125, 125, 125] + in_eap: [450, 450, 575, 575, 125, 575, 575, 575, 125, 125, 125] - name: Vulnerability points are awarded once across age, disability, military and pregnancy categories period: 2_026 input: @@ -142,6 +148,7 @@ rent: [1_200, 1_200, 1_200] in_eap_eligible: [true, true, true] in_eap_income: [0, 20_000, 30_000] + heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] heat_expense_included_in_rent: [true, true, true] pre_subsidy_electricity_expense: [1_000, 1_000, 1_000] output: @@ -208,3 +215,52 @@ tenant_pays_utilities: [false, false, false] output: in_eap: [100, 100, 100] + +- name: Other fuel reads the other heating fuel bill for bulk-fuel points, and kerosene earns no heating award + # Wages: $7.25 x 2,080 hours = $15,080. Three-month income $15,080 x 3 / 12 = $3,770 + # is within the size 1 band 1 ceiling floor($55,928 x 0.30 x 3 / 12) = $4,194: + # 9 income points and the $125 electric payment. Single-family dwelling: 3 points. + # Household 1, OTHER with a $900 other-fuel bill (Section 8.5, page 71: pellets, corn + # and biofuels are 6-point bulk fuels): (9 + 3 + 6) x $25 + $125 = $575. + # Household 2, OTHER with the bill reported only as wood: heating_expense reads + # other_heating_fuel_expense for OTHER, so there is no heating bill: $125 only. + # Household 3, KEROSENE with a $1,400 fuel bill (Section 1.1, page 10): zero fuel + # points, so no heating award: $125 only. + period: 2026 + input: + state_code: [IN, IN, IN] + age: [40, 40, 40] + employment_income: [15_080, 15_080, 15_080] + heating_type: [OTHER, OTHER, KEROSENE] + other_heating_fuel_expense: [900, 0, 0] + wood_expense: [0, 900, 0] + fuel_oil_expense: [0, 0, 1_400] + pre_subsidy_electricity_expense: [1_200, 1_200, 1_200] + output: + heating_expense: [900, 0, 1_400] + in_eap_income: [15_080, 15_080, 15_080] + in_eap: [575, 125, 125] + +- name: All utilities in rent through the tenant flag alone pays both benefits + # Section 4.7 (page 33): a tenant who pays all utilities in rent receives both + # benefits. tenant_pays_utilities: false, with the heat flag omitted, places heat + # and electricity in rent: 2 income points regardless of income (here $12,000, a + # band 1 income), no dwelling or fuel points, and the $50 electric-in-rent payment. + # Household 1: 2 x $25 + $50 = $100. + # Household 2, age 60: (2 + 2 vulnerability) x $25 + $50 = $150. + # Household 3, $11 a year in rent, below $1 a month ($12 a year): $0. + # Household 4, gas and electric bills also reported: the bills earn no matrix + # heating points once heat is in rent, so 2 x $25 + $50 = $100. + period: 2026 + input: + state_code: [IN, IN, IN, IN] + age: [40, 60, 40, 40] + rent: [9_600, 9_600, 11, 9_600] + in_eap_eligible: [true, true, true, true] + in_eap_income: [12_000, 12_000, 12_000, 12_000] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + tenant_pays_utilities: [false, false, false, false] + gas_expense: [0, 0, 0, 1_000] + pre_subsidy_electricity_expense: [0, 0, 0, 1_000] + output: + in_eap: [100, 150, 0, 100] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml index ca110e548c7..7a5643d2661 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml @@ -10,6 +10,8 @@ rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] in_eap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] in_eap_income: [33_556, 43_882, 54_207, 64_533, 74_857, 85_183, 87_119, 89_055, 90_991, 92_927] + heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, + UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] output: in_eap_eligible: [true, true, true, true, true, true, true, true, true, true] - name: Published annual sixty percent SMI limits, one dollar above @@ -24,6 +26,8 @@ rent: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] in_eap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] in_eap_income: [33_557, 43_883, 54_208, 64_534, 74_858, 85_184, 87_120, 89_056, 90_992, 92_928] + heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, + UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] output: in_eap_eligible: [false, false, false, false, false, false, false, false, false, false] - name: Federal household adjustment extends to households larger than the printed chart @@ -38,6 +42,7 @@ rent: [0, 0] in_eap_household_size: [11, 11] in_eap_income: [94_863, 94_864] + heating_type: [UNSPECIFIED, UNSPECIFIED] output: in_eap_eligible: [true, false] - name: Household eligibility requires an adult and an eligible member, independently of a utility bill @@ -52,5 +57,38 @@ rent: [0, 0, 0] immigration_status: [CITIZEN, CITIZEN, UNDOCUMENTED] in_eap_income: [0, 0, 0] + heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] output: in_eap_eligible: [false, true, false] + +- name: Farm operations income puts a farm couple over the income limit + # Section 6.1 (pages 51-52) defines self-employment to include farming (Schedule F). + # Income: $58,000 farm operations + $16,640 wages ($16.00 x 1,040 hours) = $74,640. + # Size 2 SMI: floor($107,555 x 0.68) = $73,137; 60% limit floor($43,882.20) = $43,882. + # $74,640 > $43,882, so the household is ineligible and receives $0. The wages alone + # ($16,640) would be within the limit. + period: 2026 + input: + people: + person1: + age: 52 + farm_operations_income: 58_000 + person2: + age: 50 + employment_income: 16_640 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: PROPANE + bottled_gas_expense: 2_400 + pre_subsidy_electricity_expense: 1_800 + households: + household: + members: [person1, person2] + state_code: IN + output: + in_eap_household_size: 2 + in_eap_smi: 73_137 + in_eap_income: 74_640 + in_eap_eligible: false + in_eap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml index 26df5d54fdb..d93f568e16c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml @@ -67,6 +67,7 @@ spm_units: unit: members: [adult, child] + heating_type: UNSPECIFIED households: home: members: [adult, child] @@ -75,3 +76,48 @@ in_eap_household_size: 1 in_eap_income: 15_600 in_eap_eligible: true + +- name: Farm, partnership and S corporation, estate, farm rental, strike and military retirement income count + # Section 6.1 (pages 51-52, 54, 56): Schedule F farm income, Schedule E partnership + # and S corporation, estate and trust, and farm rental lines, strike benefits and + # pensions count. One counted adult per household, one source each: + # farm operations $21,000; partnership $9,000 + S corporation $6,000 = $15,000; + # estate $4,800; farm rent $7,200; strike benefits $2,400; military retirement $18,000. + period: 2026 + input: + state_code: [IN, IN, IN, IN, IN, IN] + age: [45, 45, 45, 45, 45, 45] + farm_operations_income: [21_000, 0, 0, 0, 0, 0] + partnership_income: [0, 9_000, 0, 0, 0, 0] + s_corp_income: [0, 6_000, 0, 0, 0, 0] + estate_income: [0, 0, 4_800, 0, 0, 0] + farm_rent_income: [0, 0, 0, 7_200, 0, 0] + strike_benefits: [0, 0, 0, 0, 2_400, 0] + military_retirement_pay: [0, 0, 0, 0, 0, 18_000] + output: + in_eap_income: [21_000, 15_000, 4_800, 7_200, 2_400, 18_000] + +- name: Each income source is floored at zero, so a business, rental or farm loss does not offset wages + # Section 6.1 (pages 51-52) counts gross business income before expenses, so a net + # loss in one source cannot reduce other income. Wages: $14.00 x 2,080 hours = $29,120. + # Household 1: max($29,120, 0) + max(-$15,000 self-employment, 0) = $29,120. + # Household 2: max($29,120, 0) + max(-$6,000 rental, 0) = $29,120. + # Household 3: max($29,120, 0) + max(-$9,000 farm operations, 0) = $29,120. + # $29,120 is within the size 1 limit of $33,556. Three-month income $29,120 x 3 / 12 + # = $7,280 exceeds the band 2 ceiling floor($55,928 x 0.45 x 3 / 12) = $6,291: band 3. + # Natural gas, single-family: (2 + 3 + 1) x $25 + $50 electric = $200. + period: 2026 + input: + state_code: [IN, IN, IN] + age: [40, 40, 40] + employment_income: [29_120, 29_120, 29_120] + self_employment_income: [-15_000, 0, 0] + rental_income: [0, -6_000, 0] + farm_operations_income: [0, 0, -9_000] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_100, 1_100, 1_100] + pre_subsidy_electricity_expense: [1_300, 1_300, 1_300] + output: + in_eap_income: [29_120, 29_120, 29_120] + in_eap_eligible: [true, true, true] + in_eap: [200, 200, 200] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml index 7bcaddd71bf..8885545f84d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml @@ -92,3 +92,185 @@ in_eap_household_size: 1 in_eap_smi: 45_020 in_eap_eligible: true + +# The cases below start from raw inputs: SSI, Social Security, rent, household size, +# income and eligibility are computed by the model rather than supplied. +- name: Two-earner family with a four-year-old lands in the middle band from wages + # Wages: $27,040 ($13.00 x 2,080 hours) + $10,400 ($10.00 x 1,040 hours) = $37,440. + # No member is aged, blind or disabled, so SSI is $0; no rent is reported. + # Size 3 SMI: floor($107,555 x 0.84) = $90,346; 60% limit floor($54,207.60) = $54,207. + # Three-month income: $37,440 x 3 / 12 = $9,360. + # Band 1 ceiling floor($90,346 x 0.30 x 3 / 12) = $6,775; band 2 ceiling + # floor($90,346 x 0.45 x 3 / 12) = $10,163, so band 2 (5 points, $100 electric). + # Points: 5 income + 2 mobile home + 6 propane + 2 vulnerable (child age 4) = 15. + # Heating 15 x $25 = $375; electric $100; total $475. + period: 2026 + input: + people: + person1: + age: 34 + employment_income: 27_040 + person2: + age: 32 + employment_income: 10_400 + person3: + age: 4 + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: PROPANE + bottled_gas_expense: 1_800 + pre_subsidy_electricity_expense: 1_500 + in_eap_dwelling_type: MOBILE_HOME + households: + household: + members: [person1, person2, person3] + state_code: IN + output: + ssi: [0, 0, 0] + rent: [0, 0, 0] + heating_expense: 1_800 + in_eap_household_size: 3 + in_eap_smi: 90_346 + in_eap_income: 37_440 + in_eap_eligible: true + in_eap: 475 + +- name: Single parent with full-time wages lands in the highest band + # Wages: $17.50 x 2,080 hours = $36,400; the seven-year-old has no income. + # Size 2 SMI: floor($107,555 x 0.68) = $73,137; 60% limit floor($43,882.20) = $43,882. + # Three-month income: $36,400 x 3 / 12 = $9,100, above the band 2 ceiling + # floor($73,137 x 0.45 x 3 / 12) = $8,227, so band 3 (2 points, $50 electric). + # Points: 2 income + 3 single-family + 1 natural gas = 6; a seven-year-old is not + # a vulnerable member. Heating 6 x $25 = $150; electric $50; total $200. + period: 2026 + input: + people: + person1: + age: 29 + employment_income: 36_400 + person2: + age: 7 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_100 + pre_subsidy_electricity_expense: 1_400 + households: + household: + members: [person1, person2] + state_code: IN + output: + heating_expense: 1_100 + in_eap_household_size: 2 + in_eap_smi: 73_137 + in_eap_income: 36_400 + in_eap_eligible: true + in_eap: 200 + +- name: Elderly widow with Social Security retirement net of Medicare Part B and a pension + # Section 6.2 (page 55) counts the Social Security check net of Medicare Part B. + # Social Security: $1,300 x 12 = $15,600 retirement; Part B $202.90 x 12 = $2,434.80; + # net $13,165.20. Pension: $500 x 12 = $6,000. Income: $19,165.20. + # Computed SSI: countable ($15,600 + $6,000) / 12 - $20 = $1,780 a month exceeds the + # $994 federal benefit rate, so SSI is $0. + # Size 1 SMI: floor($107,555 x 0.52) = $55,928; 60% limit floor($33,556.80) = $33,556. + # Three-month income: $19,165.20 x 3 / 12 = $4,791.30, above the band 1 ceiling + # floor($55,928 x 0.30 x 3 / 12) = $4,194 and within the band 2 ceiling + # floor($55,928 x 0.45 x 3 / 12) = $6,291, so band 2 (5 points, $100 electric). + # Points: 5 income + 3 single-family + 6 wood + 2 vulnerable (age 60 or older) = 16. + # Heating 16 x $25 = $400; electric $100; total $500. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + social_security_retirement: 15_600 + medicare_part_b_premiums_reported: 2_434.80 + taxable_private_pension_income: 6_000 + spm_units: + spm_unit: + members: [person1] + heating_type: WOOD + wood_expense: 900 + pre_subsidy_electricity_expense: 1_200 + households: + household: + members: [person1] + state_code: IN + output: + social_security: 15_600 + ssi: 0 + heating_expense: 900 + in_eap_household_size: 1 + in_eap_smi: 55_928 + in_eap_income: 19_165.20 + in_eap_eligible: true + in_eap: 500 + +- name: Disabled part-time worker qualifies as vulnerable through computed SSI + # The adult meets the SSI disability criteria and earns $1,000 a month ($12,000), + # below the 2026 substantial gainful activity limit of $1,690 a month. + # SSI countable income: ($1,000 - $20 general - $65 earned) x 0.5 = $457.50 a month. + # SSI: $994 - $457.50 = $536.50 a month; $6,438 a year. + # Income: $12,000 wages + $6,438 SSI = $18,438. + # Three-month income: $18,438 x 3 / 12 = $4,609.50, above the band 1 ceiling of + # $4,194 and within the band 2 ceiling of $6,291, so band 2 (5 points, $100 electric). + # Medicaid receipt is not reported, so the vulnerability points come from SSI > 0. + # Points: 5 income + 1 multi-unit + 1 electric heat + 2 vulnerable = 9. + # Heating 9 x $25 = $225; electric $100; total $325. + period: 2026 + input: + people: + person1: + age: 45 + is_disabled: true + meets_ssi_disability_criteria: true + employment_income: 12_000 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_500 + in_eap_dwelling_type: MULTI_UNIT + households: + household: + members: [person1] + state_code: IN + output: + ssi: 6_438 + heating_expense: 1_500 + in_eap_household_size: 1 + in_eap_smi: 55_928 + in_eap_income: 18_438 + in_eap_eligible: true + in_eap: 325 + +- name: All utilities in rent require one dollar of monthly out-of-pocket rent computed from pre-subsidy rent + # Section 4.7 (pages 32-33): a tenant with utilities in rent must pay at least $1 a + # month in rent, and a tenant who pays all utilities in rent receives both benefits. + # Each tenant earns $11.00 x 2,080 hours = $22,880, within the size 1 limit of $33,556, + # and receives no rental assistance, so out-of-pocket rent equals pre-subsidy rent. + # Heat in rent: 2 income points regardless of income, no dwelling or fuel points; + # electricity in rent: $50. With rent of at least $12 a year: 2 x $25 + $50 = $100. + # Household 1: $750 a month ($9,000) market rent: $100. + # Household 2: exactly $1 a month ($12), the boundary: $100. + # Household 3: $11 a year, below $1 a month: $0. + # Household 4: no rent paid: $0. + period: 2026 + input: + state_code: [IN, IN, IN, IN] + age: [26, 26, 26, 26] + employment_income: [22_880, 22_880, 22_880, 22_880] + pre_subsidy_rent: [9_000, 12, 11, 0] + takes_up_housing_assistance_if_eligible: [false, false, false, false] + tenant_pays_utilities: [false, false, false, false] + in_eap_dwelling_type: [MULTI_UNIT, MULTI_UNIT, MULTI_UNIT, MULTI_UNIT] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + output: + rent: [9_000, 12, 11, 0] + in_eap_income: [22_880, 22_880, 22_880, 22_880] + in_eap_eligible: [true, true, true, true] + in_eap: [100, 100, 0, 0] diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py index aba798c0660..0c85668ef10 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py @@ -12,24 +12,34 @@ class in_eap(Variable): "and are unverified historical estimates." ) defined_for = "in_eap_eligible" - reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26,27,32,33,69,70,71,72,73,74,75,77,78" + reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=10,26,27,32,33,47,69,70,71,72,73,74,75,77,78" def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].ihcda.eap person = spm_unit.members smi_amount = spm_unit("in_eap_smi", period) - quarterly_income = spm_unit("in_eap_income", period) / 4 - low = quarterly_income <= np.floor(smi_amount * p.benefit.income.lower_rate / 4) - middle = quarterly_income <= np.floor( - smi_amount * p.benefit.income.middle_rate / 4 + # Sections 6 and 8.3 place a household in an income band using the most recent + # three months of income, so annual amounts are scaled to that period. + months_share = p.income.calculation_months / MONTHS_IN_YEAR + calculation_income = spm_unit("in_eap_income", period) * months_share + low = calculation_income <= np.floor( + smi_amount * p.benefit.income.lower_rate * months_share ) - heat_in_rent = spm_unit("heat_expense_included_in_rent", period) - # The shared tenant flag identifies all utilities included in rent. It does not - # identify electricity alone included in rent while other utilities are separate; - # that mixed arrangement remains unsupported without an electricity-specific input. + middle = calculation_income <= np.floor( + smi_amount * p.benefit.income.middle_rate * months_share + ) + # The shared tenant flag identifies all utilities included in rent, so Section + # 4.7 places both heat and electricity in rent for that household. It does not + # identify electricity alone included in rent while heat is billed separately; + # that mixed arrangement remains unsupported without an electricity-specific + # input. electric_in_rent = ~spm_unit.household("tenant_pays_utilities", period) + heat_in_rent = ( + spm_unit("heat_expense_included_in_rent", period) | electric_in_rent + ) rent_paid = ( - add(spm_unit, period, ["rent"]) >= p.eligibility.minimum_monthly_rent * 12 + add(spm_unit, period, ["rent"]) + >= p.eligibility.minimum_monthly_rent * MONTHS_IN_YEAR ) fuel = spm_unit("heating_type", period) fuel_points = p.benefit.fuel_points[fuel] diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py index 8d1debff9e2..700a898ad7e 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py @@ -26,11 +26,17 @@ def formula(spm_unit, period, parameters): counted = (age >= p.eligibility.adult_age) & ~(dependent & student) # Use annual inputs as an approximation to the annualized preceding three months. # Section 6.1 prefers paystub federal taxable gross when supplied; current wages - # do not identify that paystub field. Existing self_employment_income is net, - # whereas the manual asks for Schedule C gross profit (line 5) and Schedule F - # gross income. Keep the existing net-income approximation: no new gross inputs - # or separate business/work-expense adjustments are introduced in this project. - other = max_(add(person, period, p.income.sources), 0) * counted + # do not identify that paystub field. The manual asks for gross amounts: + # Schedule C line 5, Schedule F line 9 and the Schedule E rent, partnership and + # S corporation, estate and trust, and farm rental lines. The existing + # self-employment, farm and rental inputs are net approximations of those + # amounts: no new gross inputs or separate business/work-expense adjustments + # are introduced in this project. Each source is floored at zero, so a loss in + # one source cannot offset other counted income. + other = 0 + for source in p.income.sources: + other = other + max_(person(source, period), 0) + other = other * counted # Child SSA benefits count despite the general under-18 exclusion. Only reported # Part B premiums are available to approximate the required net SSA payment; # Part D, withholding, overpayment recovery, and exact garnishment are unavailable. From 533135bf292682b25e07ddbcc7d3c6ba801da012 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 30 Sep 2026 23:51:03 -0400 Subject: [PATCH 5/9] Use ordinary_dividend_income in Indiana EAP income sources Replace the deprecated dividend_income alias. Results are unchanged because the alias only adds ordinary_dividend_income. Co-Authored-By: Claude Fable 5.1 --- .../parameters/gov/states/in/ihcda/eap/income/sources.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml index e99d095cc62..78a182b61ac 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml @@ -22,7 +22,7 @@ values: - workers_compensation - disability_benefits - financial_assistance - - dividend_income + - ordinary_dividend_income - interest_income - rental_income - gambling_winnings From c0e8ea0bc477198ba3ba57eac86529974a72f1ff Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 1 Oct 2026 01:26:59 -0400 Subject: [PATCH 6/9] Count SSTB income in Indiana EAP --- .../states/in/ihcda/eap/income/sources.yaml | 1 + .../states/in/ihcda/eap/in_eap_income.yaml | 30 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml index 78a182b61ac..bc7367c4b26 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml @@ -3,6 +3,7 @@ values: 2025-10-01: - employment_income - self_employment_income + - sstb_self_employment_income # Section 6.1 defines self-employment to include farming (Schedule F) and lists # the Schedule E partnership and S corporation, estate and trust, and farm # rental lines. diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml index d93f568e16c..866334948fc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml @@ -10,8 +10,10 @@ rent: 0 employment_income: 12_000 self_employment_income: 6_000 + sstb_self_employment_income: 3_000 output: - in_eap_income: 18_000 + # 12,000 wages + 6,000 ordinary business + 3,000 specified service business. + in_eap_income: 21_000 - name: Adult dependent secondary and college student exemptions do not extend past age twenty-three for college period: 2_026 input: @@ -26,9 +28,10 @@ is_in_secondary_school: [true, false, false, false] is_full_time_college_student: [false, true, true, true] employment_income: [12_000, 12_000, 12_000, 12_000] + sstb_self_employment_income: [3_000, 3_000, 3_000, 3_000] interest_income: [1_000, 1_000, 1_000, 1_000] output: - in_eap_income: [0, 0, 13_000, 13_000] + in_eap_income: [0, 0, 16_000, 16_000] - name: Reported Medicare premium and support paid reduce income, while TANF, support received and capital gains are excluded period: 2_026 @@ -103,6 +106,7 @@ # Household 1: max($29,120, 0) + max(-$15,000 self-employment, 0) = $29,120. # Household 2: max($29,120, 0) + max(-$6,000 rental, 0) = $29,120. # Household 3: max($29,120, 0) + max(-$9,000 farm operations, 0) = $29,120. + # Each also has a $2,000 specified service business loss, floored at zero. # $29,120 is within the size 1 limit of $33,556. Three-month income $29,120 x 3 / 12 # = $7,280 exceeds the band 2 ceiling floor($55,928 x 0.45 x 3 / 12) = $6,291: band 3. # Natural gas, single-family: (2 + 3 + 1) x $25 + $50 electric = $200. @@ -112,6 +116,7 @@ age: [40, 40, 40] employment_income: [29_120, 29_120, 29_120] self_employment_income: [-15_000, 0, 0] + sstb_self_employment_income: [-2_000, -2_000, -2_000] rental_income: [0, -6_000, 0] farm_operations_income: [0, 0, -9_000] heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] @@ -121,3 +126,24 @@ in_eap_income: [29_120, 29_120, 29_120] in_eap_eligible: [true, true, true] in_eap: [200, 200, 200] + +- name: Service business profits above the income limit prevent a heating award + # Section 6.1 counts business income; a specified service business is not + # exempt. Existing net profits remain the documented gross-income approximation. + period: 2026 + input: + state_code: IN + age: 40 + sstb_self_employment_income: 60_000 + ssi: 0 + social_security: 0 + receives_ssi: false + receives_medicaid: false + heating_type: NATURAL_GAS + gas_expense: 1_000 + pre_subsidy_electricity_expense: 1_000 + output: + in_eap_income: 60_000 + # Above the published one-person annual limit of 33,556. + in_eap_eligible: false + in_eap: 0 From c9febf19309277caf96c1a9b5f28443f1502e325 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 1 Oct 2026 17:43:31 -0400 Subject: [PATCH 7/9] Shorten the Indiana EAP registry note Co-Authored-By: Claude Fable 5.1 --- policyengine_us/programs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index a253e0403e3..b7048f1acbe 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -830,7 +830,7 @@ programs: variable: in_eap parameter_prefix: gov.states.in.ihcda.eap verified_years: "2026" - notes: FY2026 regular heating and ordinary winter electric allowance only. A state-specific dwelling-type input selects single-family, mobile-home, or multi-unit points, defaulting to single-family when omitted; heat included in rent receives zero dwelling points for every type. Kerosene earns no heating award, and the residual other-fuel category receives bulk-fuel points because wood pellets, corn and biofuels cannot be separated within it. Gross business income, detailed household/income classifications, electricity-only inclusion in rent, account credits and administrative checks remain incomplete. Earlier results use parameter backfilling and are unverified historical estimates. + notes: PY2026 regular heating and the winter electric allowance only. Crisis, cooling and weatherization assistance are out of scope. - state: TX status: partial name: Texas CEAP From 2cfdf94d649c6a00b8c5df4f0535c75d1cc3182c Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 2 Oct 2026 12:35:31 -0400 Subject: [PATCH 8/9] Address Indiana EAP review Add the PY2024-25 values for the income points, electric payments and fuel points that differ from FY2026, and list the fuels that receive the heating award in a parameter so natural gas and electric households are paid in FY2025. Count survivor benefits, drop military retirement pay as a separate source, and count Social Security gross with the Medicare premium deduction left as a documented gap. Use single-page references with section numbers, fix test periods and names, rewrite descriptions, and add size-11, disability, heat-in-rent and FY2025 cases. Co-Authored-By: Claude Fable 5.1 --- changelog.d/in-eap.added.md | 2 +- .../ihcda/eap/benefit/amount_per_point.yaml | 4 +- .../in/ihcda/eap/benefit/dwelling_points.yaml | 8 +- .../benefit/electricity/higher_income.yaml | 9 +- .../eap/benefit/electricity/lower_income.yaml | 11 +- .../benefit/electricity/middle_income.yaml | 12 +- .../in/ihcda/eap/benefit/fuel_points.yaml | 22 +++- .../eap/benefit/heating_award_fuels.yaml | 25 ++++ .../eap/benefit/income/higher_points.yaml | 9 +- .../eap/benefit/income/lower_points.yaml | 11 +- .../ihcda/eap/benefit/income/lower_rate.yaml | 4 +- .../eap/benefit/income/middle_points.yaml | 11 +- .../ihcda/eap/benefit/income/middle_rate.yaml | 4 +- .../benefit/vulnerability/elderly_age.yaml | 8 +- .../eap/benefit/vulnerability/points.yaml | 9 +- .../vulnerability/young_child_age_limit.yaml | 8 +- .../in/ihcda/eap/eligibility/adult_age.yaml | 9 +- .../ihcda/eap/eligibility/income_limit.yaml | 4 +- .../eap/eligibility/minimum_monthly_rent.yaml | 4 +- .../ihcda/eap/income/calculation_months.yaml | 4 +- .../states/in/ihcda/eap/income/sources.yaml | 22 +++- .../ihcda/eap/income/student_age_limit.yaml | 2 +- policyengine_us/programs.yaml | 2 +- .../gov/states/in/ihcda/eap/in_eap.yaml | 121 ++++++++++++++---- .../states/in/ihcda/eap/in_eap_eligible.yaml | 18 +-- .../states/in/ihcda/eap/in_eap_income.yaml | 62 +++++---- .../gov/states/in/ihcda/eap/integration.yaml | 111 +++++++++------- .../gov/states/in/ihcda/eap/in_eap.py | 24 +++- .../in/ihcda/eap/in_eap_dwelling_type.py | 5 +- .../states/in/ihcda/eap/in_eap_eligible.py | 8 +- .../in/ihcda/eap/in_eap_household_size.py | 17 ++- .../gov/states/in/ihcda/eap/in_eap_income.py | 36 +++--- .../gov/states/in/ihcda/eap/in_eap_smi.py | 7 +- 33 files changed, 413 insertions(+), 200 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/heating_award_fuels.yaml diff --git a/changelog.d/in-eap.added.md b/changelog.d/in-eap.added.md index 9b8c50148c8..f2934b4a7ef 100644 --- a/changelog.d/in-eap.added.md +++ b/changelog.d/in-eap.added.md @@ -1 +1 @@ -Added partial Indiana EAP regular heating assistance with state-specific dwelling types for single-family homes, mobile homes, and multi-unit dwellings, with remaining income and administrative gaps documented. +Add Indiana Energy Assistance Program (EAP) regular heating assistance and the winter electric allowance. diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml index 20fb7809d0c..fd60307690f 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/amount_per_point.yaml @@ -1,4 +1,4 @@ -description: Indiana pays this regular heating amount per matrix point under the Energy Assistance Program. +description: Indiana provides this regular heating amount per matrix point under the Energy Assistance Program. values: 2025-10-01: 25 metadata: @@ -6,5 +6,5 @@ metadata: period: year label: Indiana EAP amount per point reference: - - title: Indiana PY2026 EAP Intake and Operations Manual + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.11, page 77 href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=77 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/dwelling_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/dwelling_points.yaml index fd05826de52..415dadb5bc7 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/dwelling_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/dwelling_points.yaml @@ -1,4 +1,4 @@ -description: Indiana awards these regular heating points by dwelling type under the Energy Assistance Program. +description: Indiana provides these regular heating points by dwelling type under the Energy Assistance Program. SINGLE_FAMILY: 2025-10-01: 3 MOBILE_HOME: @@ -12,5 +12,7 @@ metadata: - in_eap_dwelling_type label: Indiana EAP dwelling points reference: - - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.4 - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70,71 + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.4, page 71 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=71 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml index 380aad97e34..0c895588d09 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/higher_income.yaml @@ -1,4 +1,4 @@ -description: Indiana pays this regular electric supplement in the highest income band or when electricity is included in rent under the Energy Assistance Program. +description: Indiana provides this regular electric supplement in the highest income band or when electricity is included in rent under the Energy Assistance Program. values: 2025-10-01: 50 metadata: @@ -6,5 +6,8 @@ metadata: period: year label: Indiana EAP higher income electric payment reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72,73 + # Page 72 holds the electricity-in-rent rule and page 73 the 45% to 60% chart. + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.7, pages 72-73 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml index b2270416f6f..c21d369b210 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/lower_income.yaml @@ -1,10 +1,15 @@ -description: Indiana pays this regular electric supplement in the lowest income band under the Energy Assistance Program. +description: Indiana provides this regular electric supplement in the lowest income band under the Energy Assistance Program. values: + 2024-10-01: 100 2025-10-01: 125 metadata: unit: currency-USD period: year label: Indiana EAP lower income electric payment reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72,73 + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.7, page 72 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 + - title: Indiana PY2024-25 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/IN_BenefitMatrix_2025.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml index 1cb821b8369..fddcb148a73 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/electricity/middle_income.yaml @@ -1,10 +1,16 @@ -description: Indiana pays this regular electric supplement in the middle income band under the Energy Assistance Program. +description: Indiana provides this regular electric supplement in the middle income band under the Energy Assistance Program. values: + 2024-10-01: 75 2025-10-01: 100 metadata: unit: currency-USD period: year label: Indiana EAP middle income electric payment reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72,73 + # Page 72 holds the payment amount and page 73 the 30% to 45% chart. + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.7, pages 72-73 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 + - title: Indiana PY2024-25 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/IN_BenefitMatrix_2025.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml index db1d3080c8f..f02a613d751 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/fuel_points.yaml @@ -1,9 +1,12 @@ -description: Indiana awards these regular heating points by primary fuel under the Energy Assistance Program. +description: Indiana provides these regular heating points by primary fuel under the Energy Assistance Program. UNSPECIFIED: 2025-10-01: 0 +# The PY2024-25 matrix awarded zero points for natural gas and electric heat. ELECTRICITY: + 2024-10-01: 0 2025-10-01: 1 NATURAL_GAS: + 2024-10-01: 0 2025-10-01: 1 FUEL_OIL: 2025-10-01: 6 @@ -17,11 +20,13 @@ WOOD: 2025-10-01: 6 COAL: 2025-10-01: 6 +# Assumption: neither the manual nor the matrix lists solar heat, so it is given +# no fuel points. SOLAR: 2025-10-01: 0 -# Section 8.5 has no zero-point fuel outside rent. The remaining named fuels (wood -# pellets, corn and biofuels) are bulk fuels that the heating type input cannot -# separate within OTHER, so OTHER receives the bulk-fuel points. +# Assumption: Section 8.5 has no zero-point fuel outside rent. The remaining named +# fuels (wood pellets, corn and biofuels) are bulk fuels that the heating type +# input cannot separate within OTHER, so OTHER receives the bulk-fuel points. OTHER: 2025-10-01: 6 NONE: @@ -33,5 +38,10 @@ metadata: - heating_type label: Indiana EAP heating fuel points reference: - - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 1.1 and 8.5 - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=10,71 + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 1.1 (page 10) and 8.5 (page 71) + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=71 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 + # Page 1 holds the fuel source rows and page 2 the fuel source instruction. + - title: Indiana PY2024-25 EAP Benefit Matrix, pages 1-2 + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/IN_BenefitMatrix_2025.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/heating_award_fuels.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/heating_award_fuels.yaml new file mode 100644 index 00000000000..b97b6e8d0c8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/heating_award_fuels.yaml @@ -0,0 +1,25 @@ +description: Indiana provides the regular heating award to households heating with these fuels under the Energy Assistance Program. +# The heating_type input names each fuel. OTHER covers wood pellets, corn and +# biofuels, which Section 8.5 lists as bulk fuels. +# KEROSENE is left out because Section 1.1 bars EAP funds for kerosene. +# SOLAR is left out as an assumption: neither the manual nor the matrix lists it. +# NONE and UNSPECIFIED are left out, so an unspecified fuel receives no heating +# award. Heat included in rent is handled in the benefit formula, not here. +values: + 2024-10-01: + - ELECTRICITY + - NATURAL_GAS + - FUEL_OIL + - PROPANE + - WOOD + - COAL + - OTHER +metadata: + unit: list + period: year + label: Indiana EAP heating award fuels + reference: + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 1.1 (page 10) and 8.5 (page 71) + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=71 + - title: Indiana PY2024-25 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/IN_BenefitMatrix_2025.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml index 7055b51d4df..658e16f934a 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/higher_points.yaml @@ -1,4 +1,4 @@ -description: Indiana awards these income points in the highest income band or when heat is included in rent under the Energy Assistance Program. +description: Indiana provides these income points in the highest income band or when heat is included in rent under the Energy Assistance Program. values: 2025-10-01: 2 metadata: @@ -6,5 +6,8 @@ metadata: period: year label: Indiana EAP higher income points reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 + # Page 69 holds the heat-in-rent rule and page 70 the 45% to 60% chart. + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.3, pages 69-70 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml index ce0decdc4a8..13dfd2d2a28 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_points.yaml @@ -1,10 +1,15 @@ -description: Indiana awards these income points in the lowest income band under the Energy Assistance Program. +description: Indiana provides these income points in the lowest income band under the Energy Assistance Program. values: + 2024-10-01: 6 2025-10-01: 9 metadata: unit: /1 period: year label: Indiana EAP lower income points reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.3, pages 69-70 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 + - title: Indiana PY2024-25 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/IN_BenefitMatrix_2025.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml index 52a72da1651..f9b46945fce 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/lower_rate.yaml @@ -6,5 +6,5 @@ metadata: period: year label: Indiana EAP lower income rate reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.3, pages 69-70 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml index 4b5e2de4ade..d4f0fbeb90c 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_points.yaml @@ -1,10 +1,15 @@ -description: Indiana awards these income points in the middle income band under the Energy Assistance Program. +description: Indiana provides these income points in the middle income band under the Energy Assistance Program. values: + 2024-10-01: 4 2025-10-01: 5 metadata: unit: /1 period: year label: Indiana EAP middle income points reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.3, page 70 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 + - title: Indiana PY2024-25 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2025/benefits-matricies/IN_BenefitMatrix_2025.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml index a1d7266c007..ccc0e2b808b 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/income/middle_rate.yaml @@ -6,5 +6,5 @@ metadata: period: year label: Indiana EAP middle income rate reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70 + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.3, page 70 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml index 36679b9e5e6..19d0565abad 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/elderly_age.yaml @@ -1,4 +1,4 @@ -description: Indiana awards vulnerability points beginning at this age under the Energy Assistance Program. +description: Indiana sets this minimum age for the elderly vulnerable population category under the Energy Assistance Program. values: 2025-10-01: 60 metadata: @@ -6,5 +6,7 @@ metadata: period: year label: Indiana EAP elderly age reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26,27,71,72 + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 3.4 (pages 26-27) and 8.6 (pages 71-72) + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml index cfe8c449b59..51ff391f34c 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/points.yaml @@ -1,4 +1,4 @@ -description: Indiana awards these additional points once per household with a vulnerable member under the Energy Assistance Program. +description: Indiana provides these additional points once per household with a vulnerable member under the Energy Assistance Program. values: 2025-10-01: 2 metadata: @@ -6,5 +6,8 @@ metadata: period: year label: Indiana EAP vulnerability points reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=71,72 + # Section 8.6 starts on page 71; the two-point award is on page 72. + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 8.6, pages 71-72 + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=72 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml index 63d653a787e..a0942b3640d 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/benefit/vulnerability/young_child_age_limit.yaml @@ -1,4 +1,4 @@ -description: Indiana awards vulnerability points for children through this age under the Energy Assistance Program. +description: Indiana sets this maximum age for the young child vulnerable population category under the Energy Assistance Program. values: 2025-10-01: 5 metadata: @@ -6,5 +6,7 @@ metadata: period: year label: Indiana EAP young child age limit reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26,71,72 + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 3.4 (pages 26-27) and 8.6 (pages 71-72) + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=26 + - title: Indiana PY2025-26 EAP Benefit Matrix, page 1 + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/IN_BenefitMatrix_Heat-Crisis_2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml index b450cd8c4b0..f4173dfc06e 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/adult_age.yaml @@ -1,4 +1,7 @@ -description: Indiana counts income beginning at this age, subject to student and Social Security exceptions under the Energy Assistance Program. +description: Indiana sets this minimum age for an applicant and for counting a household member's income under the Energy Assistance Program. +# Section 4.4 lets a person apply from this age. Section 6 counts income from this +# age, subject to the Section 6.2 student exclusions; Social Security benefits paid +# for younger members also count. values: 2025-10-01: 18 metadata: @@ -6,5 +9,5 @@ metadata: period: year label: Indiana EAP adult age reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,57,58 + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 4.4 (page 29), 6 (page 47) and 6.2 (pages 57-58) + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml index ffa089d1622..a893dddfc09 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/income_limit.yaml @@ -6,5 +6,5 @@ metadata: period: year label: Indiana EAP income limit reference: - - title: Indiana PY2026 EAP Intake and Operations Manual - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23,69,70 + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 3.1 (page 23) and 8.3 (pages 69-70) + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml index fb5c8799552..8eaf78db205 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/eligibility/minimum_monthly_rent.yaml @@ -1,4 +1,4 @@ -description: Indiana requires at least this monthly out-of-pocket rent when utilities are included under the Energy Assistance Program. +description: Indiana sets this minimum monthly out-of-pocket rent for households with utilities included in rent under the Energy Assistance Program. values: 2025-10-01: 1 metadata: @@ -6,5 +6,5 @@ metadata: period: month label: Indiana EAP minimum monthly rent reference: - - title: Indiana PY2026 EAP Intake and Operations Manual + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 4.7, page 32 href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=32 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/calculation_months.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/calculation_months.yaml index 20ae52a7838..72476bcb415 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/calculation_months.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/calculation_months.yaml @@ -6,5 +6,5 @@ metadata: period: year label: Indiana EAP income calculation months reference: - - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 6 and 8.3 - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,69 + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 6 (page 47) and 8.3 (page 69) + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml index bc7367c4b26..e86c12ffe0d 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml @@ -1,7 +1,12 @@ -description: Indiana counts these available income sources for adults who are not exempt students under the Energy Assistance Program; Social Security and SSI are handled separately because benefits paid for children also count. +description: Indiana uses these income sources to compute countable income for adult members who are not exempt students under the Energy Assistance Program. +# Social Security and SSI are not listed here. The income variable adds them +# separately because benefits paid for children also count. values: 2025-10-01: - employment_income + # Section 6.1 (pages 51-52) asks for gross business, farm and rental income before + # expenses. The business, farm and rental inputs below are net amounts, so + # countable income is understated for those households. - self_employment_income - sstb_self_employment_income # Section 6.1 defines self-employment to include farming (Schedule F) and lists @@ -14,9 +19,16 @@ values: - unemployment_compensation - strike_benefits - pension_income - # Military retirement pay is a separate input from pension_income. - - military_retirement_pay + # Section 6.1 (pages 54-55) and Section 6.2 (page 59) exclude lump-sum retirement + # payments of the employee's contributions and interest, and withdrawals of + # principal. This input cannot separate them from recurring payments, so every + # distribution counts and income is overstated for those households. - retirement_distributions + # Section 6.1 (pages 53-54) counts regular life insurance payments to a survivor, + # Black Lung benefits awarded to a survivor, and retirement funds paid to a + # surviving spouse or child. Social Security survivor benefits are added with + # Social Security, not here. + - survivor_benefits - railroad_benefits - alimony_income - veterans_benefits @@ -32,5 +44,5 @@ metadata: period: year label: Indiana EAP adult income sources reference: - - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 6.1 and 6.2 - href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,48,49,50,51,52,53,54,55,56,57,58,59,60,61 + - title: Indiana PY2026 EAP Intake and Operations Manual, Sections 6.1 (pages 47-57) and 6.2 (pages 57-61) + href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47 diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml index e81d876f2fb..c2d53662e2f 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/student_age_limit.yaml @@ -6,5 +6,5 @@ metadata: period: year label: Indiana EAP student age limit reference: - - title: Indiana PY2026 EAP Intake and Operations Manual + - title: Indiana PY2026 EAP Intake and Operations Manual, Section 6.2, page 58 href: https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=58 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index b7048f1acbe..1addb3ac8c4 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, TX, IN + coverage: OR, DC, Riverside County, MA, IL, IN, TX state_implementations: - state: OR status: in_progress diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml index 7620917a443..4ac6644c22d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap.yaml @@ -1,5 +1,5 @@ -- name: Published quarterly band 1 ceilings, at the boundary - period: 2_026 +- name: Case 1, published three-month band 1 ceilings at the boundary. + period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] @@ -17,8 +17,8 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] output: in_eap: [450, 450, 450, 450, 450, 450, 450, 450, 450, 450] -- name: Published quarterly band 1 ceilings, one dollar above - period: 2_026 +- name: Case 2, published three-month band 1 ceilings one dollar above. + period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] @@ -36,8 +36,8 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] output: in_eap: [325, 325, 325, 325, 325, 325, 325, 325, 325, 325] -- name: Published quarterly band 2 ceilings, at the boundary - period: 2_026 +- name: Case 3, published three-month band 2 ceilings at the boundary. + period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] @@ -55,8 +55,8 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] output: in_eap: [325, 325, 325, 325, 325, 325, 325, 325, 325, 325] -- name: Published quarterly band 2 ceilings, one dollar above - period: 2_026 +- name: Case 4, published three-month band 2 ceilings one dollar above. + period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] @@ -74,14 +74,14 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] output: in_eap: [200, 200, 200, 200, 200, 200, 200, 200, 200, 200] -- name: Regular heating fuel points, with kerosene, solar, unspecified and no heating limited to the electric allowance +- name: Case 5, fuel points by heating type with kerosene, solar, unspecified and no heating limited to the electric allowance. # One person, $0 income: band 1 (9 income points, $125 electric); single-family: 3 points. # Section 8.5 (page 71): natural gas and electricity 1 point, bulk fuels 6 points. # Electricity, natural gas: (9 + 3 + 1) x $25 + $125 = $450. # Propane, fuel oil, coal, wood and other (pellets, corn, biofuels): (9 + 3 + 6) x $25 + $125 = $575. # Kerosene (Section 1.1, page 10, bars EAP funds for it), solar, unspecified and no # heating earn zero fuel points and no heating award: the $125 electric payment only. - period: 2_026 + period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40] @@ -98,8 +98,8 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000, 1_000] output: in_eap: [450, 450, 575, 575, 125, 575, 575, 575, 125, 125, 125] -- name: Vulnerability points are awarded once across age, disability, military and pregnancy categories - period: 2_026 +- name: Case 6, vulnerability points are awarded once across age, disability, military and pregnancy categories. + period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN] age: [59, 60, 40, 40, 40, 40, 40, 60] @@ -119,8 +119,8 @@ is_disabled: [false, false, false, false, false, false, true, true] output: in_eap: [575, 625, 625, 625, 625, 625, 625, 625] -- name: Utilities included in rent require one dollar monthly out-of-pocket rent - period: 2_026 +- name: Case 7, utilities included in rent require one dollar of monthly out-of-pocket rent. + period: 2026 input: state_code: [IN, IN, IN] age: [40, 40, 40] @@ -136,8 +136,8 @@ tenant_pays_utilities: [false, false, false] output: in_eap: [0, 0, 100] -- name: Heat in rent with separately billed electricity preserves the income-based electric supplement - period: 2_026 +- name: Case 8, heat in rent with separately billed electricity keeps the income-based electric payment. + period: 2026 input: state_code: [IN, IN, IN] age: [40, 40, 40] @@ -153,8 +153,8 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000] output: in_eap: [175, 150, 100] -- name: Regular benefits are not capped at current bills, and absent electric service receives no supplement - period: 2_026 +- name: Case 9, regular benefits are not capped at current bills and no electric service means no electric payment. + period: 2026 input: state_code: [IN, IN] age: [40, 40] @@ -171,7 +171,7 @@ output: in_eap: [325, 450] -- name: Dwelling type applies the published three, two, and one point awards +- name: Case 10, dwelling type applies the published three, two and one point awards. # Section 8.4: single-family 3, mobile home 2, multi-unit 1; $25 per point. # Low band: (9 + dwelling + 1 gas) * $25 + $125 electricity. # High band: (2 + dwelling + 1 gas) * $25 + $50 electricity. @@ -195,7 +195,7 @@ output: in_eap: [450, 425, 400, 200, 175, 150] -- name: Dwelling type does not change zero dwelling points when heat is in rent +- name: Case 11, dwelling type does not change zero dwelling points when heat is in rent. # Section 8.4: zero dwelling points for every type when heat is in rent. # Two income points * $25 plus the $50 electricity-in-rent allowance. period: 2026 @@ -216,7 +216,7 @@ output: in_eap: [100, 100, 100] -- name: Other fuel reads the other heating fuel bill for bulk-fuel points, and kerosene earns no heating award +- name: Case 12, other fuel reads the other heating fuel bill for bulk-fuel points and kerosene earns no heating award. # Wages: $7.25 x 2,080 hours = $15,080. Three-month income $15,080 x 3 / 12 = $3,770 # is within the size 1 band 1 ceiling floor($55,928 x 0.30 x 3 / 12) = $4,194: # 9 income points and the $125 electric payment. Single-family dwelling: 3 points. @@ -241,7 +241,7 @@ in_eap_income: [15_080, 15_080, 15_080] in_eap: [575, 125, 125] -- name: All utilities in rent through the tenant flag alone pays both benefits +- name: Case 13, all utilities in rent through the tenant flag alone pays both benefits. # Section 4.7 (page 33): a tenant who pays all utilities in rent receives both # benefits. tenant_pays_utilities: false, with the heat flag omitted, places heat # and electricity in rent: 2 income points regardless of income (here $12,000, a @@ -264,3 +264,80 @@ pre_subsidy_electricity_expense: [0, 0, 0, 1_000] output: in_eap: [100, 150, 0, 100] + +- name: Case 14, size 11 income bands follow the federal adjustment beyond the printed chart. + # Section 8.3 (page 69) prints the charts through size 10 and refers larger + # households to the calculation methodology. 45 CFR 96.85 adds 3% of the four-person + # state median income for each member beyond six, so size 11 uses 52% + 5 x 16% + + # 5 x 3% = 147%: floor($107,555 x 1.47) = $158,105. The same method at 144% gives + # the printed size 10 three-month ceilings of $11,615 and $17,423 (page 70). + # Band 1 three-month ceiling: floor($158,105 x 0.30 x 3 / 12) = $11,857, so annual + # income of $47,428 ($11,857 x 4) is in band 1 and $47,432 ($11,858 x 4) in band 2. + # Band 2 three-month ceiling: floor($158,105 x 0.45 x 3 / 12) = $17,786, so annual + # income of $71,144 ($17,786 x 4) is in band 2 and $71,148 ($17,787 x 4) in band 3. + # Natural gas, single-family (pages 69-72): band 1 (9 + 3 + 1) x $25 + $125 = $450; + # band 2 (5 + 3 + 1) x $25 + $100 = $325; band 3 (2 + 3 + 1) x $25 + $50 = $200. + period: 2026 + input: + state_code: [IN, IN, IN, IN] + age: [40, 40, 40, 40] + in_eap_eligible: [true, true, true, true] + in_eap_household_size: [11, 11, 11, 11] + in_eap_income: [47_428, 47_432, 71_144, 71_148] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_000, 1_000, 1_000, 1_000] + pre_subsidy_electricity_expense: [1_000, 1_000, 1_000, 1_000] + output: + in_eap_smi: [158_105, 158_105, 158_105, 158_105] + in_eap: [450, 325, 325, 200] + +- name: Case 15, SSDI or reported SSI receipt alone makes a household vulnerable and a disability flag alone does not. + # Section 3.4 (page 26) treats a member as a person with a disability when they + # receive SSI, SSDI or another listed benefit. A disability reported without one of + # those benefits needs a doctor's statement and a pending SSA claim, which the model + # cannot identify. Section 8.6 (page 72) awards 2 points for a vulnerable member. + # No household receives an SSI payment in the model or Medicaid. + # Household 1, SSDI of $1,200 x 12 = $14,400: three-month income $3,600 is within the + # size 1 band 1 ceiling of $4,194 (page 69): (9 + 3 + 6 + 2) x $25 + $125 = $625. + # Household 2, reports SSI receipt, wages $12.00 x 780 hours = $9,360 (three-month + # income $2,340, band 1): (9 + 3 + 6 + 2) x $25 + $125 = $625. + # Household 3, disabled with no SSI, SSDI or Medicaid, wages $7.25 x 2,080 hours = + # $15,080 (three-month income $3,770, band 1): (9 + 3 + 6) x $25 + $125 = $575. + period: 2026 + input: + state_code: [IN, IN, IN] + age: [40, 40, 40] + ssi: [0, 0, 0] + social_security_disability: [14_400, 0, 0] + receives_ssi: [false, true, false] + is_disabled: [false, false, true] + receives_medicaid: [false, false, false] + employment_income: [0, 9_360, 15_080] + heating_type: [PROPANE, PROPANE, PROPANE] + bottled_gas_expense: [1_800, 1_800, 1_800] + pre_subsidy_electricity_expense: [1_200, 1_200, 1_200] + output: + in_eap_income: [14_400, 9_360, 15_080] + in_eap: [625, 625, 575] + +- name: Case 16, heat in rent with separately billed electricity and rent under one dollar a month pays only the electric benefit. + # Section 4.7 (page 32): a client with utilities included in rent must pay at least + # $1 a month in rent to receive that benefit. Page 33: when heat is in rent and the + # tenant pays the electric bill directly, the electric benefit goes to the vendor. + # Wages: $7.25 x 2,080 hours = $15,080. Three-month income $3,770 is within the size 1 + # band 1 ceiling of $4,194 (page 69), so the electric payment is $125 (page 72). + # Households 1 and 2, rent of $0 and $11 a year, below $12: no heating award, $125. + # Household 3, rent of $12 a year: heat in rent earns 2 income points (page 69) and + # no dwelling or fuel points: 2 x $25 + $125 = $175. + period: 2026 + input: + state_code: [IN, IN, IN] + age: [40, 40, 40] + employment_income: [15_080, 15_080, 15_080] + rent: [0, 11, 12] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + heat_expense_included_in_rent: [true, true, true] + pre_subsidy_electricity_expense: [1_200, 1_200, 1_200] + output: + in_eap_income: [15_080, 15_080, 15_080] + in_eap: [125, 125, 175] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml index 7a5643d2661..981055ff692 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_eligible.yaml @@ -1,5 +1,5 @@ -- name: Published annual sixty percent SMI limits, at the boundary - period: 2_026 +- name: Case 1, published annual 60% of state median income limits at the boundary. + period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] @@ -14,8 +14,8 @@ UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] output: in_eap_eligible: [true, true, true, true, true, true, true, true, true, true] -- name: Published annual sixty percent SMI limits, one dollar above - period: 2_026 +- name: Case 2, published annual 60% of state median income limits one dollar above. + period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN, IN, IN, IN, IN] age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40] @@ -30,8 +30,8 @@ UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] output: in_eap_eligible: [false, false, false, false, false, false, false, false, false, false] -- name: Federal household adjustment extends to households larger than the printed chart - period: 2_026 +- name: Case 3, federal household adjustment extends to households larger than the printed chart. + period: 2026 input: state_code: [IN, IN] age: [40, 40] @@ -45,8 +45,8 @@ heating_type: [UNSPECIFIED, UNSPECIFIED] output: in_eap_eligible: [true, false] -- name: Household eligibility requires an adult and an eligible member, independently of a utility bill - period: 2_026 +- name: Case 4, household eligibility requires an adult and an eligible member independently of a utility bill. + period: 2026 input: state_code: [IN, IN, IN] age: [17, 18, 18] @@ -61,7 +61,7 @@ output: in_eap_eligible: [false, true, false] -- name: Farm operations income puts a farm couple over the income limit +- name: Case 5, farm operations income puts a farm couple over the income limit. # Section 6.1 (pages 51-52) defines self-employment to include farming (Schedule F). # Income: $58,000 farm operations + $16,640 wages ($16.00 x 1,040 hours) = $74,640. # Size 2 SMI: floor($107,555 x 0.68) = $73,137; 60% limit floor($43,882.20) = $43,882. diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml index 866334948fc..a8873827ede 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml @@ -1,5 +1,5 @@ -- name: Existing net business income remains an approximation without a new business deduction - period: 2_026 +- name: Case 1, existing net business income remains an approximation without a new business deduction. + period: 2026 input: state_code: IN age: 40 @@ -14,8 +14,8 @@ output: # 12,000 wages + 6,000 ordinary business + 3,000 specified service business. in_eap_income: 21_000 -- name: Adult dependent secondary and college student exemptions do not extend past age twenty-three for college - period: 2_026 +- name: Case 2, adult dependent secondary and college student exemptions do not extend past age 23 for college. + period: 2026 input: state_code: [IN, IN, IN, IN] age: [18, 23, 24, 23] @@ -32,9 +32,8 @@ interest_income: [1_000, 1_000, 1_000, 1_000] output: in_eap_income: [0, 0, 16_000, 16_000] -- name: Reported Medicare premium and support paid reduce income, while TANF, support received and capital gains - are excluded - period: 2_026 +- name: Case 3, support paid reduces income while TANF, support received and capital gains are excluded. + period: 2026 input: state_code: IN age: 40 @@ -44,48 +43,49 @@ receives_medicaid: false rent: 0 employment_income: 12_000 - medicare_part_b_premiums_reported: 2_400 child_support_expense: 2_400 child_support_received: 4_000 tanf: 4_000 long_term_capital_gains: 4_000 output: - in_eap_income: 20_400 -- name: Immigration excludes an adult from size but counts earnings, and child SSA counts despite excluded child - wages - period: 2_026 + # 12_000 wages + 12_000 Social Security (gross; the Medicare premium is not + # deducted yet) + 1_200 SSI - 2_400 support paid = 22_800. + in_eap_income: 22_800 +- name: Case 4, immigration excludes an adult from size but counts earnings and child Social Security counts despite excluded child wages. + period: 2026 input: people: - adult: + person1: age: 35 immigration_status: UNDOCUMENTED employment_income: 12_000 ssi: 0 social_security: 0 - child: + person2: age: 10 employment_income: 6_000 social_security: 2_400 ssi: 1_200 spm_units: - unit: - members: [adult, child] + spm_unit: + members: [person1, person2] heating_type: UNSPECIFIED households: - home: - members: [adult, child] + household: + members: [person1, person2] state_code: IN output: in_eap_household_size: 1 in_eap_income: 15_600 in_eap_eligible: true -- name: Farm, partnership and S corporation, estate, farm rental, strike and military retirement income count +- name: Case 5, farm, partnership and S corporation, estate, farm rental, strike and pension income count. # Section 6.1 (pages 51-52, 54, 56): Schedule F farm income, Schedule E partnership # and S corporation, estate and trust, and farm rental lines, strike benefits and # pensions count. One counted adult per household, one source each: # farm operations $21,000; partnership $9,000 + S corporation $6,000 = $15,000; - # estate $4,800; farm rent $7,200; strike benefits $2,400; military retirement $18,000. + # estate $4,800; farm rent $7,200; strike benefits $2,400; a military pension of + # $18,000, reported as a taxable public pension. period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN] @@ -96,11 +96,11 @@ estate_income: [0, 0, 4_800, 0, 0, 0] farm_rent_income: [0, 0, 0, 7_200, 0, 0] strike_benefits: [0, 0, 0, 0, 2_400, 0] - military_retirement_pay: [0, 0, 0, 0, 0, 18_000] + taxable_public_pension_income: [0, 0, 0, 0, 0, 18_000] output: in_eap_income: [21_000, 15_000, 4_800, 7_200, 2_400, 18_000] -- name: Each income source is floored at zero, so a business, rental or farm loss does not offset wages +- name: Case 6, each income source is floored at zero so a business, rental or farm loss does not offset wages. # Section 6.1 (pages 51-52) counts gross business income before expenses, so a net # loss in one source cannot reduce other income. Wages: $14.00 x 2,080 hours = $29,120. # Household 1: max($29,120, 0) + max(-$15,000 self-employment, 0) = $29,120. @@ -127,7 +127,7 @@ in_eap_eligible: [true, true, true] in_eap: [200, 200, 200] -- name: Service business profits above the income limit prevent a heating award +- name: Case 7, service business profits above the income limit prevent a heating award. # Section 6.1 counts business income; a specified service business is not # exempt. Existing net profits remain the documented gross-income approximation. period: 2026 @@ -147,3 +147,19 @@ # Above the published one-person annual limit of 33,556. in_eap_eligible: false in_eap: 0 + +- name: Case 8, survivor benefits other than Social Security count as income. + # Section 6.1 (page 54) counts life insurance payments issued on a regular basis to + # a surviving household member and retirement funds paid to a surviving spouse, and + # page 53 counts Black Lung benefits awarded to a survivor. + # A widow receives a $900 monthly survivor annuity from her late husband's pension + # ($900 x 12 = $10,800) and earns $12.00 x 780 hours = $9,360. + # Income: $10,800 + $9,360 = $20,160. + period: 2026 + input: + state_code: IN + age: 58 + survivor_benefits: 10_800 + employment_income: 9_360 + output: + in_eap_income: 20_160 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml index 8885545f84d..528f63ee7fc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml @@ -1,5 +1,5 @@ -- name: Pregnancy increases household size and supplies a single vulnerability bonus - period: 2_026 +- name: Case 1, pregnancy increases household size and supplies a single vulnerability bonus. + period: 2026 input: state_code: IN age: 40 @@ -16,48 +16,48 @@ output: in_eap_household_size: 2 in_eap: 625 -- name: Young-child vulnerability stops after age five - period: 2_026 +- name: Case 2, young-child vulnerability stops after age five. + period: 2026 input: people: - adult1: + person1: age: 40 ssi: 0 social_security: 0 - child1: + person2: age: 5 ssi: 0 social_security: 0 - adult2: + person3: age: 40 ssi: 0 social_security: 0 - child2: + person4: age: 6 ssi: 0 social_security: 0 spm_units: - unit1: - members: [adult1, child1] + spm_unit1: + members: [person1, person2] heating_type: PROPANE bottled_gas_expense: 1_000 pre_subsidy_electricity_expense: 1_000 - unit2: - members: [adult2, child2] + spm_unit2: + members: [person3, person4] heating_type: PROPANE bottled_gas_expense: 1_000 pre_subsidy_electricity_expense: 1_000 households: - home1: - members: [adult1, child1] + household1: + members: [person1, person2] state_code: IN - home2: - members: [adult2, child2] + household2: + members: [person3, person4] state_code: IN output: in_eap: [625, 575] -- name: Mixed-state and over-income households receive zero - period: 2_026 +- name: Case 3, mixed-state and over-income households receive zero. + period: 2026 input: state_code: [IN, IN, IL] age: [40, 40, 40] @@ -72,30 +72,46 @@ pre_subsidy_electricity_expense: [1_000, 1_000, 1_000] output: in_eap: [450, 0, 0] -# Backfilling checks the model convention, not verified historical Indiana policy. -# 2022 uses FY2022 SMI, with the earliest available state benefit schedule. -- name: Parameter backfill uses period-specific SMI for a 2022 estimate - period: 2_022 + +# Period 2025 reads the values in force on 2025-01-01: the PY2024-25 benefit matrix +# (https://liheapch.acf.gov/docs/2025/benefits-matricies/IN_BenefitMatrix_2025.pdf#page=1) +# and the FY2025 state median income. FY2025 is not a verified year: values that the +# PY2024-25 matrix does not change are backfilled from FY2026. +- name: Case 4, period 2025 uses the PY2024-25 benefit matrix. + # PY2024-25 matrix, page 1: income points 6, 4, 2; electric benefit $100, $75, $50; + # site-built single family 3 points; bulk fuels 6 points; natural gas 0 points and + # electric 0 points; $25 per point. Page 2: "Award zero (0) points if the household + # heats with natural gas or electricity." + # Size 1 SMI: floor($103,324 x 0.52) = $53,728; 60% limit floor($32,236.80) = $32,236. + # Page 1, size 1 three-month ceilings: $4,029 (30% of SMI) and $6,044 (45% of SMI). + # Households 1 to 3 earn $12.00 x 1,040 hours = $12,480. Three-month income + # $12,480 x 3 / 12 = $3,120 is within $4,029: band 1 (6 points, $100 electric). + # Household 1, natural gas: (6 + 3 + 0) x $25 + $100 = $325. + # Household 2, propane: (6 + 3 + 6) x $25 + $100 = $475. + # Household 3, electric heat: (6 + 3 + 0) x $25 + $100 = $325. + # Household 4 earns $10.00 x 2,080 hours = $20,800. Three-month income + # $20,800 x 3 / 12 = $5,200 is above $4,029 and within $6,044: band 2 (4 points, + # $75 electric). Natural gas: (4 + 3 + 0) x $25 + $75 = $250. + period: 2025 input: - state_code: IN - age: 40 - ssi: 0 - social_security: 0 - receives_ssi: false - receives_medicaid: false - rent: 0 - employment_income: 0 - heating_type: NATURAL_GAS - gas_expense: 1_000 + state_code: [IN, IN, IN, IN] + age: [40, 40, 40, 40] + employment_income: [12_480, 12_480, 12_480, 20_800] + heating_type: [NATURAL_GAS, PROPANE, ELECTRICITY, NATURAL_GAS] + gas_expense: [1_000, 0, 0, 1_000] + bottled_gas_expense: [0, 1_800, 0, 0] + pre_subsidy_electricity_expense: [1_200, 1_200, 2_000, 1_200] output: - in_eap: 325 - in_eap_household_size: 1 - in_eap_smi: 45_020 - in_eap_eligible: true + heating_expense: [1_000, 1_800, 2_000, 1_000] + in_eap_household_size: [1, 1, 1, 1] + in_eap_smi: [53_728, 53_728, 53_728, 53_728] + in_eap_income: [12_480, 12_480, 12_480, 20_800] + in_eap_eligible: [true, true, true, true] + in_eap: [325, 475, 325, 250] # The cases below start from raw inputs: SSI, Social Security, rent, household size, # income and eligibility are computed by the model rather than supplied. -- name: Two-earner family with a four-year-old lands in the middle band from wages +- name: Case 5, two-earner family with a four-year-old lands in the middle band from wages. # Wages: $27,040 ($13.00 x 2,080 hours) + $10,400 ($10.00 x 1,040 hours) = $37,440. # No member is aged, blind or disabled, so SSI is $0; no rent is reported. # Size 3 SMI: floor($107,555 x 0.84) = $90,346; 60% limit floor($54,207.60) = $54,207. @@ -136,7 +152,7 @@ in_eap_eligible: true in_eap: 475 -- name: Single parent with full-time wages lands in the highest band +- name: Case 6, single parent with full-time wages lands in the highest band. # Wages: $17.50 x 2,080 hours = $36,400; the seven-year-old has no income. # Size 2 SMI: floor($107,555 x 0.68) = $73,137; 60% limit floor($43,882.20) = $43,882. # Three-month income: $36,400 x 3 / 12 = $9,100, above the band 2 ceiling @@ -169,26 +185,25 @@ in_eap_eligible: true in_eap: 200 -- name: Elderly widow with Social Security retirement net of Medicare Part B and a pension - # Section 6.2 (page 55) counts the Social Security check net of Medicare Part B. - # Social Security: $1,300 x 12 = $15,600 retirement; Part B $202.90 x 12 = $2,434.80; - # net $13,165.20. Pension: $500 x 12 = $6,000. Income: $19,165.20. +- name: Case 7, elderly widow with Social Security retirement and a pension. + # Section 6.1 (page 55) counts the Social Security check net of Medicare Part B. + # The premium is not deducted in the model yet, so the gross benefit is counted. + # Social Security: $1,300 x 12 = $15,600 retirement. Pension: $500 x 12 = $6,000. + # Income: $21,600. # Computed SSI: countable ($15,600 + $6,000) / 12 - $20 = $1,780 a month exceeds the # $994 federal benefit rate, so SSI is $0. # Size 1 SMI: floor($107,555 x 0.52) = $55,928; 60% limit floor($33,556.80) = $33,556. - # Three-month income: $19,165.20 x 3 / 12 = $4,791.30, above the band 1 ceiling + # Three-month income: $21,600 x 3 / 12 = $5,400, above the band 1 ceiling # floor($55,928 x 0.30 x 3 / 12) = $4,194 and within the band 2 ceiling # floor($55,928 x 0.45 x 3 / 12) = $6,291, so band 2 (5 points, $100 electric). # Points: 5 income + 3 single-family + 6 wood + 2 vulnerable (age 60 or older) = 16. # Heating 16 x $25 = $400; electric $100; total $500. period: 2026 - absolute_error_margin: 0.01 input: people: person1: age: 72 social_security_retirement: 15_600 - medicare_part_b_premiums_reported: 2_434.80 taxable_private_pension_income: 6_000 spm_units: spm_unit: @@ -206,11 +221,11 @@ heating_expense: 900 in_eap_household_size: 1 in_eap_smi: 55_928 - in_eap_income: 19_165.20 + in_eap_income: 21_600 in_eap_eligible: true in_eap: 500 -- name: Disabled part-time worker qualifies as vulnerable through computed SSI +- name: Case 8, disabled part-time worker qualifies as vulnerable through computed SSI. # The adult meets the SSI disability criteria and earns $1,000 a month ($12,000), # below the 2026 substantial gainful activity limit of $1,690 a month. # SSI countable income: ($1,000 - $20 general - $65 earned) x 0.5 = $457.50 a month. @@ -248,7 +263,7 @@ in_eap_eligible: true in_eap: 325 -- name: All utilities in rent require one dollar of monthly out-of-pocket rent computed from pre-subsidy rent +- name: Case 9, all utilities in rent require one dollar of monthly out-of-pocket rent computed from pre-subsidy rent. # Section 4.7 (pages 32-33): a tenant with utilities in rent must pay at least $1 a # month in rent, and a tenant who pays all utilities in rent receives both benefits. # Each tenant earns $11.00 x 2,080 hours = $22,880, within the size 1 limit of $33,556, diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py index 0c85668ef10..1cbf4dd7aef 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap.py @@ -8,11 +8,19 @@ class in_eap(Variable): unit = USD label = "Indiana EAP regular heating assistance" documentation = ( - "Verified for FY2026. Earlier years use model parameter backfilling " - "and are unverified historical estimates." + "Verified for FY2026. FY2025 uses the PY2024-25 benefit matrix for the " + "income points, electric payments and fuel points that differ from " + "FY2026. Its other values, and all earlier years, use model parameter " + "backfilling and are unverified historical estimates." ) defined_for = "in_eap_eligible" - reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=10,26,27,32,33,47,69,70,71,72,73,74,75,77,78" + reference = ( + # Section 8.11 (page 77) benefit formula, Sections 8.3-8.7 (pages 69-73) points + # and electric payment, Section 8.8 (pages 73-75), Sections 8.12-8.13 (pages + # 77-78), Section 1.1 (page 10), Section 3.4 (pages 26-27), Section 4.7 (pages + # 32-33) and Section 6 (page 47). + "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=77", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].ihcda.eap @@ -44,9 +52,11 @@ def formula(spm_unit, period, parameters): fuel = spm_unit("heating_type", period) fuel_points = p.benefit.fuel_points[fuel] heating_bill = spm_unit("heating_expense", period) > 0 - heating_burden = where( - heat_in_rent, rent_paid, heating_bill & (fuel_points > 0) - ) + # The fuels that receive the heating award are listed separately from the + # fuel points: the PY2024-25 matrix gave natural gas and electric heat zero + # fuel points but still paid the award on the income and dwelling points. + award_fuel = np.isin(fuel.decode_to_str(), p.benefit.heating_award_fuels) + heating_burden = where(heat_in_rent, rent_paid, heating_bill & award_fuel) income_points = select( [heat_in_rent, low, middle], [ @@ -66,7 +76,7 @@ def formula(spm_unit, period, parameters): # Disability with Medicaid receipt approximates the specified Medicaid pathways. disability = ( (person("ssi", period) > 0) - | person("receives_ssi", period) + | (add(person, period, ["receives_ssi"]) > 0) | (person("social_security_disability", period) > 0) | (person("is_disabled", period) & person("receives_medicaid", period)) ) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_dwelling_type.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_dwelling_type.py index adc7fa619f1..e094a5c4b7a 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_dwelling_type.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_dwelling_type.py @@ -20,4 +20,7 @@ class in_eap_dwelling_type(Variable): "the model assumes single-family; report the type to apply the correct " "dwelling points. Heat included in rent is reported separately." ) - reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70,71" + reference = ( + # Section 8.4 (pages 70-71). + "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=70", + ) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py index 4a25639f48d..208fe21f869 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_eligible.py @@ -7,7 +7,11 @@ class in_eap_eligible(Variable): definition_period = YEAR label = "Indiana EAP household eligibility" defined_for = StateCode.IN - reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23,29,69,70,73,74,75" + reference = ( + # Section 3.1 (page 23), Section 4.4 (page 29), Section 8.3 (pages 69-70) and + # Section 8.8 (pages 73-75). + "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].ihcda.eap @@ -18,7 +22,7 @@ def formula(spm_unit, period, parameters): # cannot be determined here. Section 8.8 separates household eligibility from # whether each utility can receive a benefit; burden is checked in in_eap. return ( - spm_unit.any(spm_unit.members("is_citizen_or_legal_immigrant", period)) + (add(spm_unit, period, ["is_citizen_or_legal_immigrant"]) > 0) & spm_unit.any(spm_unit.members("age", period) >= p.eligibility.adult_age) & (income <= limit) ) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py index fd1b6d58036..2da449ef7ba 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_household_size.py @@ -7,14 +7,19 @@ class in_eap_household_size(Variable): definition_period = YEAR label = "Indiana EAP eligible household size" defined_for = StateCode.IN - reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23,24,25,29,30" + reference = ( + # Sections 3.2-3.3 (pages 23-25) and Sections 4.4-4.5 (pages 29-30). + "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=23", + ) def formula(spm_unit, period, parameters): - # SPM units approximate the residence-based unit. Current inputs cannot identify - # all excluded foster children, exchange students, transient guests, or changes - # in residence during the three-month budget period. Citizenship is approximated - # by the existing qualified-status flag; SSN/document verification is not modeled. - # Reported pregnancies count under Section 3.2. + # SPM units approximate the residence-based unit. Section 3.2 counts roommates + # and housemates as household members even when they are unrelated, and SPM + # units place unrelated roommates in separate units. Current inputs cannot + # identify all excluded foster children, exchange students, transient guests, + # or changes in residence during the three-month budget period. Citizenship is + # approximated by the existing qualified-status flag; SSN/document verification + # is not modeled. Reported pregnancies count under Section 3.2. return add( spm_unit, period, ["is_citizen_or_legal_immigrant", "current_pregnancies"] ) diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py index 700a898ad7e..1b2fb742715 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py @@ -8,20 +8,19 @@ class in_eap_income(Variable): unit = USD label = "Indiana EAP annual countable income" defined_for = StateCode.IN - reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47,48,49,50,51,52,53,54,55,56,57,58,59,60,61" + reference = ( + # Sections 6 and 6.1 (pages 47-57) and Section 6.2 (pages 57-61). + "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=47", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].ihcda.eap person = spm_unit.members age = person("age", period) dependent = person("is_tax_unit_dependent", period) - student = ( - person("is_in_secondary_school", period) - | person("is_in_k12_school", period) - | ( - person("is_full_time_college_student", period) - & (age <= p.income.student_age_limit) - ) + student = person("is_in_secondary_school", period) | ( + person("is_full_time_college_student", period) + & (age <= p.income.student_age_limit) ) counted = (age >= p.eligibility.adult_age) & ~(dependent & student) # Use annual inputs as an approximation to the annualized preceding three months. @@ -30,22 +29,19 @@ def formula(spm_unit, period, parameters): # Schedule C line 5, Schedule F line 9 and the Schedule E rent, partnership and # S corporation, estate and trust, and farm rental lines. The existing # self-employment, farm and rental inputs are net approximations of those - # amounts: no new gross inputs or separate business/work-expense adjustments - # are introduced in this project. Each source is floored at zero, so a loss in - # one source cannot offset other counted income. + # amounts: gross inputs and separate business/work-expense adjustments are not + # modeled. Each source is floored at zero, so a loss in one source cannot + # offset other counted income. other = 0 for source in p.income.sources: other = other + max_(person(source, period), 0) other = other * counted - # Child SSA benefits count despite the general under-18 exclusion. Only reported - # Part B premiums are available to approximate the required net SSA payment; - # Part D, withholding, overpayment recovery, and exact garnishment are unavailable. - ssa = max_( - person("social_security", period) - - person("medicare_part_b_premiums_reported", period), - 0, - ) - ssa = ssa + person("ssi", period) + # Child SSA benefits count despite the general under-18 exclusion. Section 6.1 + # counts the Social Security payment net of Medicare Part B and Part D + # premiums. The premium is not deducted yet: neither medicare_part_b_premium + # nor medicare_part_b_premiums_reported is wired in. Withholding, overpayment + # recovery, and exact garnishment are also unavailable. + ssa = person("social_security", period) + person("ssi", period) # Actual support paid is deductible. Child support received, TANF, capital gains, # tax refunds, and educational assistance are excluded. Recurring versus lump-sum # receipts, royalties, protected employment, and specific VA/insurance exclusions diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py index e3a159681b4..0de3f79d516 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_smi.py @@ -9,7 +9,10 @@ class in_eap_smi(Variable): unit = USD label = "Indiana EAP household-adjusted state median income" defined_for = StateCode.IN - reference = "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69,70,72,73" + reference = ( + # Section 8.3 (pages 69-70) and Section 8.7 (pages 72-73). + "https://www.in.gov/ihcda/files/Indiana-LIHEAP-Intake-and-Operations-Program-Manual-PY2026.pdf#page=69", + ) def formula(spm_unit, period, parameters): size = spm_unit("in_eap_household_size", period) @@ -17,6 +20,4 @@ def formula(spm_unit, period, parameters): # Truncate household-adjusted 100% SMI before applying each income-band rate. # This numerical pattern reproduces all 90 published monthly, quarterly and # annual table values; the manual does not state an explicit rounding rule. - # Mississippi's base-first truncation would raise the FY2026 60% limits - # for sizes 1 and 5 by $1. Keep this ordering in state code. return where(size > 0, np.floor(smi(size, state, period, parameters)), 0) From 661fff1bc31e32804acced873adb664ad5cdef3d Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 2 Oct 2026 22:08:23 -0400 Subject: [PATCH 9/9] Deduct the Medicare Part B premium from Social Security and count military retirement pay Manual Section 6.1 counts the Social Security check net of the Medicare Part B premium, so the premium the person pays, from the existing medicare_part_b_premium variable, is subtracted; there is no Part D premium variable. military_retirement_pay is a separate input from the pension inputs that pension_income adds, so it is listed beside pension_income. Co-Authored-By: Claude Fable 5.1 --- .../states/in/ihcda/eap/income/sources.yaml | 5 +++ .../states/in/ihcda/eap/in_eap_income.yaml | 33 ++++++++++++++++--- .../gov/states/in/ihcda/eap/integration.yaml | 26 ++++++++------- .../gov/states/in/ihcda/eap/in_eap_income.py | 14 +++++--- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml index e86c12ffe0d..b2e1e413598 100644 --- a/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml +++ b/policyengine_us/parameters/gov/states/in/ihcda/eap/income/sources.yaml @@ -19,6 +19,11 @@ values: - unemployment_compensation - strike_benefits - pension_income + # Section 6.1 (pages 54-55) counts ongoing pension and retirement payments. + # Military retirement pay is a separate input from the pension inputs that + # pension_income adds, so both are listed; a household reports the amount + # in one or the other. + - military_retirement_pay # Section 6.1 (pages 54-55) and Section 6.2 (page 59) exclude lump-sum retirement # payments of the employee's contributions and interest, and withdrawals of # principal. This input cannot separate them from recurring payments, so every diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml index a8873827ede..7703a961d5b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/in_eap_income.yaml @@ -48,8 +48,9 @@ tanf: 4_000 long_term_capital_gains: 4_000 output: - # 12_000 wages + 12_000 Social Security (gross; the Medicare premium is not - # deducted yet) + 1_200 SSI - 2_400 support paid = 22_800. + # 12_000 wages + 12_000 Social Security (a 40-year-old is not enrolled in + # Medicare, so no premium is deducted) + 1_200 SSI - 2_400 support paid = + # 22_800. in_eap_income: 22_800 - name: Case 4, immigration excludes an adult from size but counts earnings and child Social Security counts despite excluded child wages. period: 2026 @@ -85,7 +86,7 @@ # pensions count. One counted adult per household, one source each: # farm operations $21,000; partnership $9,000 + S corporation $6,000 = $15,000; # estate $4,800; farm rent $7,200; strike benefits $2,400; a military pension of - # $18,000, reported as a taxable public pension. + # $18,000, reported in military_retirement_pay. period: 2026 input: state_code: [IN, IN, IN, IN, IN, IN] @@ -96,7 +97,7 @@ estate_income: [0, 0, 4_800, 0, 0, 0] farm_rent_income: [0, 0, 0, 7_200, 0, 0] strike_benefits: [0, 0, 0, 0, 2_400, 0] - taxable_public_pension_income: [0, 0, 0, 0, 0, 18_000] + military_retirement_pay: [0, 0, 0, 0, 0, 18_000] output: in_eap_income: [21_000, 15_000, 4_800, 7_200, 2_400, 18_000] @@ -163,3 +164,27 @@ employment_income: 9_360 output: in_eap_income: 20_160 + +- name: Case 9, the Medicare Part B premium is deducted from Social Security only when the person pays it. + # Section 6.1 (page 55) counts the net Social Security check after the Part B + # deduction. The 2026 standard premium is $202.90 x 12 = $2,434.80. + # Household 1: age 70, $12,000 of Social Security; countable income of + # $1,000 - $20 a month is under 135% of the poverty guideline, so a Medicare + # Savings Program covers the premium and the full $12,000 is counted. + # Household 2: age 70, $2,000 of Social Security and a $24,000 private pension; + # the premium is paid and exceeds the benefit, which is floored at zero: + # $0 + $24,000. + # Household 3: age 40 with $12,000 of Social Security disability and no + # Medicare enrollment: no premium, $12,000. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [IN, IN, IN] + age: [70, 70, 40] + social_security_retirement: [12_000, 2_000, 0] + social_security_disability: [0, 0, 12_000] + taxable_private_pension_income: [0, 24_000, 0] + ssi: [0, 0, 0] + output: + medicare_part_b_premium: [0, 2_434.8, 0] + in_eap_income: [12_000, 24_000, 12_000] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml index 528f63ee7fc..5da8ca3538f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/ihcda/eap/integration.yaml @@ -186,25 +186,28 @@ in_eap: 200 - name: Case 7, elderly widow with Social Security retirement and a pension. - # Section 6.1 (page 55) counts the Social Security check net of Medicare Part B. - # The premium is not deducted in the model yet, so the gross benefit is counted. - # Social Security: $1,300 x 12 = $15,600 retirement. Pension: $500 x 12 = $6,000. - # Income: $21,600. - # Computed SSI: countable ($15,600 + $6,000) / 12 - $20 = $1,780 a month exceeds the - # $994 federal benefit rate, so SSI is $0. + # Section 6.1 (page 55) counts the Social Security check net of the Medicare + # Part B premium. Social Security: $1,800 x 12 = $21,600 retirement. Pension: + # $5,000. The 2026 standard Part B premium is $202.90 x 12 = $2,434.80; her + # countable income ($26,600 / 12 - $20 = $2,196.67 a month) is above the + # Medicare Savings Program limit, so she pays it. + # Income: ($21,600 - $2,434.80) + $5,000 = $24,165.20. + # Computed SSI: $2,196.67 a month exceeds the $994 federal benefit rate, so SSI is $0. # Size 1 SMI: floor($107,555 x 0.52) = $55,928; 60% limit floor($33,556.80) = $33,556. - # Three-month income: $21,600 x 3 / 12 = $5,400, above the band 1 ceiling + # Three-month income: $24,165.20 x 3 / 12 = $6,041.30, above the band 1 ceiling # floor($55,928 x 0.30 x 3 / 12) = $4,194 and within the band 2 ceiling # floor($55,928 x 0.45 x 3 / 12) = $6,291, so band 2 (5 points, $100 electric). + # Counted gross, $26,600 x 3 / 12 = $6,650 would be band 3 (2 points, $50). # Points: 5 income + 3 single-family + 6 wood + 2 vulnerable (age 60 or older) = 16. # Heating 16 x $25 = $400; electric $100; total $500. period: 2026 + absolute_error_margin: 0.01 input: people: person1: age: 72 - social_security_retirement: 15_600 - taxable_private_pension_income: 6_000 + social_security_retirement: 21_600 + taxable_private_pension_income: 5_000 spm_units: spm_unit: members: [person1] @@ -216,12 +219,13 @@ members: [person1] state_code: IN output: - social_security: 15_600 + social_security: 21_600 + medicare_part_b_premium: 2_434.8 ssi: 0 heating_expense: 900 in_eap_household_size: 1 in_eap_smi: 55_928 - in_eap_income: 21_600 + in_eap_income: 24_165.2 in_eap_eligible: true in_eap: 500 diff --git a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py index 1b2fb742715..06d35943ef5 100644 --- a/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py +++ b/policyengine_us/variables/gov/states/in/ihcda/eap/in_eap_income.py @@ -37,11 +37,15 @@ def formula(spm_unit, period, parameters): other = other + max_(person(source, period), 0) other = other * counted # Child SSA benefits count despite the general under-18 exclusion. Section 6.1 - # counts the Social Security payment net of Medicare Part B and Part D - # premiums. The premium is not deducted yet: neither medicare_part_b_premium - # nor medicare_part_b_premiums_reported is wired in. Withholding, overpayment - # recovery, and exact garnishment are also unavailable. - ssa = person("social_security", period) + person("ssi", period) + # (page 55) counts the Social Security check net of the Medicare Part B and + # Part D premiums. medicare_part_b_premium is the Part B premium the person + # pays: zero when not enrolled, and excluding the share a Medicare Savings + # Program pays, which is not withheld from the check. The model has no Part D + # premium variable, so that deduction, tax withholding, overpayment recovery + # and garnishment are not modeled. + premium = person("medicare_part_b_premium", period) + social_security = max_(person("social_security", period) - premium, 0) + ssa = social_security + person("ssi", period) # Actual support paid is deductible. Child support received, TANF, capital gains, # tax refunds, and educational assistance are excluded. Recurring versus lump-sum # receipts, royalties, protected employment, and specific VA/insurance exclusions