From 157fff8fd588f457a5ea16c91bc7504c55604ffd Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 1 Oct 2026 16:24:42 -0400 Subject: [PATCH 1/9] Add New Jersey LIHEAP regular heating assistance --- changelog.d/nj-liheap.added.md | 1 + .../liheap/eligibility/max_table_size.yaml | 10 ++ .../nj/dca/liheap/eligibility/smi_rate.yaml | 12 ++ .../nj/dca/liheap/income/adult_age.yaml | 12 ++ .../income/nonqualified_member_disregard.yaml | 10 ++ .../nj/dca/liheap/income/sources/earned.yaml | 14 +++ .../dca/liheap/income/sources/unearned.yaml | 22 ++++ .../liheap/payment/amount/deliverables.yaml | 86 +++++++++++++ .../dca/liheap/payment/amount/electric.yaml | 86 +++++++++++++ .../nj/dca/liheap/payment/amount/gas.yaml | 86 +++++++++++++ .../nj/dca/liheap/payment/amount/renters.yaml | 86 +++++++++++++ .../liheap/payment/household_size_group.yaml | 27 ++++ .../nj/dca/liheap/payment/income_band.yaml | 28 +++++ .../dca/liheap/payment/regions/region_1.yaml | 29 +++++ .../dca/liheap/payment/regions/region_2.yaml | 12 ++ policyengine_us/programs.yaml | 10 +- .../eligibility/nj_liheap_eligible.yaml | 56 +++++++++ .../eligibility/nj_liheap_income_limit.yaml | 8 ++ .../income/nj_liheap_countable_income.yaml | 10 ++ .../nj_liheap_countable_income_person.yaml | 38 ++++++ .../gov/states/nj/dca/liheap/integration.yaml | 51 ++++++++ .../gov/states/nj/dca/liheap/nj_liheap.yaml | 117 ++++++++++++++++++ .../liheap/eligibility/nj_liheap_eligible.py | 35 ++++++ .../eligibility/nj_liheap_household_size.py | 15 +++ .../eligibility/nj_liheap_income_limit.py | 38 ++++++ .../income/nj_liheap_countable_income.py | 19 +++ .../nj_liheap_countable_income_person.py | 42 +++++++ .../gov/states/nj/dca/liheap/nj_liheap.py | 51 ++++++++ .../liheap/payment/nj_liheap_income_band.py | 19 +++ .../nj/dca/liheap/payment/nj_liheap_region.py | 20 +++ 30 files changed, 1049 insertions(+), 1 deletion(-) create mode 100644 changelog.d/nj-liheap.added.md create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml create mode 100644 policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py create mode 100644 policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py create mode 100644 policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py create mode 100644 policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py create mode 100644 policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py create mode 100644 policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py create mode 100644 policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py create mode 100644 policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py diff --git a/changelog.d/nj-liheap.added.md b/changelog.d/nj-liheap.added.md new file mode 100644 index 00000000000..5770adc16c0 --- /dev/null +++ b/changelog.d/nj-liheap.added.md @@ -0,0 +1 @@ +Add New Jersey LIHEAP regular heating assistance for FY2026. diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml new file mode 100644 index 00000000000..569691b11d8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml @@ -0,0 +1,10 @@ +description: New Jersey prints income limits through this household size before using a fixed monthly increment under the Low Income Home Energy Assistance Program. +values: + '2025-10-01': 12 +metadata: + unit: person + period: year + label: New Jersey LIHEAP maximum income table size + reference: + - title: FFY2026 LIHEAP and USF fact sheet, income guidelines + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml new file mode 100644 index 00000000000..c9ccc69c047 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml @@ -0,0 +1,12 @@ +description: New Jersey limits monthly income to this share of state median income under the Low Income Home Energy Assistance Program. +values: + '2025-10-01': 0.6 +metadata: + unit: /1 + period: year + label: New Jersey LIHEAP SMI rate + reference: + - title: FY2026 LIHEAP Handbook, section 2.3.A + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7 + - title: FY2026 LIHEAP State Plan, section 2.1 + href: https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=9 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml new file mode 100644 index 00000000000..687f8b64773 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml @@ -0,0 +1,12 @@ +description: New Jersey excludes child earnings and Social Security below this age under the Low Income Home Energy Assistance Program. +values: + '2025-10-01': 18 +metadata: + unit: year + period: year + label: New Jersey LIHEAP adult income age + reference: + - title: FY2026 LIHEAP Handbook, section 2.3.E + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=8,9 + - title: FY2026 LIHEAP State Plan, section 1.9 + href: https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml new file mode 100644 index 00000000000..7e60de0912b --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml @@ -0,0 +1,10 @@ +description: New Jersey excludes this much monthly income of a nonqualified member before adding the excess to household income under the Low Income Home Energy Assistance Program. +values: + '2025-10-01': 500 +metadata: + unit: currency-USD + period: month + label: New Jersey LIHEAP nonqualified member income disregard + reference: + - title: FY2026 LIHEAP Handbook + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml new file mode 100644 index 00000000000..23095509b4b --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml @@ -0,0 +1,14 @@ +description: New Jersey uses these reported earnings sources without any additional business expense deduction under the Low Income Home Energy Assistance Program. +values: + '2025-10-01': + - employment_income + - self_employment_income + - sstb_self_employment_income + - farm_operations_income +metadata: + unit: list + period: year + label: New Jersey LIHEAP earned sources + reference: + - title: FY2026 LIHEAP Handbook + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7,8,9 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml new file mode 100644 index 00000000000..14e6dd99ebe --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml @@ -0,0 +1,22 @@ +description: New Jersey counts these available unearned income sources under the Low Income Home Energy Assistance Program. +values: + '2025-10-01': + - unemployment_compensation + - strike_benefits + - ssi + - pension_income + - general_assistance + - rental_income + - alimony_income + - child_support_received + - interest_income + - dividend_income + - workers_compensation + - disability_benefits +metadata: + unit: list + period: year + label: New Jersey LIHEAP unearned sources + reference: + - title: FY2026 LIHEAP Handbook + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7,8,9,10 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml new file mode 100644 index 00000000000..2de040b204f --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml @@ -0,0 +1,86 @@ +description: New Jersey pays this annual regular heating benefit in the deliverables panel under the Low Income Home Energy Assistance Program, by county region, monthly income band and household size group. +'1': + 1: + 1: + '2025-10-01': 641 + 2: + '2025-10-01': 859 + 3: + '2025-10-01': 1025 + 4: + '2025-10-01': 1128 + 2: + 1: + '2025-10-01': 535 + 2: + '2025-10-01': 715 + 3: + '2025-10-01': 855 + 4: + '2025-10-01': 941 + 3: + 1: + '2025-10-01': 428 + 2: + '2025-10-01': 573 + 3: + '2025-10-01': 685 + 4: + '2025-10-01': 754 + 4: + 1: + '2025-10-01': 321 + 2: + '2025-10-01': 428 + 3: + '2025-10-01': 513 + 4: + '2025-10-01': 564 +'2': + 1: + 1: + '2025-10-01': 961 + 2: + '2025-10-01': 983 + 3: + '2025-10-01': 1162 + 4: + '2025-10-01': 1278 + 2: + 1: + '2025-10-01': 613 + 2: + '2025-10-01': 820 + 3: + '2025-10-01': 979 + 4: + '2025-10-01': 1077 + 3: + 1: + '2025-10-01': 491 + 2: + '2025-10-01': 657 + 3: + '2025-10-01': 784 + 4: + '2025-10-01': 862 + 4: + 1: + '2025-10-01': 366 + 2: + '2025-10-01': 493 + 3: + '2025-10-01': 587 + 4: + '2025-10-01': 646 +metadata: + unit: currency-USD + period: year + label: New Jersey LIHEAP deliverables payment + breakdown: + - range(1, 3) + - range(1, 5) + - range(1, 5) + reference: + - title: FY2026 heating benefit grid + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml new file mode 100644 index 00000000000..6d76b745c17 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml @@ -0,0 +1,86 @@ +description: New Jersey pays this annual regular heating benefit in the electric panel under the Low Income Home Energy Assistance Program, by county region, monthly income band and household size group. +'1': + 1: + 1: + '2025-10-01': 529 + 2: + '2025-10-01': 710 + 3: + '2025-10-01': 846 + 4: + '2025-10-01': 931 + 2: + 1: + '2025-10-01': 442 + 2: + '2025-10-01': 591 + 3: + '2025-10-01': 705 + 4: + '2025-10-01': 776 + 3: + 1: + '2025-10-01': 352 + 2: + '2025-10-01': 473 + 3: + '2025-10-01': 564 + 4: + '2025-10-01': 620 + 4: + 1: + '2025-10-01': 265 + 2: + '2025-10-01': 354 + 3: + '2025-10-01': 424 + 4: + '2025-10-01': 466 +'2': + 1: + 1: + '2025-10-01': 606 + 2: + '2025-10-01': 821 + 3: + '2025-10-01': 970 + 4: + '2025-10-01': 1067 + 2: + 1: + '2025-10-01': 506 + 2: + '2025-10-01': 675 + 3: + '2025-10-01': 807 + 4: + '2025-10-01': 888 + 3: + 1: + '2025-10-01': 404 + 2: + '2025-10-01': 541 + 3: + '2025-10-01': 646 + 4: + '2025-10-01': 711 + 4: + 1: + '2025-10-01': 304 + 2: + '2025-10-01': 406 + 3: + '2025-10-01': 485 + 4: + '2025-10-01': 534 +metadata: + unit: currency-USD + period: year + label: New Jersey LIHEAP electric payment + breakdown: + - range(1, 3) + - range(1, 5) + - range(1, 5) + reference: + - title: FY2026 heating benefit grid + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml new file mode 100644 index 00000000000..13e898c4667 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml @@ -0,0 +1,86 @@ +description: New Jersey pays this annual regular heating benefit in the gas panel under the Low Income Home Energy Assistance Program, by county region, monthly income band and household size group. +'1': + 1: + 1: + '2025-10-01': 334 + 2: + '2025-10-01': 448 + 3: + '2025-10-01': 535 + 4: + '2025-10-01': 589 + 2: + 1: + '2025-10-01': 278 + 2: + '2025-10-01': 373 + 3: + '2025-10-01': 446 + 4: + '2025-10-01': 491 + 3: + 1: + '2025-10-01': 222 + 2: + '2025-10-01': 298 + 3: + '2025-10-01': 355 + 4: + '2025-10-01': 391 + 4: + 1: + '2025-10-01': 167 + 2: + '2025-10-01': 224 + 3: + '2025-10-01': 267 + 4: + '2025-10-01': 294 +'2': + 1: + 1: + '2025-10-01': 383 + 2: + '2025-10-01': 512 + 3: + '2025-10-01': 612 + 4: + '2025-10-01': 673 + 2: + 1: + '2025-10-01': 318 + 2: + '2025-10-01': 427 + 3: + '2025-10-01': 509 + 4: + '2025-10-01': 560 + 3: + 1: + '2025-10-01': 254 + 2: + '2025-10-01': 341 + 3: + '2025-10-01': 408 + 4: + '2025-10-01': 445 + 4: + 1: + '2025-10-01': 191 + 2: + '2025-10-01': 256 + 3: + '2025-10-01': 306 + 4: + '2025-10-01': 337 +metadata: + unit: currency-USD + period: year + label: New Jersey LIHEAP gas payment + breakdown: + - range(1, 3) + - range(1, 5) + - range(1, 5) + reference: + - title: FY2026 heating benefit grid + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml new file mode 100644 index 00000000000..197236bb0ae --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml @@ -0,0 +1,86 @@ +description: New Jersey pays this annual regular heating benefit in the renters panel under the Low Income Home Energy Assistance Program, by county region, monthly income band and household size group. +'1': + 1: + 1: + '2025-10-01': 234 + 2: + '2025-10-01': 312 + 3: + '2025-10-01': 374 + 4: + '2025-10-01': 411 + 2: + 1: + '2025-10-01': 196 + 2: + '2025-10-01': 262 + 3: + '2025-10-01': 312 + 4: + '2025-10-01': 343 + 3: + 1: + '2025-10-01': 156 + 2: + '2025-10-01': 208 + 3: + '2025-10-01': 250 + 4: + '2025-10-01': 275 + 4: + 1: + '2025-10-01': 118 + 2: + '2025-10-01': 157 + 3: + '2025-10-01': 186 + 4: + '2025-10-01': 205 +'2': + 1: + 1: + '2025-10-01': 267 + 2: + '2025-10-01': 360 + 3: + '2025-10-01': 428 + 4: + '2025-10-01': 471 + 2: + 1: + '2025-10-01': 222 + 2: + '2025-10-01': 299 + 3: + '2025-10-01': 358 + 4: + '2025-10-01': 394 + 3: + 1: + '2025-10-01': 179 + 2: + '2025-10-01': 240 + 3: + '2025-10-01': 286 + 4: + '2025-10-01': 315 + 4: + 1: + '2025-10-01': 134 + 2: + '2025-10-01': 179 + 3: + '2025-10-01': 216 + 4: + '2025-10-01': 238 +metadata: + unit: currency-USD + period: year + label: New Jersey LIHEAP renters payment + breakdown: + - range(1, 3) + - range(1, 5) + - range(1, 5) + reference: + - title: FY2026 heating benefit grid + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml new file mode 100644 index 00000000000..416276d94ea --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml @@ -0,0 +1,27 @@ +description: New Jersey uses these household size group boundaries under the Low Income Home Energy Assistance Program. +brackets: +- threshold: + '2025-10-01': 1 + amount: + '2025-10-01': 1 +- threshold: + '2025-10-01': 5 + amount: + '2025-10-01': 2 +- threshold: + '2025-10-01': 9 + amount: + '2025-10-01': 3 +- threshold: + '2025-10-01': 13 + amount: + '2025-10-01': 4 +metadata: + type: single_amount + threshold_unit: person + amount_unit: /1 + period: year + label: New Jersey LIHEAP household size group + reference: + - title: FY2026 heating benefit grid + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml new file mode 100644 index 00000000000..ea8c847acd1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml @@ -0,0 +1,28 @@ +# The first three published income rows have identical payments and are combined. +description: New Jersey uses these monthly income band boundaries under the Low Income Home Energy Assistance Program. +brackets: +- threshold: + '2025-10-01': 0 + amount: + '2025-10-01': 1 +- threshold: + '2025-10-01': 6440 + amount: + '2025-10-01': 2 +- threshold: + '2025-10-01': 8887 + amount: + '2025-10-01': 3 +- threshold: + '2025-10-01': 9660 + amount: + '2025-10-01': 4 +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + period: month + label: New Jersey LIHEAP monthly income band + reference: + - title: FY2026 heating benefit grid + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml new file mode 100644 index 00000000000..ed3ef109b3f --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml @@ -0,0 +1,29 @@ +description: New Jersey assigns these counties to payment region 1 under the Low Income Home Energy Assistance Program. +values: + '2025-10-01': + - ATLANTIC_COUNTY_NJ + - BERGEN_COUNTY_NJ + - BURLINGTON_COUNTY_NJ + - CAMDEN_COUNTY_NJ + - CAPE_MAY_COUNTY_NJ + - CUMBERLAND_COUNTY_NJ + - ESSEX_COUNTY_NJ + - GLOUCESTER_COUNTY_NJ + - HUDSON_COUNTY_NJ + - HUNTERDON_COUNTY_NJ + - MERCER_COUNTY_NJ + - MIDDLESEX_COUNTY_NJ + - MONMOUTH_COUNTY_NJ + - MORRIS_COUNTY_NJ + - OCEAN_COUNTY_NJ + - PASSAIC_COUNTY_NJ + - SALEM_COUNTY_NJ + - SOMERSET_COUNTY_NJ + - UNION_COUNTY_NJ +metadata: + unit: list + period: year + label: New Jersey LIHEAP region 1 counties + reference: + - title: FY2026 heating benefit grid, county headings + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml new file mode 100644 index 00000000000..c32709f28c5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml @@ -0,0 +1,12 @@ +description: New Jersey assigns these counties to payment region 2 under the Low Income Home Energy Assistance Program. +values: + '2025-10-01': + - SUSSEX_COUNTY_NJ + - WARREN_COUNTY_NJ +metadata: + unit: list + period: year + label: New Jersey LIHEAP region 2 counties + reference: + - title: FY2026 heating benefit grid, county headings + href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 81c10bc47b6..b0945c606ec 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -802,8 +802,16 @@ programs: category: Benefits agency: HHS status: partial - coverage: OR, DC, Riverside County, MA, IL, TX + coverage: OR, DC, Riverside County, MA, IL, TX, NJ state_implementations: + - state: NJ + status: partial + name: New Jersey LIHEAP + full_name: New Jersey Low Income Home Energy Assistance Program + variable: nj_liheap + parameter_prefix: gov.states.nj.dca.liheap + verified_years: "2026" + notes: Regular heating with qualified-member size, the FY2026 handbook income rules, published monthly SMI limits and county/fuel/income/size grid. Current handbook choices differ from older codified threshold, disregard and subsidized-direct-payer rules. Striker/institution exclusions, landlord fuel charges, special income and complete subsidy coverage remain unsupported. Earlier years are unverified backfilled estimates. - state: OR status: in_progress name: LIHEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml new file mode 100644 index 00000000000..5fe5cf619af --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml @@ -0,0 +1,56 @@ +- name: Income limit does not disappear for SNAP recipients + period: 2026 + input: + state_code: [NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_countable_income: [50004, 50016] + has_heating_expense: [true, true] + heating_type: [NATURAL_GAS, NATURAL_GAS] + snap: [100, 100] + output: + nj_liheap_eligible: [true, false] +- name: Heat included in subsidized rent remains ineligible even with a reported bill + period: 2026 + input: + state_code: [NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_countable_income: [0, 0] + has_heating_expense: [true, true] + heating_type: [NATURAL_GAS, NATURAL_GAS] + heat_expense_included_in_rent: [true, true] + receives_housing_assistance: [false, true] + output: + nj_liheap_eligible: [true, false] +- name: A wholly dependent student household is excluded + period: 2026 + input: + state_code: NJ + county: ESSEX_COUNTY_NJ + nj_liheap_countable_income: 0 + has_heating_expense: true + heating_type: NATURAL_GAS + is_full_time_student: true + is_tax_unit_dependent: true + output: + nj_liheap_eligible: false +- name: Unknown county cannot select a benefit region + period: 2026 + input: + state_code: NJ + county: UNKNOWN + nj_liheap_countable_income: 0 + has_heating_expense: true + heating_type: NATURAL_GAS + output: + nj_liheap_eligible: false +- name: No heat responsibility, no qualified members, and other states are excluded + period: 2026 + input: + state_code: [NJ, NJ, NY] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_countable_income: [0, 0, 0] + has_heating_expense: [false, true, true] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [CITIZEN, UNDOCUMENTED, CITIZEN] + output: + nj_liheap_eligible: [false, false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml new file mode 100644 index 00000000000..1c78c01afec --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml @@ -0,0 +1,8 @@ +- name: All published monthly limits and the stated additional-person increment + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + nj_liheap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] + output: + nj_liheap_income_limit: [50004, 65388, 80784, 96168, 111552, 126936, 129828, 132708, 135588, 138480, 141360, 144252, 147144, 150036] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml new file mode 100644 index 00000000000..0a6a718fec9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml @@ -0,0 +1,10 @@ +# 11,196 is monthly 933; 11,202 / 12 = 933.5 rounds up to 934. +- name: Monthly household income rounds half up after TANF is added once + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS] + state_code: [NJ, NJ] + nj_liheap_countable_income_person: [10001, 10002] + nj_wfnj: [1200, 1200] + output: + nj_liheap_countable_income: [11196, 11208] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml new file mode 100644 index 00000000000..4c01a912a99 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml @@ -0,0 +1,38 @@ +- name: Child and student earnings are excluded while adult earnings and net business income count + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NJ, NJ, NJ, NJ] + age: [17, 20, 20, 40] + spm_unit_size: [1, 2, 1, 1] + is_full_time_student: [false, true, true, false] + employment_income: [12000, 12000, 12000, 12000] + self_employment_income: [1000, 1000, 1000, -1000] + sstb_self_employment_income: [600, 600, 600, 600] + farm_operations_income: [1200, 1200, 1200, 1200] + ssi: [0, 0, 0, 0] + output: + nj_liheap_countable_income_person: [0, 0, 14800, 13800] +- name: Children social security is excluded and adults deduct paid Part B premiums + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NJ, NJ, NJ] + age: [17, 40, 40] + social_security: [12000, 12000, 12000] + medicare_part_b_premium: [0, 1200, 0] + ssi: [600, 600, 600] + veterans_benefits: [5000, 5000, 5000] + output: + nj_liheap_countable_income_person: [600, 11400, 12600] +- name: Each excluded member has the handbook monthly disregard + period: 2026 + input: + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NJ, NJ, NJ] + age: [40, 40, 40] + immigration_status: [UNDOCUMENTED, UNDOCUMENTED, UNDOCUMENTED] + employment_income: [5000, 6000, 7200] + ssi: [0, 0, 0] + output: + nj_liheap_countable_income_person: [0, 0, 1200] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml new file mode 100644 index 00000000000..f8ef7b31175 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml @@ -0,0 +1,51 @@ +- name: Mixed-status household counts the nonqualified adult income only above the disregard + period: 2026 + input: + people: + adult: + age: 40 + employment_income: 18000 + immigration_status: UNDOCUMENTED + ssi: 0 + child: + age: 5 + ssi: 0 + spm_units: + unit: + members: + - adult + - child + nj_wfnj: 0 + heating_type: FUEL_OIL + fuel_oil_expense: 1 + households: + home: + members: + - adult + - child + state_code: NJ + county: SUSSEX_COUNTY_NJ + output: + nj_liheap_household_size: 1 + nj_liheap_countable_income_person: [12000, 0] + nj_liheap_countable_income: 12000 + nj_liheap_income_limit: 50004 + nj_liheap_income_band: 1 + nj_liheap_region: 2 + nj_liheap_eligible: true + nj_liheap: 961 +- name: An unsubsidized rent-included household receives the renter schedule without fuel information + period: 2026 + input: + state_code: NJ + county: ESSEX_COUNTY_NJ + nj_liheap_countable_income: 12000 + has_heating_expense: false + heating_type: UNSPECIFIED + age: 40 + employment_income: 12000 + ssi: 0 + nj_wfnj: 0 + heat_expense_included_in_rent: true + output: + nj_liheap: 234 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml new file mode 100644 index 00000000000..df1852cadb8 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml @@ -0,0 +1,117 @@ +- name: Published Deliverables payments in All Other (19) counties for every distinct income band and size group + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + heating_type: [FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL] + heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] + output: + nj_liheap: [641, 859, 1025, 1128, 535, 715, 855, 941, 428, 573, 685, 754, 321, 428, 513, 564] +- name: Published Deliverables payments in Warren & Sussex Counties for every distinct income band and size group + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + heating_type: [FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL] + heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] + output: + nj_liheap: [961, 983, 1162, 1278, 613, 820, 979, 1077, 491, 657, 784, 862, 366, 493, 587, 646] +- name: Published Electric payments in All Other (19) counties for every distinct income band and size group + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] + heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] + output: + nj_liheap: [529, 710, 846, 931, 442, 591, 705, 776, 352, 473, 564, 620, 265, 354, 424, 466] +- name: Published Electric payments in Warren & Sussex Counties for every distinct income band and size group + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] + heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] + output: + nj_liheap: [606, 821, 970, 1067, 506, 675, 807, 888, 404, 541, 646, 711, 304, 406, 485, 534] +- name: Published Gas payments in All Other (19) counties for every distinct income band and size group + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] + output: + nj_liheap: [334, 448, 535, 589, 278, 373, 446, 491, 222, 298, 355, 391, 167, 224, 267, 294] +- name: Published Gas payments in Warren & Sussex Counties for every distinct income band and size group + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] + output: + nj_liheap: [383, 512, 612, 673, 318, 427, 509, 560, 254, 341, 408, 445, 191, 256, 306, 337] +- name: Published Renters payments in All Other (19) counties for every distinct income band and size group + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + output: + nj_liheap: [234, 312, 374, 411, 196, 262, 312, 343, 156, 208, 250, 275, 118, 157, 186, 205] +- name: Published Renters payments in Warren & Sussex Counties for every distinct income band and size group + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] + heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] + output: + nj_liheap: [267, 360, 428, 471, 222, 299, 358, 394, 179, 240, 286, 315, 134, 179, 216, 238] +- name: All published heating fuels map to their panel + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_countable_income: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + heating_type: [ELECTRICITY, NATURAL_GAS, FUEL_OIL, KEROSENE, PROPANE, WOOD, COAL, SOLAR, OTHER, UNSPECIFIED, NONE] + output: + nj_liheap: [529, 334, 641, 641, 641, 641, 641, 0, 0, 0, 0] +- name: Income bands preserve the printed boundary dollars + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true] + nj_liheap_household_size: [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + nj_liheap_countable_income: [0, 12000, 12012, 24000, 24012, 77268, 77280, 106632, 106644, 115908, 115920] + output: + nj_liheap: [334, 334, 334, 334, 334, 334, 278, 278, 222, 222, 167] diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py new file mode 100644 index 00000000000..ab2a6bb97b0 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py @@ -0,0 +1,35 @@ +from policyengine_us.model_api import * + + +class nj_liheap_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "New Jersey LIHEAP regular heating eligibility" + defined_for = StateCode.NJ + reference = ( + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5,6,7,11,12", + ) + documentation = "Automatic enrollment does not waive the income test, and regular heating has no asset test. Striker and institutional-residence exclusions, full utility-allowance coverage and payments by people outside the household need inputs not available here. Unknown county is unsupported, not a legal denial." + + def formula(spm_unit, period, parameters): + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + subsidized = spm_unit( + "receives_housing_assistance", period + ) | spm_unit.household("is_in_public_housing", period) + person = spm_unit.members + dependent_students_only = spm_unit.all( + person("is_full_time_student", period) + & person("is_tax_unit_dependent", period) + ) + return ( + (spm_unit("has_heating_expense", period) | heat_in_rent) + & ~(heat_in_rent & subsidized) + & ~dependent_students_only + & (spm_unit("nj_liheap_household_size", period) > 0) + & (spm_unit("nj_liheap_region", period) > 0) + & ( + spm_unit("nj_liheap_countable_income", period) + <= spm_unit("nj_liheap_income_limit", period) + ) + ) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py new file mode 100644 index 00000000000..ea2c792aaff --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class nj_liheap_household_size(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "New Jersey LIHEAP qualified household size" + defined_for = StateCode.NJ + reference = ( + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5,6,10", + ) + documentation = "Qualified SPM members approximate the economic household. The federal qualified-noncitizen indicator is used without SNAP-specific bars. Foster residents, tax-dependent students away at school, and separate roomer/boarder households require correct SPM membership; not all protected immigration statuses have an enum choice." + + adds = ["is_citizen_or_legal_immigrant"] diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py new file mode 100644 index 00000000000..9866b08c21d --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py @@ -0,0 +1,38 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class nj_liheap_income_limit(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "New Jersey LIHEAP annualized income limit" + unit = USD + defined_for = StateCode.NJ + reference = ( + "https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2", + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", + ) + documentation = "FY2026 handbook and published limits use 60% SMI rather than the older codified 175%-FPG ceiling. Annualized monthly limits control this monthly-income eligibility test." + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.nj.dca.liheap.eligibility + size = max_(spm_unit("nj_liheap_household_size", period), 1) + capped_size = min_(size, p.max_table_size) + state = spm_unit.household("state_code_str", period) + smi_parameters = parameters(period).gov.hhs.smi + base = smi_parameters.amount[state] + factor = smi(capped_size, state, period, parameters) / base + # Inferred two-stage flooring reproduces all 12 annual limits; + # their monthly column uses half-up rounding (not half-to-even). + annual = np.floor(factor * np.floor(base * p.smi_rate)) + monthly = np.floor(annual / MONTHS_IN_YEAR + 0.5) + # The published monthly increment is rounded up separately. Applying + # the size factor to the whole household would miss the 13+ rows. + step = np.ceil( + base + * p.smi_rate + * smi_parameters.household_size_adjustment.additional_person + / MONTHS_IN_YEAR + ) + return (monthly + max_(size - p.max_table_size, 0) * step) * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py new file mode 100644 index 00000000000..3d252bdd38c --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class nj_liheap_countable_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "New Jersey LIHEAP annualized household income" + unit = USD + defined_for = StateCode.NJ + reference = ( + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6,9,10", + ) + documentation = "Annual inputs approximate the four-week verification period. The summed monthly income is rounded to the nearest dollar, with half dollars rounded up. WFNJ benefits are counted once at the unit level; rental income is assumed nonnegative." + + def formula(spm_unit, period, parameters): + # WFNJ paid for eligible household members is counted once, in full. + income = add(spm_unit, period, ["nj_liheap_countable_income_person", "nj_wfnj"]) + return np.floor(max_(income, 0) / MONTHS_IN_YEAR + 0.5) * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py new file mode 100644 index 00000000000..ff617502299 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py @@ -0,0 +1,42 @@ +from policyengine_us.model_api import * + + +class nj_liheap_countable_income_person(Variable): + value_type = float + entity = Person + definition_period = YEAR + label = "New Jersey LIHEAP countable income per person" + unit = USD + defined_for = StateCode.NJ + reference = ( + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6,7,8,9,10", + ) + documentation = "Uses existing net self-employment inputs without extra deductions; flooring losses is a modeling convention. Child earnings follow the FY2026 plan. Social Security of children and documented veterans benefits are excluded by the handbook. SSI Lifeline supplements, gifts, foster payments, royalties and roomer receipts cannot be separately identified. The handbook uses a $500 monthly nonqualified-member disregard where older codified text says $268." + + def formula(person, period, parameters): + p = parameters(period).gov.states.nj.dca.liheap.income + earned = 0 + for source in p.sources.earned: + earned = earned + max_(person(source, period), 0) + adult = person("age", period) >= p.adult_age + student_in_larger_household = person("is_full_time_student", period) & ( + person.spm_unit("spm_unit_size", period) > 1 + ) + earned = where(adult & ~student_in_larger_household, earned, 0) + social_security = where( + adult, + max_( + person("social_security", period) + - person("medicare_part_b_premium", period), + 0, + ), + 0, + ) + income = earned + social_security + add(person, period, p.sources.unearned) + qualified = person("is_citizen_or_legal_immigrant", period) + # Read the handbook's singular-member rule as a per-person disregard. + return where( + qualified, + income, + max_(income - p.nonqualified_member_disregard * MONTHS_IN_YEAR, 0), + ) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py new file mode 100644 index 00000000000..934af69c957 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py @@ -0,0 +1,51 @@ +from policyengine_us.model_api import * + + +class nj_liheap(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + label = "New Jersey LIHEAP regular heating benefit" + unit = USD + defined_for = "nj_liheap_eligible" + reference = ( + "https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf", + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7,12,17,18", + "https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=9,10", + ) + documentation = "Annual regular heating payment, verified for FY2026. Earlier years use backfilled parameters and are unverified historical estimates. Amounts preserve all published grid anomalies; no expense cap applies. Unknown/unsupported direct fuels return zero. Separate fuel charges paid to landlords cannot be distinguished from vendor bills without a direct benefit override. Crisis, cooling, furnace and utility-program benefits are excluded." + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.nj.dca.liheap.payment + region = max_(spm_unit("nj_liheap_region", period), 1) + size = p.household_size_group.calc( + max_(spm_unit("nj_liheap_household_size", period), 1) + ) + band = spm_unit("nj_liheap_income_band", period) + fuel = spm_unit("heating_type", period) + types = fuel.possible_values + deliverable = ( + (fuel == types.FUEL_OIL) + | (fuel == types.KEROSENE) + | (fuel == types.PROPANE) + | (fuel == types.WOOD) + | (fuel == types.COAL) + ) + # FY2026 handbook 3.2.F assigns direct payers by their heating fuel. + # The older codified renter-level rule for subsidized direct payers + # differs; this draft follows the current operating handbook. + return select( + [ + spm_unit("heat_expense_included_in_rent", period), + fuel == types.ELECTRICITY, + fuel == types.NATURAL_GAS, + deliverable, + ], + [ + p.amount.renters[region][band][size], + p.amount.electric[region][band][size], + p.amount.gas[region][band][size], + p.amount.deliverables[region][band][size], + ], + default=0, + ) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py new file mode 100644 index 00000000000..d27f4af6637 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class nj_liheap_income_band(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "New Jersey LIHEAP payment income band" + defined_for = StateCode.NJ + reference = ( + "https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf", + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7,9,12", + ) + documentation = "The grid does not label the income period; monthly follows the handbook income test and the historical monthly thresholds used in the grid. Three identical initial rows are combined." + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.nj.dca.liheap.payment + monthly = spm_unit("nj_liheap_countable_income", period) / MONTHS_IN_YEAR + return p.income_band.calc(max_(monthly, 0)) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py new file mode 100644 index 00000000000..70453bd77c2 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class nj_liheap_region(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "New Jersey LIHEAP payment region" + defined_for = StateCode.NJ + reference = ("https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf",) + documentation = "Region 2 is Warren/Sussex; region 1 is the other nineteen counties. Zero means a county is unknown or outside New Jersey." + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.nj.dca.liheap.payment.regions + county = spm_unit.household("county_str", period) + return select( + [np.isin(county, p.region_1), np.isin(county, p.region_2)], + [1, 2], + default=0, + ) From 2635c28783e88a33ecb5f9d5c2bd531c956d003d Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 2 Oct 2026 12:14:52 -0400 Subject: [PATCH 2/9] Document current New Jersey LIHEAP regulatory conflict --- .../nj/dca/liheap/eligibility/nj_liheap_income_limit.py | 3 ++- .../variables/gov/states/nj/dca/liheap/nj_liheap.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py index 9866b08c21d..4c83073d78d 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py @@ -12,8 +12,9 @@ class nj_liheap_income_limit(Variable): reference = ( "https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2", "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", + "https://www.nj.gov/dca/hmfa/about/regulations/docs/noticeofadoption10.20.25njr.pdf#page=6", ) - documentation = "FY2026 handbook and published limits use 60% SMI rather than the older codified 175%-FPG ceiling. Annualized monthly limits control this monthly-income eligibility test." + documentation = "FY2026 handbook and published limits use 60% SMI rather than the codified 175%-FPG ceiling. Chapter 5:49 was readopted without change effective September 22, 2025; its 2017 expiration does not resolve this conflict. This draft follows the operating handbook while legal reconciliation remains open. Annualized monthly limits control this monthly-income eligibility test." def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nj.dca.liheap.eligibility diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py index 934af69c957..7f5a639117d 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py @@ -32,8 +32,8 @@ def formula(spm_unit, period, parameters): | (fuel == types.COAL) ) # FY2026 handbook 3.2.F assigns direct payers by their heating fuel. - # The older codified renter-level rule for subsidized direct payers - # differs; this draft follows the current operating handbook. + # The codified renter-level rule for subsidized direct payers differs. + # Chapter 5:49 was readopted in 2025; the conflict remains unresolved. return select( [ spm_unit("heat_expense_included_in_rent", period), From 3b7e373fa55f0f3057f30a419a69e1cfc41a3f1e Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 2 Oct 2026 12:56:44 -0400 Subject: [PATCH 3/9] Align New Jersey LIHEAP income and coverage conventions --- .../states/nj/dca/liheap/income/adult_age.yaml | 4 ++-- .../nj/dca/liheap/income/sources/earned.yaml | 4 ++-- .../nj/dca/liheap/income/sources/unearned.yaml | 6 +++--- policyengine_us/programs.yaml | 2 +- .../liheap/eligibility/nj_liheap_eligible.yaml | 5 +++-- .../income/nj_liheap_countable_income.yaml | 14 +++++++++++++- .../nj_liheap_countable_income_person.yaml | 4 ++-- .../gov/states/nj/dca/liheap/integration.yaml | 4 ++-- .../liheap/eligibility/nj_liheap_eligible.py | 4 ++-- .../eligibility/nj_liheap_household_size.py | 3 ++- .../income/nj_liheap_countable_income.py | 8 +++++--- .../nj_liheap_countable_income_person.py | 18 +++++++----------- .../gov/states/nj/dca/liheap/nj_liheap.py | 10 +++++++--- .../liheap/payment/nj_liheap_income_band.py | 3 ++- 14 files changed, 53 insertions(+), 36 deletions(-) diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml index 687f8b64773..a35f9160a9f 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml @@ -6,7 +6,7 @@ metadata: period: year label: New Jersey LIHEAP adult income age reference: - - title: FY2026 LIHEAP Handbook, section 2.3.E - href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=8,9 + - title: FY2026 LIHEAP Handbook, section 2.3.E, PDF pages 8, 9 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=8 - title: FY2026 LIHEAP State Plan, section 1.9 href: https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml index 23095509b4b..702e3e92813 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml @@ -10,5 +10,5 @@ metadata: period: year label: New Jersey LIHEAP earned sources reference: - - title: FY2026 LIHEAP Handbook - href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7,8,9 + - title: FY2026 LIHEAP Handbook, PDF pages 7, 8, 9 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml index 14e6dd99ebe..7e546899d5e 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml @@ -10,7 +10,7 @@ values: - alimony_income - child_support_received - interest_income - - dividend_income + - ordinary_dividend_income - workers_compensation - disability_benefits metadata: @@ -18,5 +18,5 @@ metadata: period: year label: New Jersey LIHEAP unearned sources reference: - - title: FY2026 LIHEAP Handbook - href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7,8,9,10 + - title: FY2026 LIHEAP Handbook, PDF pages 7, 8, 9, 10 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index b0945c606ec..444ed883738 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -811,7 +811,7 @@ programs: variable: nj_liheap parameter_prefix: gov.states.nj.dca.liheap verified_years: "2026" - notes: Regular heating with qualified-member size, the FY2026 handbook income rules, published monthly SMI limits and county/fuel/income/size grid. Current handbook choices differ from older codified threshold, disregard and subsidized-direct-payer rules. Striker/institution exclusions, landlord fuel charges, special income and complete subsidy coverage remain unsupported. Earlier years are unverified backfilled estimates. + notes: Regular heating under the FY2026 operating handbook and payment matrix. Conflicts with the readopted regulation and some income/housing rules remain unresolved; earlier years are unverified estimates. - state: OR status: in_progress name: LIHEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml index 5fe5cf619af..39ead6d442e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml @@ -33,7 +33,7 @@ is_tax_unit_dependent: true output: nj_liheap_eligible: false -- name: Unknown county cannot select a benefit region +- name: Unknown county leaves payment unsupported without denying legal eligibility period: 2026 input: state_code: NJ @@ -42,7 +42,8 @@ has_heating_expense: true heating_type: NATURAL_GAS output: - nj_liheap_eligible: false + nj_liheap_eligible: true + nj_liheap: 0 - name: No heat responsibility, no qualified members, and other states are excluded period: 2026 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml index 0a6a718fec9..1f5c6d4b5c3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml @@ -5,6 +5,18 @@ heating_type: [NATURAL_GAS, NATURAL_GAS] state_code: [NJ, NJ] nj_liheap_countable_income_person: [10001, 10002] - nj_wfnj: [1200, 1200] + tanf: [1200, 1200] output: nj_liheap_countable_income: [11196, 11208] + +- name: State cash entitlement counts only when TANF is taken up + period: 2026 + input: + state_code: [NJ, NJ] + heating_type: [NATURAL_GAS, NATURAL_GAS] + age: [40, 40] + nj_wfnj: [1200, 1200] + takes_up_tanf_if_eligible: [false, true] + ssi: [0, 0] + output: + nj_liheap_countable_income: [0, 1200] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml index 4c01a912a99..eb1ba2a74fd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml @@ -13,7 +13,7 @@ ssi: [0, 0, 0, 0] output: nj_liheap_countable_income_person: [0, 0, 14800, 13800] -- name: Children social security is excluded and adults deduct paid Part B premiums +- name: Child Social Security is excluded and adult Medicare deductions remain deferred period: 2026 input: heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] @@ -24,7 +24,7 @@ ssi: [600, 600, 600] veterans_benefits: [5000, 5000, 5000] output: - nj_liheap_countable_income_person: [600, 11400, 12600] + nj_liheap_countable_income_person: [600, 12600, 12600] - name: Each excluded member has the handbook monthly disregard period: 2026 input: diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml index f8ef7b31175..075ac9f20e3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml @@ -15,7 +15,7 @@ members: - adult - child - nj_wfnj: 0 + tanf: 0 heating_type: FUEL_OIL fuel_oil_expense: 1 households: @@ -45,7 +45,7 @@ age: 40 employment_income: 12000 ssi: 0 - nj_wfnj: 0 + tanf: 0 heat_expense_included_in_rent: true output: nj_liheap: 234 diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py index ab2a6bb97b0..ddc7a24dd95 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py @@ -8,7 +8,8 @@ class nj_liheap_eligible(Variable): label = "New Jersey LIHEAP regular heating eligibility" defined_for = StateCode.NJ reference = ( - "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5,6,7,11,12", + # PDF pages 5, 6, 7, 11, 12. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5", ) documentation = "Automatic enrollment does not waive the income test, and regular heating has no asset test. Striker and institutional-residence exclusions, full utility-allowance coverage and payments by people outside the household need inputs not available here. Unknown county is unsupported, not a legal denial." @@ -27,7 +28,6 @@ def formula(spm_unit, period, parameters): & ~(heat_in_rent & subsidized) & ~dependent_students_only & (spm_unit("nj_liheap_household_size", period) > 0) - & (spm_unit("nj_liheap_region", period) > 0) & ( spm_unit("nj_liheap_countable_income", period) <= spm_unit("nj_liheap_income_limit", period) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py index ea2c792aaff..44152df120f 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py @@ -8,7 +8,8 @@ class nj_liheap_household_size(Variable): label = "New Jersey LIHEAP qualified household size" defined_for = StateCode.NJ reference = ( - "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5,6,10", + # PDF pages 5, 6, 10. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5", ) documentation = "Qualified SPM members approximate the economic household. The federal qualified-noncitizen indicator is used without SNAP-specific bars. Foster residents, tax-dependent students away at school, and separate roomer/boarder households require correct SPM membership; not all protected immigration statuses have an enum choice." diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py index 3d252bdd38c..79254d4069e 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py @@ -9,11 +9,13 @@ class nj_liheap_countable_income(Variable): unit = USD defined_for = StateCode.NJ reference = ( - "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6,9,10", + # PDF pages 6, 9, 10. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6", ) documentation = "Annual inputs approximate the four-week verification period. The summed monthly income is rounded to the nearest dollar, with half dollars rounded up. WFNJ benefits are counted once at the unit level; rental income is assumed nonnegative." def formula(spm_unit, period, parameters): - # WFNJ paid for eligible household members is counted once, in full. - income = add(spm_unit, period, ["nj_liheap_countable_income_person", "nj_wfnj"]) + # The annual TANF aggregate applies take-up to WFNJ entitlement. + # Benefits received are counted once at the household level. + income = add(spm_unit, period, ["nj_liheap_countable_income_person", "tanf"]) return np.floor(max_(income, 0) / MONTHS_IN_YEAR + 0.5) * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py index ff617502299..e109749289f 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py @@ -9,9 +9,10 @@ class nj_liheap_countable_income_person(Variable): unit = USD defined_for = StateCode.NJ reference = ( - "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6,7,8,9,10", + # PDF pages 6, 7, 8, 9, 10. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6", ) - documentation = "Uses existing net self-employment inputs without extra deductions; flooring losses is a modeling convention. Child earnings follow the FY2026 plan. Social Security of children and documented veterans benefits are excluded by the handbook. SSI Lifeline supplements, gifts, foster payments, royalties and roomer receipts cannot be separately identified. The handbook uses a $500 monthly nonqualified-member disregard where older codified text says $268." + documentation = "Uses existing net self-employment inputs without extra deductions; flooring losses is a modeling convention. Child earnings follow the FY2026 plan. Social Security of children and documented veterans benefits are excluded by the handbook. SSI Lifeline supplements, gifts, foster payments, royalties and roomer receipts cannot be separately identified. The handbook uses a $500 monthly nonqualified-member disregard while the readopted regulation still says $268." def formula(person, period, parameters): p = parameters(period).gov.states.nj.dca.liheap.income @@ -23,15 +24,10 @@ def formula(person, period, parameters): person.spm_unit("spm_unit_size", period) > 1 ) earned = where(adult & ~student_in_larger_household, earned, 0) - social_security = where( - adult, - max_( - person("social_security", period) - - person("medicare_part_b_premium", period), - 0, - ), - 0, - ) + # Section 2.3.F.7(a) deducts actual Part B premiums from gross SSA. + # Premium handling remains deferred; modeled and reported premiums + # are not deducted here. + social_security = where(adult, person("social_security", period), 0) income = earned + social_security + add(person, period, p.sources.unearned) qualified = person("is_citizen_or_legal_immigrant", period) # Read the handbook's singular-member rule as a per-person disregard. diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py index 7f5a639117d..3f479868733 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py @@ -10,8 +10,10 @@ class nj_liheap(Variable): defined_for = "nj_liheap_eligible" reference = ( "https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf", - "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7,12,17,18", - "https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=9,10", + # PDF pages 7, 12, 17, 18. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", + # PDF pages 9, 10. + "https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=9", ) documentation = "Annual regular heating payment, verified for FY2026. Earlier years use backfilled parameters and are unverified historical estimates. Amounts preserve all published grid anomalies; no expense cap applies. Unknown/unsupported direct fuels return zero. Separate fuel charges paid to landlords cannot be distinguished from vendor bills without a direct benefit override. Crisis, cooling, furnace and utility-program benefits are excluded." @@ -34,7 +36,7 @@ def formula(spm_unit, period, parameters): # FY2026 handbook 3.2.F assigns direct payers by their heating fuel. # The codified renter-level rule for subsidized direct payers differs. # Chapter 5:49 was readopted in 2025; the conflict remains unresolved. - return select( + amount = select( [ spm_unit("heat_expense_included_in_rent", period), fuel == types.ELECTRICITY, @@ -49,3 +51,5 @@ def formula(spm_unit, period, parameters): ], default=0, ) + # Unknown county is a payment-table coverage gap, not a legal denial. + return where(spm_unit("nj_liheap_region", period) > 0, amount, 0) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py index d27f4af6637..160ca69889d 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py @@ -9,7 +9,8 @@ class nj_liheap_income_band(Variable): defined_for = StateCode.NJ reference = ( "https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf", - "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7,9,12", + # PDF pages 7, 9, 12. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", ) documentation = "The grid does not label the income period; monthly follows the handbook income test and the historical monthly thresholds used in the grid. Three identical initial rows are combined." From 556723188981bd1818e8625072d36b8187760a13 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 01:52:26 -0400 Subject: [PATCH 4/9] Fix issues from review: floor the income band, registry order, tests Floor the income band before the grid lookup so units outside New Jersey index a valid key in mixed-state simulations, and add a two-state case. Name the Medicare premium variables that are not wired in. Place New Jersey between IL and TX in programs.yaml and shorten the note. Give the integration cases realistic bills and real income inputs, add income-ineligible and multi-member scenarios, and bring the test files to the shared conventions. Co-Authored-By: Claude Fable 5.1 --- policyengine_us/programs.yaml | 18 +- .../eligibility/nj_liheap_eligible.yaml | 54 ++++- .../eligibility/nj_liheap_income_limit.yaml | 19 +- .../income/nj_liheap_countable_income.yaml | 33 ++- .../nj_liheap_countable_income_person.yaml | 119 +++++++++-- .../gov/states/nj/dca/liheap/integration.yaml | 192 ++++++++++++++++-- .../gov/states/nj/dca/liheap/nj_liheap.yaml | 158 ++++++++++++-- .../nj_liheap_countable_income_person.py | 6 +- .../gov/states/nj/dca/liheap/nj_liheap.py | 3 +- 9 files changed, 510 insertions(+), 92 deletions(-) diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 444ed883738..807759c3a01 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -802,16 +802,8 @@ programs: category: Benefits agency: HHS status: partial - coverage: OR, DC, Riverside County, MA, IL, TX, NJ + coverage: OR, DC, Riverside County, MA, IL, NJ, TX state_implementations: - - state: NJ - status: partial - name: New Jersey LIHEAP - full_name: New Jersey Low Income Home Energy Assistance Program - variable: nj_liheap - parameter_prefix: gov.states.nj.dca.liheap - verified_years: "2026" - notes: Regular heating under the FY2026 operating handbook and payment matrix. Conflicts with the readopted regulation and some income/housing rules remain unresolved; earlier years are unverified estimates. - state: OR status: in_progress name: LIHEAP @@ -831,6 +823,14 @@ programs: name: Illinois LIHEAP full_name: Illinois Low Income Home Energy Assistance Program variable: il_liheap + - state: NJ + status: partial + name: New Jersey LIHEAP + full_name: New Jersey Low Income Home Energy Assistance Program + variable: nj_liheap + parameter_prefix: gov.states.nj.dca.liheap + verified_years: "2026" + notes: FY2026 regular heating only, covering eligibility, countable income and the benefit grid. Crisis, cooling and equipment assistance are out of scope. - state: TX status: partial name: Texas CEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml index 39ead6d442e..d87abeac636 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml @@ -1,15 +1,37 @@ -- name: Income limit does not disappear for SNAP recipients +# Sources for the expected values in this file: +# - FFY 2026 fact sheet, monthly income limits on page 2: +# https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 +# - FY2026 LIHEAP Handbook, sections 2.2 (pages 5 and 6), 2.3.B (page 7) and +# 3.1.a.2 (page 11): +# https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5 +# - FY2026 Benefit Matrix (one page): +# https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + +# Two one-person households receiving SNAP. Handbook section 3.1.a.2 (page 11) +# keeps the income standard for automatic SNAP payments: "The household must +# have a current monthly income that is less than or equal to the program's +# standards." The one-person limit is $4,167 a month (fact sheet, page 2). +# - 50_004 / 12 = 4,167 does not exceed 4,167: eligible. +# - 50_016 / 12 = 4,168 exceeds 4,167: not eligible. +- name: Case 1, income limit still applies to households receiving SNAP. period: 2026 input: state_code: [NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] - nj_liheap_countable_income: [50004, 50016] + nj_liheap_countable_income: [50_004, 50_016] has_heating_expense: [true, true] heating_type: [NATURAL_GAS, NATURAL_GAS] snap: [100, 100] output: nj_liheap_eligible: [true, false] -- name: Heat included in subsidized rent remains ineligible even with a reported bill + +# Two renters with heat included in rent and no income. Handbook section 2.2 +# (page 6) makes a renter whose heating costs are included in rent eligible, +# and lists as not eligible households "receiving a rent subsidy which includes +# all heating costs". +# - No rent subsidy: eligible. +# - Rent subsidy: not eligible, even with a heating bill reported. +- name: Case 2, heat included in subsidized rent is ineligible. period: 2026 input: state_code: [NJ, NJ] @@ -21,7 +43,11 @@ receives_housing_assistance: [false, true] output: nj_liheap_eligible: [true, false] -- name: A wholly dependent student household is excluded + +# Handbook section 2.2 (page 6), ineligible households item 3, and section +# 2.3.B.5 (page 7): "Households consisting entirely of students who are tax +# dependents of another household" are not eligible. +- name: Case 3, household made up only of tax-dependent students is ineligible. period: 2026 input: state_code: NJ @@ -33,7 +59,14 @@ is_tax_unit_dependent: true output: nj_liheap_eligible: false -- name: Unknown county leaves payment unsupported without denying legal eligibility + +# The eligibility rules in handbook section 2.2 (pages 5 and 6) do not depend +# on the county, so a New Jersey household with a heating bill and no income is +# eligible. The Benefit Matrix prints amounts only under "All Other (19) +# counties" and "Warren & Sussex Counties"; with the county unknown no column +# can be read, so the payment is 0. That is missing information, not a +# published denial. +- name: Case 4, unknown county keeps eligibility but has no payment column. period: 2026 input: state_code: NJ @@ -44,7 +77,16 @@ output: nj_liheap_eligible: true nj_liheap: 0 -- name: No heat responsibility, no qualified members, and other states are excluded + +# Three one-person households with no income: +# - No heating cost of its own and no heat in rent: "The household must pay for +# its own heating/cooling costs" or have them included in rent (handbook +# section 2.2, page 6). Not eligible. +# - Undocumented member: a non-qualified member is excluded from the household +# size (section 2.2.5, page 6), which leaves no eligible member. Not eligible. +# - New York household: "The household members shall be residents of New +# Jersey" (section 2.2, page 5). Not eligible. +- name: Case 5, no heating cost, no qualified member and another state are each ineligible. period: 2026 input: state_code: [NJ, NJ, NY] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml index 1c78c01afec..7c593b498c8 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml @@ -1,8 +1,23 @@ -- name: All published monthly limits and the stated additional-person increment +# Source for the expected values in this file: FFY 2026 fact sheet, page 2, +# "FY2026 Program Income Limit ... (60% State Median Income)": +# https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 +# The income test is monthly (FY2026 LIHEAP Handbook section 2.3.A, page 7), so +# each expected value is the published monthly limit times 12: +# size 1: 4,167 * 12 = 50_004 size 7: 10,819 * 12 = 129_828 +# size 2: 5,449 * 12 = 65_388 size 8: 11,059 * 12 = 132_708 +# size 3: 6,732 * 12 = 80_784 size 9: 11,299 * 12 = 135_588 +# size 4: 8,014 * 12 = 96_168 size 10: 11,540 * 12 = 138_480 +# size 5: 9,296 * 12 = 111_552 size 11: 11,780 * 12 = 141_360 +# size 6: 10,578 * 12 = 126_936 size 12: 12,021 * 12 = 144_252 +# "Household members greater than 12 - Please add $241 for each additional +# member for monthly income limit": +# size 13: (12,021 + 241) * 12 = 12,262 * 12 = 147_144 +# size 14: (12,021 + 2 * 241) * 12 = 12,503 * 12 = 150_036 +- name: Case 1, published monthly limits for sizes 1 to 12 and the additional-member increment. period: 2026 input: heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] nj_liheap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] output: - nj_liheap_income_limit: [50004, 65388, 80784, 96168, 111552, 126936, 129828, 132708, 135588, 138480, 141360, 144252, 147144, 150036] + nj_liheap_income_limit: [50_004, 65_388, 80_784, 96_168, 111_552, 126_936, 129_828, 132_708, 135_588, 138_480, 141_360, 144_252, 147_144, 150_036] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml index 1f5c6d4b5c3..d4e0a549993 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml @@ -1,22 +1,39 @@ -# 11,196 is monthly 933; 11,202 / 12 = 933.5 rounds up to 934. -- name: Monthly household income rounds half up after TANF is added once +# Source for the expected values in this file: FY2026 LIHEAP Handbook, sections +# 2.2 (page 6) and 2.3.F (page 9): +# https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6 + +# Handbook section 2.3.F (page 9): earned and unearned income "shall be added +# to determine the household's total gross monthly income. Cents shall be +# rounded to the nearest dollar." TANF is part of total income (section 2.2, +# page 6, ineligible households item 4) and is added once for the household. +# The result is the rounded monthly amount times 12: +# - 10_001 + 1_200 = 11_201; 11_201 / 12 = 933.42 -> 933; 933 * 12 = 11_196. +# - 10_002 + 1_200 = 11_202; 11_202 / 12 = 933.50 -> 934; 934 * 12 = 11_208. +# Rounding an exact half dollar up is a modeling convention. +- name: Case 1, monthly household income rounds to the nearest dollar after TANF is added once. period: 2026 input: heating_type: [NATURAL_GAS, NATURAL_GAS] state_code: [NJ, NJ] - nj_liheap_countable_income_person: [10001, 10002] - tanf: [1200, 1200] + nj_liheap_countable_income_person: [10_001, 10_002] + tanf: [1_200, 1_200] output: - nj_liheap_countable_income: [11196, 11208] + nj_liheap_countable_income: [11_196, 11_208] -- name: State cash entitlement counts only when TANF is taken up +# Total income includes "any TANF, GA or SSI grants" (handbook section 2.2, +# page 6, ineligible households item 4), meaning grants the household receives. +# Both households are entitled to 1_200 a year of WFNJ (100 a month) and have +# no other income. +# - Does not take up WFNJ: nothing is received, so 0. +# - Takes up WFNJ: 1_200 / 12 = 100 a month; 100 * 12 = 1_200. +- name: Case 2, WFNJ entitlement counts only when it is taken up. period: 2026 input: state_code: [NJ, NJ] heating_type: [NATURAL_GAS, NATURAL_GAS] age: [40, 40] - nj_wfnj: [1200, 1200] + nj_wfnj: [1_200, 1_200] takes_up_tanf_if_eligible: [false, true] ssi: [0, 0] output: - nj_liheap_countable_income: [0, 1200] + nj_liheap_countable_income: [0, 1_200] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml index eb1ba2a74fd..8af43e42f9e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml @@ -1,38 +1,117 @@ -- name: Child and student earnings are excluded while adult earnings and net business income count +# Sources for the expected values in this file: +# - FY2026 LIHEAP Handbook, sections 2.2.5 (page 6), 2.3.C (page 7), 2.3.E.3 +# (page 8), 2.3.E.9 and 2.3.E.10 (page 9) and 2.3.F.7 (page 10): +# https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6 +# - FY2026 LIHEAP State Plan, section 1.9 (pages 6 and 7; the child earnings +# box is on page 7): +# https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=7 + +# Household 1 is a parent (person4) living with a 17-year-old (person1) and a +# 20-year-old full-time student (person2). Household 2 is a 20-year-old +# full-time student living alone (person3). Each person has 12_000 in wages, +# 600 of specified-service business income and 1_200 of farm income; the first +# three also have 1_000 of other self-employment income and the parent has a +# 1_000 self-employment loss. +# - person1: "Earned income of a child under the age of 18" is not a countable +# form of income (State Plan section 1.9, page 7): 0. +# - person2: "Earned income of a student who is a member of a larger household, +# enrolled in any school or training program full-time" is excluded (handbook +# section 2.3.E.3, page 8): 0. +# - person3: a student living alone is not a member of a larger household, so +# wages and self-employment income count (section 2.3.C, page 7): +# 12_000 + 1_000 + 600 + 1_200 = 14_800. +# - person4: 12_000 + 0 + 600 + 1_200 = 13_800. The 1_000 loss is floored at +# zero for that source, a modeling convention. +- name: Case 1, child and student earnings are excluded while adult wages and business income count. period: 2026 input: - heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] - state_code: [NJ, NJ, NJ, NJ] - age: [17, 20, 20, 40] - spm_unit_size: [1, 2, 1, 1] - is_full_time_student: [false, true, true, false] - employment_income: [12000, 12000, 12000, 12000] - self_employment_income: [1000, 1000, 1000, -1000] - sstb_self_employment_income: [600, 600, 600, 600] - farm_operations_income: [1200, 1200, 1200, 1200] - ssi: [0, 0, 0, 0] + people: + person1: + age: 17 + is_full_time_student: false + employment_income: 12_000 + self_employment_income: 1_000 + sstb_self_employment_income: 600 + farm_operations_income: 1_200 + ssi: 0 + person2: + age: 20 + is_full_time_student: true + employment_income: 12_000 + self_employment_income: 1_000 + sstb_self_employment_income: 600 + farm_operations_income: 1_200 + ssi: 0 + person3: + age: 20 + is_full_time_student: true + employment_income: 12_000 + self_employment_income: 1_000 + sstb_self_employment_income: 600 + farm_operations_income: 1_200 + ssi: 0 + person4: + age: 40 + is_full_time_student: false + employment_income: 12_000 + self_employment_income: -1_000 + sstb_self_employment_income: 600 + farm_operations_income: 1_200 + ssi: 0 + spm_units: + spm_unit1: + members: [person1, person2, person4] + heating_type: NATURAL_GAS + spm_unit2: + members: [person3] + heating_type: NATURAL_GAS + households: + household1: + members: [person1, person2, person4] + state_code: NJ + household2: + members: [person3] + state_code: NJ output: - nj_liheap_countable_income_person: [0, 0, 14800, 13800] -- name: Child Social Security is excluded and adult Medicare deductions remain deferred + nj_liheap_countable_income_person: [0, 0, 14_800, 13_800] + +# Three one-person households, each with 12_000 of Social Security, 600 of SSI +# and 5_000 of veterans benefits. +# - Age 17: "Social Security benefits for children under 18 years old shall be +# excluded" (handbook section 2.3.E.9, page 9), leaving the SSI: 600. +# - Age 40 paying a 1_200 Medicare Part B premium: 12_000 + 600 = 12_600. +# Section 2.3.F.7(a) (page 10) deducts the premium from gross Social Security; +# the model counts Social Security gross and does not read the premium yet. +# - Age 40 with no premium: 12_000 + 600 = 12_600. +# Veterans benefits are excluded for all three (section 2.3.E.10, page 9). +- name: Case 2, child Social Security is excluded and adult Social Security counts gross. period: 2026 input: heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] state_code: [NJ, NJ, NJ] age: [17, 40, 40] - social_security: [12000, 12000, 12000] - medicare_part_b_premium: [0, 1200, 0] + social_security: [12_000, 12_000, 12_000] + medicare_part_b_premium: [0, 1_200, 0] ssi: [600, 600, 600] - veterans_benefits: [5000, 5000, 5000] + veterans_benefits: [5_000, 5_000, 5_000] output: - nj_liheap_countable_income_person: [600, 12600, 12600] -- name: Each excluded member has the handbook monthly disregard + nj_liheap_countable_income_person: [600, 12_600, 12_600] + +# Three undocumented adults with wages only. Handbook section 2.2.5 (page 6): +# "If the non-qualified citizens have a monthly income of more than $500.00, +# the amount in excess of $500.00 shall be counted as income to the household." +# The annual disregard is 500 * 12 = 6_000 for each such member. +# - 5_000 - 6_000 is below zero: 0. +# - 6_000 - 6_000 = 0. +# - 7_200 - 6_000 = 1_200. +- name: Case 3, each nonqualified member has the monthly disregard. period: 2026 input: heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] state_code: [NJ, NJ, NJ] age: [40, 40, 40] immigration_status: [UNDOCUMENTED, UNDOCUMENTED, UNDOCUMENTED] - employment_income: [5000, 6000, 7200] + employment_income: [5_000, 6_000, 7_200] ssi: [0, 0, 0] output: - nj_liheap_countable_income_person: [0, 0, 1200] + nj_liheap_countable_income_person: [0, 0, 1_200] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml index 075ac9f20e3..6f0e3db7403 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml @@ -1,51 +1,201 @@ -- name: Mixed-status household counts the nonqualified adult income only above the disregard +# Sources for the expected values in this file: +# - FY2026 Benefit Matrix (one page; four fuel panels, each with the columns +# "All Other (19) counties" and "Warren & Sussex Counties"): +# https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf +# - FFY 2026 fact sheet, monthly income limits on page 2: +# https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 +# - FY2026 LIHEAP Handbook, sections 2.2 (page 6), 2.3.A and 2.3.C (page 7), +# 2.3.F (page 9) and 3.2.F (page 12): +# https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6 +# Model amounts are annual: the monthly limit and the rounded monthly income +# are each multiplied by 12. + +# Sussex County household: an undocumented parent with low wages and a citizen +# child, heating with fuel oil they buy themselves (about $2,000 a year). No +# WFNJ/TANF or SSI is received. +- name: Case 1, mixed-status household counts the nonqualified parent's income above the disregard. period: 2026 input: people: - adult: + person1: age: 40 - employment_income: 18000 + employment_income: 18_000 immigration_status: UNDOCUMENTED ssi: 0 - child: + person2: age: 5 ssi: 0 spm_units: - unit: - members: - - adult - - child + spm_unit: + members: [person1, person2] tanf: 0 heating_type: FUEL_OIL - fuel_oil_expense: 1 + fuel_oil_expense: 2_000 households: - home: - members: - - adult - - child + household: + members: [person1, person2] state_code: NJ county: SUSSEX_COUNTY_NJ output: + # The household pays for its own heating (section 2.2, page 6). + has_heating_expense: true + # The nonqualified parent is excluded from the household size, leaving the + # child (section 2.2.5, page 6). nj_liheap_household_size: 1 - nj_liheap_countable_income_person: [12000, 0] - nj_liheap_countable_income: 12000 - nj_liheap_income_limit: 50004 + # Only the parent's income above $500 a month counts (section 2.2.5, + # page 6): 18_000 - 500 * 12 = 12_000. The child has no income. + nj_liheap_countable_income_person: [12_000, 0] + # 12_000 / 12 = 1,000 a month, already a whole dollar. + nj_liheap_countable_income: 12_000 + # One person: $4,167 a month (fact sheet, page 2); 4,167 * 12 = 50_004. + nj_liheap_income_limit: 50_004 + # $1,000 a month is in the printed row "$0 - $1000". Band 1 covers the + # first three printed rows, which pay the same amounts. nj_liheap_income_band: 1 + # Sussex is in the "Warren & Sussex Counties" column. nj_liheap_region: 2 + # 1,000 does not exceed 4,167 (section 2.3.A, page 7). nj_liheap_eligible: true + # Deliverables panel (fuel oil), "Warren & Sussex Counties", row + # "$0 - $1000", column "1 to 4": $961. nj_liheap: 961 -- name: An unsubsidized rent-included household receives the renter schedule without fuel information + +# Newark (Essex County) renter: one adult working part time whose heat is +# included in an unsubsidized rent, with no fuel bill of their own. The +# building's fuel is not known to the tenant, so heating_type is UNSPECIFIED; +# the Renters panel does not depend on the fuel. No WFNJ/TANF or SSI is +# received. +- name: Case 2, unsubsidized renter with heat included in rent receives the renters panel. period: 2026 input: state_code: NJ county: ESSEX_COUNTY_NJ - nj_liheap_countable_income: 12000 - has_heating_expense: false - heating_type: UNSPECIFIED age: 40 - employment_income: 12000 + employment_income: 12_000 ssi: 0 tanf: 0 + heating_type: UNSPECIFIED heat_expense_included_in_rent: true output: + # No heating bill in the household's own name; heat is paid through rent. + has_heating_expense: false + nj_liheap_household_size: 1 + # Wages count in full (section 2.3.C, page 7). + nj_liheap_countable_income_person: 12_000 + # 12_000 / 12 = 1,000 a month, already a whole dollar. + nj_liheap_countable_income: 12_000 + # One person: $4,167 a month (fact sheet, page 2); 4,167 * 12 = 50_004. + nj_liheap_income_limit: 50_004 + # $1,000 a month is in the printed row "$0 - $1000". + nj_liheap_income_band: 1 + # Essex is in the "All Other (19) counties" column. + nj_liheap_region: 1 + # Heat included in rent qualifies when the rent is not subsidized + # (section 2.2, page 6), and 1,000 does not exceed 4,167. + nj_liheap_eligible: true + # Heat included in rent is its own fuel type (section 3.2.F.2, page 12). + # Renters panel, "All Other (19) counties", row "$0 - $1000", column + # "1 to 4": $234. nj_liheap: 234 + +# Bergen County couple, both working full time, heating with natural gas billed +# in their own name (about $1,400 a year). No WFNJ/TANF or SSI is received. +- name: Case 3, working couple above the two-person income limit is ineligible. + period: 2026 + input: + people: + person1: + age: 38 + employment_income: 45_000 + ssi: 0 + person2: + age: 36 + employment_income: 36_000 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_400 + households: + household: + members: [person1, person2] + state_code: NJ + county: BERGEN_COUNTY_NJ + output: + # The household pays for its own heating (section 2.2, page 6). + has_heating_expense: true + # Both members are citizens. + nj_liheap_household_size: 2 + # Wages count in full (section 2.3.C, page 7). + nj_liheap_countable_income_person: [45_000, 36_000] + # 45_000 + 36_000 = 81_000; 81_000 / 12 = 6,750 a month, a whole dollar. + nj_liheap_countable_income: 81_000 + # Two people: $5,449 a month (fact sheet, page 2); 5,449 * 12 = 65_388. + nj_liheap_income_limit: 65_388 + # Bergen is in the "All Other (19) counties" column. + nj_liheap_region: 1 + # 6,750 exceeds 5,449, so the household is not income eligible (section + # 2.3.A, page 7, and section 2.2, page 6, ineligible households item 4). + nj_liheap_eligible: false + # No payment for an ineligible household. + nj_liheap: 0 + +# Middlesex County family of five: two working parents and three school-age +# children, heating with natural gas billed in their own name (about $1,600 a +# year). No WFNJ/TANF or SSI is received. +- name: Case 4, family of five uses the five-person limit and the 5 to 8 size column. + period: 2026 + input: + people: + person1: + age: 41 + employment_income: 52_000 + ssi: 0 + person2: + age: 39 + employment_income: 34_000 + ssi: 0 + person3: + age: 14 + ssi: 0 + person4: + age: 10 + ssi: 0 + person5: + age: 6 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_600 + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: NJ + county: MIDDLESEX_COUNTY_NJ + output: + # The household pays for its own heating (section 2.2, page 6). + has_heating_expense: true + # All five members are citizens. + nj_liheap_household_size: 5 + # Wages count in full (section 2.3.C, page 7); the children have no income. + nj_liheap_countable_income_person: [52_000, 34_000, 0, 0, 0] + # 52_000 + 34_000 = 86_000; 86_000 / 12 = 7,166.67, rounded to the nearest + # dollar = 7,167 a month (section 2.3.F, page 9); 7,167 * 12 = 86_004. + nj_liheap_countable_income: 86_004 + # Five people: $9,296 a month (fact sheet, page 2); 9,296 * 12 = 111_552. + nj_liheap_income_limit: 111_552 + # $7,167 a month is in the printed row "$6440 - $8886", which is band 2. + nj_liheap_income_band: 2 + # Middlesex is in the "All Other (19) counties" column. + nj_liheap_region: 1 + # 7,167 does not exceed 9,296 (section 2.3.A, page 7). The same income + # would exceed the three-person limit of $6,732. + nj_liheap_eligible: true + # Gas panel, "All Other (19) counties", row "$6440 - $8886", column + # "5 to 8": $373. + nj_liheap: 373 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml index df1852cadb8..1db5e46d27c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml @@ -1,100 +1,179 @@ -- name: Published Deliverables payments in All Other (19) counties for every distinct income band and size group +# Sources for the expected values in this file: +# - FY2026 Benefit Matrix (one page; four fuel panels, each with the columns +# "All Other (19) counties" and "Warren & Sussex Counties"): +# https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf +# - FFY 2026 fact sheet, income limits on page 2: +# https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 +# - FY2026 LIHEAP Handbook, sections 2.2 (page 5), 2.3.A (page 7), 3.1.a.3 +# (page 11) and 3.2.F (page 12): +# https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5 +# +# Cases 1 to 8 read the printed cells of one panel and one county column each. +# Eligibility is set directly because these cases test the grid lookup, not the +# income test. In every one of them: +# - Monthly income is 0, 77_280 / 12 = 6,440, 106_644 / 12 = 8,887 and +# 115_920 / 12 = 9,660: the first dollar of the printed rows "$0 - $1000", +# "$6440 - $8886", "$8887 - $9659" and "$9660 +". The rows "$1001 - $2000" +# and "$2001 - $6439" print the same amounts as "$0 - $1000" (Case 10). +# - Sizes 1, 5, 9 and 13 are the first sizes of the printed columns "1 to 4", +# "5 to 8", "9 to 12" and "13 or More". + +# Deliverables panel, "All Other (19) counties". Printed cells by row: +# $0 - $1000: 641, 859, 1,025, 1,128 +# $6440 - $8886: 535, 715, 855, 941 +# $8887 - $9659: 428, 573, 685, 754 +# $9660 +: 321, 428, 513, 564 +- name: Case 1, deliverables panel in the other nineteen counties by income row and size group. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] - nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: - nj_liheap: [641, 859, 1025, 1128, 535, 715, 855, 941, 428, 573, 685, 754, 321, 428, 513, 564] -- name: Published Deliverables payments in Warren & Sussex Counties for every distinct income band and size group + nj_liheap: [641, 859, 1_025, 1_128, 535, 715, 855, 941, 428, 573, 685, 754, 321, 428, 513, 564] + +# Deliverables panel, "Warren & Sussex Counties". Printed cells by row: +# $0 - $1000: 961, 983, 1,162, 1,278 +# $6440 - $8886: 613, 820, 979, 1,077 +# $8887 - $9659: 491, 657, 784, 862 +# $9660 +: 366, 493, 587, 646 +# The $961 cell is what the matrix prints for "1 to 4". +- name: Case 2, deliverables panel in Warren and Sussex by income row and size group. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] - nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: - nj_liheap: [961, 983, 1162, 1278, 613, 820, 979, 1077, 491, 657, 784, 862, 366, 493, 587, 646] -- name: Published Electric payments in All Other (19) counties for every distinct income band and size group + nj_liheap: [961, 983, 1_162, 1_278, 613, 820, 979, 1_077, 491, 657, 784, 862, 366, 493, 587, 646] + +# Electric panel, "All Other (19) counties". Printed cells by row: +# $0 - $1000: 529, 710, 846, 931 +# $6440 - $8886: 442, 591, 705, 776 +# $8887 - $9659: 352, 473, 564, 620 +# $9660 +: 265, 354, 424, 466 +- name: Case 3, electric panel in the other nineteen counties by income row and size group. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] - nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [529, 710, 846, 931, 442, 591, 705, 776, 352, 473, 564, 620, 265, 354, 424, 466] -- name: Published Electric payments in Warren & Sussex Counties for every distinct income band and size group + +# Electric panel, "Warren & Sussex Counties". Printed cells by row: +# $0 - $1000: 606, 821, 970, 1,067 +# $6440 - $8886: 506, 675, 807, 888 +# $8887 - $9659: 404, 541, 646, 711 +# $9660 +: 304, 406, 485, 534 +- name: Case 4, electric panel in Warren and Sussex by income row and size group. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] - nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: - nj_liheap: [606, 821, 970, 1067, 506, 675, 807, 888, 404, 541, 646, 711, 304, 406, 485, 534] -- name: Published Gas payments in All Other (19) counties for every distinct income band and size group + nj_liheap: [606, 821, 970, 1_067, 506, 675, 807, 888, 404, 541, 646, 711, 304, 406, 485, 534] + +# Gas panel, "All Other (19) counties". Printed cells by row: +# $0 - $1000: 334, 448, 535, 589 +# $6440 - $8886: 278, 373, 446, 491 +# $8887 - $9659: 222, 298, 355, 391 +# $9660 +: 167, 224, 267, 294 +- name: Case 5, gas panel in the other nineteen counties by income row and size group. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] - nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [334, 448, 535, 589, 278, 373, 446, 491, 222, 298, 355, 391, 167, 224, 267, 294] -- name: Published Gas payments in Warren & Sussex Counties for every distinct income band and size group + +# Gas panel, "Warren & Sussex Counties". Printed cells by row: +# $0 - $1000: 383, 512, 612, 673 +# $6440 - $8886: 318, 427, 509, 560 +# $8887 - $9659: 254, 341, 408, 445 +# $9660 +: 191, 256, 306, 337 +- name: Case 6, gas panel in Warren and Sussex by income row and size group. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] - nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [383, 512, 612, 673, 318, 427, 509, 560, 254, 341, 408, 445, 191, 256, 306, 337] -- name: Published Renters payments in All Other (19) counties for every distinct income band and size group + +# Renters panel, "All Other (19) counties". Heat is included in rent, so the +# fuel is not needed (handbook section 3.2.F.2, page 12). Printed cells by row: +# $0 - $1000: 234, 312, 374, 411 +# $6440 - $8886: 196, 262, 312, 343 +# $8887 - $9659: 156, 208, 250, 275 +# $9660 +: 118, 157, 186, 205 +- name: Case 7, renters panel in the other nineteen counties by income row and size group. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] - nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] output: nj_liheap: [234, 312, 374, 411, 196, 262, 312, 343, 156, 208, 250, 275, 118, 157, 186, 205] -- name: Published Renters payments in Warren & Sussex Counties for every distinct income band and size group + +# Renters panel, "Warren & Sussex Counties". Printed cells by row: +# $0 - $1000: 267, 360, 428, 471 +# $6440 - $8886: 222, 299, 358, 394 +# $8887 - $9659: 179, 240, 286, 315 +# $9660 +: 134, 179, 216, 238 +- name: Case 8, renters panel in Warren and Sussex by income row and size group. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] - nj_liheap_countable_income: [0, 0, 0, 0, 77280, 77280, 77280, 77280, 106644, 106644, 106644, 106644, 115920, 115920, 115920, 115920] + nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] output: nj_liheap: [267, 360, 428, 471, 222, 299, 358, 394, 179, 240, 286, 315, 134, 179, 216, 238] -- name: All published heating fuels map to their panel + +# One-person households with $0 income in Essex ("All Other (19) counties"), +# row "$0 - $1000", column "1 to 4". Handbook section 3.2.F.1 (page 12) lists +# the fuel types: electricity, natural gas, oil, propane, kerosene, coal, wood +# and heat included in rent. +# - Electricity: Electric panel, $529. Natural gas: Gas panel, $334. +# - Oil, kerosene, propane, wood and coal are the delivered fuels (section +# 3.1.a.3, page 11) and read the Deliverables panel: $641 each. +# - Solar, other, unspecified and no heating are not listed fuel types, and no +# panel applies to a household paying its own heating bill: $0. +- name: Case 9, each heating fuel reads its own panel. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] @@ -104,7 +183,16 @@ heating_type: [ELECTRICITY, NATURAL_GAS, FUEL_OIL, KEROSENE, PROPANE, WOOD, COAL, SOLAR, OTHER, UNSPECIFIED, NONE] output: nj_liheap: [529, 334, 641, 641, 641, 641, 641, 0, 0, 0, 0] -- name: Income bands preserve the printed boundary dollars + +# Gas panel, "All Other (19) counties", column "1 to 4" (size 4). Annual incomes +# divided by 12 are the last and first dollars of each printed row: +# $0 - $1000: 0 and 12_000 / 12 = 1,000 -> 334, 334 +# $1001 - $2000: 12_012 / 12 = 1,001 and 24_000 / 12 = 2,000 -> 334, 334 +# $2001 - $6439: 24_012 / 12 = 2,001 and 77_268 / 12 = 6,439 -> 334, 334 +# $6440 - $8886: 77_280 / 12 = 6,440 and 106_632 / 12 = 8,886 -> 278, 278 +# $8887 - $9659: 106_644 / 12 = 8,887 and 115_908 / 12 = 9,659 -> 222, 222 +# $9660 +: 115_920 / 12 = 9,660 -> 167 +- name: Case 10, income row boundaries follow the printed dollars. period: 2026 input: state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] @@ -112,6 +200,32 @@ nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true] nj_liheap_household_size: [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4] heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] - nj_liheap_countable_income: [0, 12000, 12012, 24000, 24012, 77268, 77280, 106632, 106644, 115908, 115920] + nj_liheap_countable_income: [0, 12_000, 12_012, 24_000, 24_012, 77_268, 77_280, 106_632, 106_644, 115_908, 115_920] output: nj_liheap: [334, 334, 334, 334, 334, 334, 278, 278, 222, 222, 167] + +# One simulation holding a Newark (Essex County) household and a Brooklyn +# (Kings County, New York) household. Each is a single adult working full time +# who heats with natural gas billed in their own name. Neither receives +# WFNJ/TANF or SSI. Nothing is set on the New Jersey unit except what an +# applicant would report. +# - New Jersey unit: wages 42_000 / 12 = 3,500 a month, which does not exceed +# the one-person limit of $4,167 (fact sheet, page 2), so the household is +# income eligible (handbook section 2.3.A, page 7). Gas panel, "All Other +# (19) counties", row "$2001 - $6439", column "1 to 4": $334. +# - New York unit: household members must be residents of New Jersey (handbook +# section 2.2, page 5), so it is not eligible and receives $0. +- name: Case 11, New Jersey household and New York household in one simulation. + period: 2026 + input: + state_code: [NJ, NY] + county: [ESSEX_COUNTY_NJ, KINGS_COUNTY_NY] + age: [34, 41] + employment_income: [42_000, 48_000] + ssi: [0, 0] + tanf: [0, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_300, 1_500] + output: + nj_liheap_eligible: [true, false] + nj_liheap: [334, 0] diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py index e109749289f..42459325e79 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py @@ -24,9 +24,9 @@ def formula(person, period, parameters): person.spm_unit("spm_unit_size", period) > 1 ) earned = where(adult & ~student_in_larger_household, earned, 0) - # Section 2.3.F.7(a) deducts actual Part B premiums from gross SSA. - # Premium handling remains deferred; modeled and reported premiums - # are not deducted here. + # Handbook section 2.3.F.7(a) (page 10) deducts the Medicare Part B premium + # from gross Social Security. The premium is not deducted yet: neither + # medicare_part_b_premium nor medicare_part_b_premiums_reported is wired in. social_security = where(adult, person("social_security", period), 0) income = earned + social_security + add(person, period, p.sources.unearned) qualified = person("is_citizen_or_legal_immigrant", period) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py index 3f479868733..64205b072cb 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py @@ -23,7 +23,8 @@ def formula(spm_unit, period, parameters): size = p.household_size_group.calc( max_(spm_unit("nj_liheap_household_size", period), 1) ) - band = spm_unit("nj_liheap_income_band", period) + # The floor keeps units outside New Jersey (band 0) on a valid grid key. + band = max_(spm_unit("nj_liheap_income_band", period), 1) fuel = spm_unit("heating_type", period) types = fuel.possible_values deliverable = ( From 42f6603bf30a316c10bca0e0b01e5c999d580729 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 17:28:43 -0400 Subject: [PATCH 5/9] Count farm rental income in New Jersey LIHEAP --- .../dca/liheap/income/sources/unearned.yaml | 1 + .../gov/states/nj/dca/liheap/nj_liheap.yaml | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml index 7e546899d5e..16a6c3a0f93 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml @@ -7,6 +7,7 @@ values: - pension_income - general_assistance - rental_income + - farm_rent_income - alimony_income - child_support_received - interest_income diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml index 1db5e46d27c..17167853388 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml @@ -229,3 +229,27 @@ output: nj_liheap_eligible: [true, false] nj_liheap: [334, 0] + +- name: Case 12, farm rental income puts a gas-heating household over the income limit. + period: 2026 + input: + state_code: NJ + county: SUSSEX_COUNTY_NJ + age: 45 + immigration_status: CITIZEN + employment_income: 36_000 + farm_rent_income: 24_000 + rental_income: 0 + ssi: 0 + tanf: 0 + snap: 0 + heating_type: NATURAL_GAS + gas_expense: 1_200 + output: + # Handbook section 2.3.D (page 8) counts rental-property receipts. With no + # rental expenses, $36,000 wages + $24,000 farm rents = $60,000 annually. + nj_liheap_countable_income: 60_000 + # Fact sheet, page 2: $4,167 monthly for one person x 12 = $50,004. + nj_liheap_income_limit: 50_004 + nj_liheap_eligible: false + nj_liheap: 0 From 0f47f9cd328040febe3c5f85ba7240ba60cb500f Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 22:15:27 -0400 Subject: [PATCH 6/9] Count survivor benefits in New Jersey LIHEAP Handbook 2.3.D counts pensions and annuities, which covers survivor pensions and annuities. 2.3.E.10 excludes veterans' benefits, but VA survivor payments cannot be separated from survivor_benefits, so the whole amount counts; the parameter comment records this. Co-Authored-By: Claude Fable 5.1 --- .../gov/states/nj/dca/liheap/income/sources/unearned.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml index 16a6c3a0f93..b9be9cb64b3 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml @@ -5,6 +5,9 @@ values: - strike_benefits - ssi - pension_income + # Handbook 2.3.D counts pensions and annuities; 2.3.E.10 excludes veterans' + # benefits, but VA survivor payments cannot be separated and count here. + - survivor_benefits - general_assistance - rental_income - farm_rent_income From 924519344a34f7d34af98c79466a6e5c95088c5a Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 5 Oct 2026 22:58:17 -0400 Subject: [PATCH 7/9] Tidy New Jersey LIHEAP parameters and tests Write parameter date keys unquoted, wrap each variable's documentation string across lines, and split the household-size sweeps between files so each size is asserted once: odd sizes in the income-limit test, even sizes in the benefit-grid tests. Co-Authored-By: Claude Fable 5.1 --- .../liheap/eligibility/max_table_size.yaml | 2 +- .../nj/dca/liheap/eligibility/smi_rate.yaml | 2 +- .../nj/dca/liheap/income/adult_age.yaml | 2 +- .../income/nonqualified_member_disregard.yaml | 2 +- .../nj/dca/liheap/income/sources/earned.yaml | 2 +- .../dca/liheap/income/sources/unearned.yaml | 2 +- .../liheap/payment/amount/deliverables.yaml | 64 +++++++++---------- .../dca/liheap/payment/amount/electric.yaml | 64 +++++++++---------- .../nj/dca/liheap/payment/amount/gas.yaml | 64 +++++++++---------- .../nj/dca/liheap/payment/amount/renters.yaml | 64 +++++++++---------- .../liheap/payment/household_size_group.yaml | 16 ++--- .../nj/dca/liheap/payment/income_band.yaml | 16 ++--- .../dca/liheap/payment/regions/region_1.yaml | 2 +- .../dca/liheap/payment/regions/region_2.yaml | 2 +- .../eligibility/nj_liheap_income_limit.yaml | 20 +++--- .../gov/states/nj/dca/liheap/nj_liheap.yaml | 49 ++++++++------ .../liheap/eligibility/nj_liheap_eligible.py | 7 +- .../eligibility/nj_liheap_household_size.py | 8 ++- .../eligibility/nj_liheap_income_limit.py | 8 ++- .../income/nj_liheap_countable_income.py | 7 +- .../nj_liheap_countable_income_person.py | 10 ++- .../gov/states/nj/dca/liheap/nj_liheap.py | 9 ++- .../liheap/payment/nj_liheap_income_band.py | 6 +- .../nj/dca/liheap/payment/nj_liheap_region.py | 5 +- 24 files changed, 244 insertions(+), 189 deletions(-) diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml index 569691b11d8..e598e0f49e1 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml @@ -1,6 +1,6 @@ description: New Jersey prints income limits through this household size before using a fixed monthly increment under the Low Income Home Energy Assistance Program. values: - '2025-10-01': 12 + 2025-10-01: 12 metadata: unit: person period: year diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml index c9ccc69c047..ea9f5738d2c 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml @@ -1,6 +1,6 @@ description: New Jersey limits monthly income to this share of state median income under the Low Income Home Energy Assistance Program. values: - '2025-10-01': 0.6 + 2025-10-01: 0.6 metadata: unit: /1 period: year diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml index a35f9160a9f..c971201c2a3 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml @@ -1,6 +1,6 @@ description: New Jersey excludes child earnings and Social Security below this age under the Low Income Home Energy Assistance Program. values: - '2025-10-01': 18 + 2025-10-01: 18 metadata: unit: year period: year diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml index 7e60de0912b..b80fc3c8efc 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml @@ -1,6 +1,6 @@ description: New Jersey excludes this much monthly income of a nonqualified member before adding the excess to household income under the Low Income Home Energy Assistance Program. values: - '2025-10-01': 500 + 2025-10-01: 500 metadata: unit: currency-USD period: month diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml index 702e3e92813..80f254e0dce 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml @@ -1,6 +1,6 @@ description: New Jersey uses these reported earnings sources without any additional business expense deduction under the Low Income Home Energy Assistance Program. values: - '2025-10-01': + 2025-10-01: - employment_income - self_employment_income - sstb_self_employment_income diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml index b9be9cb64b3..f028d63e948 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml @@ -1,6 +1,6 @@ description: New Jersey counts these available unearned income sources under the Low Income Home Energy Assistance Program. values: - '2025-10-01': + 2025-10-01: - unemployment_compensation - strike_benefits - ssi diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml index 2de040b204f..dbb2bf934a5 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml @@ -2,77 +2,77 @@ description: New Jersey pays this annual regular heating benefit in the delivera '1': 1: 1: - '2025-10-01': 641 + 2025-10-01: 641 2: - '2025-10-01': 859 + 2025-10-01: 859 3: - '2025-10-01': 1025 + 2025-10-01: 1025 4: - '2025-10-01': 1128 + 2025-10-01: 1128 2: 1: - '2025-10-01': 535 + 2025-10-01: 535 2: - '2025-10-01': 715 + 2025-10-01: 715 3: - '2025-10-01': 855 + 2025-10-01: 855 4: - '2025-10-01': 941 + 2025-10-01: 941 3: 1: - '2025-10-01': 428 + 2025-10-01: 428 2: - '2025-10-01': 573 + 2025-10-01: 573 3: - '2025-10-01': 685 + 2025-10-01: 685 4: - '2025-10-01': 754 + 2025-10-01: 754 4: 1: - '2025-10-01': 321 + 2025-10-01: 321 2: - '2025-10-01': 428 + 2025-10-01: 428 3: - '2025-10-01': 513 + 2025-10-01: 513 4: - '2025-10-01': 564 + 2025-10-01: 564 '2': 1: 1: - '2025-10-01': 961 + 2025-10-01: 961 2: - '2025-10-01': 983 + 2025-10-01: 983 3: - '2025-10-01': 1162 + 2025-10-01: 1162 4: - '2025-10-01': 1278 + 2025-10-01: 1278 2: 1: - '2025-10-01': 613 + 2025-10-01: 613 2: - '2025-10-01': 820 + 2025-10-01: 820 3: - '2025-10-01': 979 + 2025-10-01: 979 4: - '2025-10-01': 1077 + 2025-10-01: 1077 3: 1: - '2025-10-01': 491 + 2025-10-01: 491 2: - '2025-10-01': 657 + 2025-10-01: 657 3: - '2025-10-01': 784 + 2025-10-01: 784 4: - '2025-10-01': 862 + 2025-10-01: 862 4: 1: - '2025-10-01': 366 + 2025-10-01: 366 2: - '2025-10-01': 493 + 2025-10-01: 493 3: - '2025-10-01': 587 + 2025-10-01: 587 4: - '2025-10-01': 646 + 2025-10-01: 646 metadata: unit: currency-USD period: year diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml index 6d76b745c17..8e2fafdab30 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml @@ -2,77 +2,77 @@ description: New Jersey pays this annual regular heating benefit in the electric '1': 1: 1: - '2025-10-01': 529 + 2025-10-01: 529 2: - '2025-10-01': 710 + 2025-10-01: 710 3: - '2025-10-01': 846 + 2025-10-01: 846 4: - '2025-10-01': 931 + 2025-10-01: 931 2: 1: - '2025-10-01': 442 + 2025-10-01: 442 2: - '2025-10-01': 591 + 2025-10-01: 591 3: - '2025-10-01': 705 + 2025-10-01: 705 4: - '2025-10-01': 776 + 2025-10-01: 776 3: 1: - '2025-10-01': 352 + 2025-10-01: 352 2: - '2025-10-01': 473 + 2025-10-01: 473 3: - '2025-10-01': 564 + 2025-10-01: 564 4: - '2025-10-01': 620 + 2025-10-01: 620 4: 1: - '2025-10-01': 265 + 2025-10-01: 265 2: - '2025-10-01': 354 + 2025-10-01: 354 3: - '2025-10-01': 424 + 2025-10-01: 424 4: - '2025-10-01': 466 + 2025-10-01: 466 '2': 1: 1: - '2025-10-01': 606 + 2025-10-01: 606 2: - '2025-10-01': 821 + 2025-10-01: 821 3: - '2025-10-01': 970 + 2025-10-01: 970 4: - '2025-10-01': 1067 + 2025-10-01: 1067 2: 1: - '2025-10-01': 506 + 2025-10-01: 506 2: - '2025-10-01': 675 + 2025-10-01: 675 3: - '2025-10-01': 807 + 2025-10-01: 807 4: - '2025-10-01': 888 + 2025-10-01: 888 3: 1: - '2025-10-01': 404 + 2025-10-01: 404 2: - '2025-10-01': 541 + 2025-10-01: 541 3: - '2025-10-01': 646 + 2025-10-01: 646 4: - '2025-10-01': 711 + 2025-10-01: 711 4: 1: - '2025-10-01': 304 + 2025-10-01: 304 2: - '2025-10-01': 406 + 2025-10-01: 406 3: - '2025-10-01': 485 + 2025-10-01: 485 4: - '2025-10-01': 534 + 2025-10-01: 534 metadata: unit: currency-USD period: year diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml index 13e898c4667..0b9b4d33f70 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml @@ -2,77 +2,77 @@ description: New Jersey pays this annual regular heating benefit in the gas pane '1': 1: 1: - '2025-10-01': 334 + 2025-10-01: 334 2: - '2025-10-01': 448 + 2025-10-01: 448 3: - '2025-10-01': 535 + 2025-10-01: 535 4: - '2025-10-01': 589 + 2025-10-01: 589 2: 1: - '2025-10-01': 278 + 2025-10-01: 278 2: - '2025-10-01': 373 + 2025-10-01: 373 3: - '2025-10-01': 446 + 2025-10-01: 446 4: - '2025-10-01': 491 + 2025-10-01: 491 3: 1: - '2025-10-01': 222 + 2025-10-01: 222 2: - '2025-10-01': 298 + 2025-10-01: 298 3: - '2025-10-01': 355 + 2025-10-01: 355 4: - '2025-10-01': 391 + 2025-10-01: 391 4: 1: - '2025-10-01': 167 + 2025-10-01: 167 2: - '2025-10-01': 224 + 2025-10-01: 224 3: - '2025-10-01': 267 + 2025-10-01: 267 4: - '2025-10-01': 294 + 2025-10-01: 294 '2': 1: 1: - '2025-10-01': 383 + 2025-10-01: 383 2: - '2025-10-01': 512 + 2025-10-01: 512 3: - '2025-10-01': 612 + 2025-10-01: 612 4: - '2025-10-01': 673 + 2025-10-01: 673 2: 1: - '2025-10-01': 318 + 2025-10-01: 318 2: - '2025-10-01': 427 + 2025-10-01: 427 3: - '2025-10-01': 509 + 2025-10-01: 509 4: - '2025-10-01': 560 + 2025-10-01: 560 3: 1: - '2025-10-01': 254 + 2025-10-01: 254 2: - '2025-10-01': 341 + 2025-10-01: 341 3: - '2025-10-01': 408 + 2025-10-01: 408 4: - '2025-10-01': 445 + 2025-10-01: 445 4: 1: - '2025-10-01': 191 + 2025-10-01: 191 2: - '2025-10-01': 256 + 2025-10-01: 256 3: - '2025-10-01': 306 + 2025-10-01: 306 4: - '2025-10-01': 337 + 2025-10-01: 337 metadata: unit: currency-USD period: year diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml index 197236bb0ae..42363c5eec4 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml @@ -2,77 +2,77 @@ description: New Jersey pays this annual regular heating benefit in the renters '1': 1: 1: - '2025-10-01': 234 + 2025-10-01: 234 2: - '2025-10-01': 312 + 2025-10-01: 312 3: - '2025-10-01': 374 + 2025-10-01: 374 4: - '2025-10-01': 411 + 2025-10-01: 411 2: 1: - '2025-10-01': 196 + 2025-10-01: 196 2: - '2025-10-01': 262 + 2025-10-01: 262 3: - '2025-10-01': 312 + 2025-10-01: 312 4: - '2025-10-01': 343 + 2025-10-01: 343 3: 1: - '2025-10-01': 156 + 2025-10-01: 156 2: - '2025-10-01': 208 + 2025-10-01: 208 3: - '2025-10-01': 250 + 2025-10-01: 250 4: - '2025-10-01': 275 + 2025-10-01: 275 4: 1: - '2025-10-01': 118 + 2025-10-01: 118 2: - '2025-10-01': 157 + 2025-10-01: 157 3: - '2025-10-01': 186 + 2025-10-01: 186 4: - '2025-10-01': 205 + 2025-10-01: 205 '2': 1: 1: - '2025-10-01': 267 + 2025-10-01: 267 2: - '2025-10-01': 360 + 2025-10-01: 360 3: - '2025-10-01': 428 + 2025-10-01: 428 4: - '2025-10-01': 471 + 2025-10-01: 471 2: 1: - '2025-10-01': 222 + 2025-10-01: 222 2: - '2025-10-01': 299 + 2025-10-01: 299 3: - '2025-10-01': 358 + 2025-10-01: 358 4: - '2025-10-01': 394 + 2025-10-01: 394 3: 1: - '2025-10-01': 179 + 2025-10-01: 179 2: - '2025-10-01': 240 + 2025-10-01: 240 3: - '2025-10-01': 286 + 2025-10-01: 286 4: - '2025-10-01': 315 + 2025-10-01: 315 4: 1: - '2025-10-01': 134 + 2025-10-01: 134 2: - '2025-10-01': 179 + 2025-10-01: 179 3: - '2025-10-01': 216 + 2025-10-01: 216 4: - '2025-10-01': 238 + 2025-10-01: 238 metadata: unit: currency-USD period: year diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml index 416276d94ea..59ecd17a79b 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml @@ -1,21 +1,21 @@ description: New Jersey uses these household size group boundaries under the Low Income Home Energy Assistance Program. brackets: - threshold: - '2025-10-01': 1 + 2025-10-01: 1 amount: - '2025-10-01': 1 + 2025-10-01: 1 - threshold: - '2025-10-01': 5 + 2025-10-01: 5 amount: - '2025-10-01': 2 + 2025-10-01: 2 - threshold: - '2025-10-01': 9 + 2025-10-01: 9 amount: - '2025-10-01': 3 + 2025-10-01: 3 - threshold: - '2025-10-01': 13 + 2025-10-01: 13 amount: - '2025-10-01': 4 + 2025-10-01: 4 metadata: type: single_amount threshold_unit: person diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml index ea8c847acd1..b2cb767faff 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml @@ -2,21 +2,21 @@ description: New Jersey uses these monthly income band boundaries under the Low Income Home Energy Assistance Program. brackets: - threshold: - '2025-10-01': 0 + 2025-10-01: 0 amount: - '2025-10-01': 1 + 2025-10-01: 1 - threshold: - '2025-10-01': 6440 + 2025-10-01: 6440 amount: - '2025-10-01': 2 + 2025-10-01: 2 - threshold: - '2025-10-01': 8887 + 2025-10-01: 8887 amount: - '2025-10-01': 3 + 2025-10-01: 3 - threshold: - '2025-10-01': 9660 + 2025-10-01: 9660 amount: - '2025-10-01': 4 + 2025-10-01: 4 metadata: type: single_amount threshold_unit: currency-USD diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml index ed3ef109b3f..6698cb7fcbf 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml @@ -1,6 +1,6 @@ description: New Jersey assigns these counties to payment region 1 under the Low Income Home Energy Assistance Program. values: - '2025-10-01': + 2025-10-01: - ATLANTIC_COUNTY_NJ - BERGEN_COUNTY_NJ - BURLINGTON_COUNTY_NJ diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml index c32709f28c5..5d0916f60c3 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml @@ -1,6 +1,6 @@ description: New Jersey assigns these counties to payment region 2 under the Low Income Home Energy Assistance Program. values: - '2025-10-01': + 2025-10-01: - SUSSEX_COUNTY_NJ - WARREN_COUNTY_NJ metadata: diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml index 7c593b498c8..c3f8e5f9eb2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml @@ -2,22 +2,22 @@ # "FY2026 Program Income Limit ... (60% State Median Income)": # https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 # The income test is monthly (FY2026 LIHEAP Handbook section 2.3.A, page 7), so -# each expected value is the published monthly limit times 12: +# each expected value is the published monthly limit times 12. This file +# asserts the odd sizes of the published table (1, 3, 5, 7, 9 and 11) plus the +# additional-member increment; the grid cases in ../nj_liheap.yaml use the even +# sizes. # size 1: 4,167 * 12 = 50_004 size 7: 10,819 * 12 = 129_828 -# size 2: 5,449 * 12 = 65_388 size 8: 11,059 * 12 = 132_708 # size 3: 6,732 * 12 = 80_784 size 9: 11,299 * 12 = 135_588 -# size 4: 8,014 * 12 = 96_168 size 10: 11,540 * 12 = 138_480 # size 5: 9,296 * 12 = 111_552 size 11: 11,780 * 12 = 141_360 -# size 6: 10,578 * 12 = 126_936 size 12: 12,021 * 12 = 144_252 # "Household members greater than 12 - Please add $241 for each additional -# member for monthly income limit": +# member for monthly income limit", starting from the size-12 limit of 12,021: # size 13: (12,021 + 241) * 12 = 12,262 * 12 = 147_144 # size 14: (12,021 + 2 * 241) * 12 = 12,503 * 12 = 150_036 -- name: Case 1, published monthly limits for sizes 1 to 12 and the additional-member increment. +- name: Case 1, published monthly limits for the odd sizes 1 to 11 and the additional-member increment. period: 2026 input: - heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] - state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] - nj_liheap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + nj_liheap_household_size: [1, 3, 5, 7, 9, 11, 13, 14] output: - nj_liheap_income_limit: [50_004, 65_388, 80_784, 96_168, 111_552, 126_936, 129_828, 132_708, 135_588, 138_480, 141_360, 144_252, 147_144, 150_036] + nj_liheap_income_limit: [50_004, 80_784, 111_552, 129_828, 135_588, 141_360, 147_144, 150_036] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml index 17167853388..4c2552a94f3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml @@ -15,10 +15,13 @@ # 115_920 / 12 = 9,660: the first dollar of the printed rows "$0 - $1000", # "$6440 - $8886", "$8887 - $9659" and "$9660 +". The rows "$1001 - $2000" # and "$2001 - $6439" print the same amounts as "$0 - $1000" (Case 10). -# - Sizes 1, 5, 9 and 13 are the first sizes of the printed columns "1 to 4", -# "5 to 8", "9 to 12" and "13 or More". +# - Sizes 2, 6, 10 and 14 are the smallest even sizes in the printed columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More". One even size stands for +# each size group here; the odd sizes are asserted in +# eligibility/nj_liheap_income_limit.yaml. -# Deliverables panel, "All Other (19) counties". Printed cells by row: +# Deliverables panel, "All Other (19) counties", sizes 2, 6, 10 and 14 (columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Printed cells by row: # $0 - $1000: 641, 859, 1,025, 1,128 # $6440 - $8886: 535, 715, 855, 941 # $8887 - $9659: 428, 573, 685, 754 @@ -29,14 +32,15 @@ state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] - nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_household_size: [2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14] nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [641, 859, 1_025, 1_128, 535, 715, 855, 941, 428, 573, 685, 754, 321, 428, 513, 564] -# Deliverables panel, "Warren & Sussex Counties". Printed cells by row: +# Deliverables panel, "Warren & Sussex Counties", sizes 2, 6, 10 and 14 (columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Printed cells by row: # $0 - $1000: 961, 983, 1,162, 1,278 # $6440 - $8886: 613, 820, 979, 1,077 # $8887 - $9659: 491, 657, 784, 862 @@ -48,14 +52,15 @@ state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] - nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_household_size: [2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14] nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL, FUEL_OIL] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [961, 983, 1_162, 1_278, 613, 820, 979, 1_077, 491, 657, 784, 862, 366, 493, 587, 646] -# Electric panel, "All Other (19) counties". Printed cells by row: +# Electric panel, "All Other (19) counties", sizes 2, 6, 10 and 14 (columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Printed cells by row: # $0 - $1000: 529, 710, 846, 931 # $6440 - $8886: 442, 591, 705, 776 # $8887 - $9659: 352, 473, 564, 620 @@ -66,14 +71,15 @@ state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] - nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_household_size: [2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14] nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [529, 710, 846, 931, 442, 591, 705, 776, 352, 473, 564, 620, 265, 354, 424, 466] -# Electric panel, "Warren & Sussex Counties". Printed cells by row: +# Electric panel, "Warren & Sussex Counties", sizes 2, 6, 10 and 14 (columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Printed cells by row: # $0 - $1000: 606, 821, 970, 1,067 # $6440 - $8886: 506, 675, 807, 888 # $8887 - $9659: 404, 541, 646, 711 @@ -84,14 +90,15 @@ state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] - nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_household_size: [2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14] nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY, ELECTRICITY] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [606, 821, 970, 1_067, 506, 675, 807, 888, 404, 541, 646, 711, 304, 406, 485, 534] -# Gas panel, "All Other (19) counties". Printed cells by row: +# Gas panel, "All Other (19) counties", sizes 2, 6, 10 and 14 (columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Printed cells by row: # $0 - $1000: 334, 448, 535, 589 # $6440 - $8886: 278, 373, 446, 491 # $8887 - $9659: 222, 298, 355, 391 @@ -102,14 +109,15 @@ state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] - nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_household_size: [2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14] nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [334, 448, 535, 589, 278, 373, 446, 491, 222, 298, 355, 391, 167, 224, 267, 294] -# Gas panel, "Warren & Sussex Counties". Printed cells by row: +# Gas panel, "Warren & Sussex Counties", sizes 2, 6, 10 and 14 (columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Printed cells by row: # $0 - $1000: 383, 512, 612, 673 # $6440 - $8886: 318, 427, 509, 560 # $8887 - $9659: 254, 341, 408, 445 @@ -120,15 +128,17 @@ state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] - nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_household_size: [2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14] nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] output: nj_liheap: [383, 512, 612, 673, 318, 427, 509, 560, 254, 341, 408, 445, 191, 256, 306, 337] -# Renters panel, "All Other (19) counties". Heat is included in rent, so the -# fuel is not needed (handbook section 3.2.F.2, page 12). Printed cells by row: +# Renters panel, "All Other (19) counties", sizes 2, 6, 10 and 14 (columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Heat is included in rent, so +# the fuel is not needed (handbook section 3.2.F.2, page 12). Printed cells by +# row: # $0 - $1000: 234, 312, 374, 411 # $6440 - $8886: 196, 262, 312, 343 # $8887 - $9659: 156, 208, 250, 275 @@ -139,14 +149,15 @@ state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] - nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_household_size: [2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14] nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] output: nj_liheap: [234, 312, 374, 411, 196, 262, 312, 343, 156, 208, 250, 275, 118, 157, 186, 205] -# Renters panel, "Warren & Sussex Counties". Printed cells by row: +# Renters panel, "Warren & Sussex Counties", sizes 2, 6, 10 and 14 (columns +# "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Printed cells by row: # $0 - $1000: 267, 360, 428, 471 # $6440 - $8886: 222, 299, 358, 394 # $8887 - $9659: 179, 240, 286, 315 @@ -157,7 +168,7 @@ state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] nj_liheap_eligible: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] - nj_liheap_household_size: [1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13, 1, 5, 9, 13] + nj_liheap_household_size: [2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14, 2, 6, 10, 14] nj_liheap_countable_income: [0, 0, 0, 0, 77_280, 77_280, 77_280, 77_280, 106_644, 106_644, 106_644, 106_644, 115_920, 115_920, 115_920, 115_920] heating_type: [UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] heat_expense_included_in_rent: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true] diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py index ddc7a24dd95..c4d48941db6 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py @@ -11,7 +11,12 @@ class nj_liheap_eligible(Variable): # PDF pages 5, 6, 7, 11, 12. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5", ) - documentation = "Automatic enrollment does not waive the income test, and regular heating has no asset test. Striker and institutional-residence exclusions, full utility-allowance coverage and payments by people outside the household need inputs not available here. Unknown county is unsupported, not a legal denial." + documentation = ( + "Automatic enrollment does not waive the income test, and regular heating has " + "no asset test. Striker and institutional-residence exclusions, full " + "utility-allowance coverage and payments by people outside the household need " + "inputs not available here. Unknown county is unsupported, not a legal denial." + ) def formula(spm_unit, period, parameters): heat_in_rent = spm_unit("heat_expense_included_in_rent", period) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py index 44152df120f..e7b2b3420e1 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py @@ -11,6 +11,12 @@ class nj_liheap_household_size(Variable): # PDF pages 5, 6, 10. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5", ) - documentation = "Qualified SPM members approximate the economic household. The federal qualified-noncitizen indicator is used without SNAP-specific bars. Foster residents, tax-dependent students away at school, and separate roomer/boarder households require correct SPM membership; not all protected immigration statuses have an enum choice." + documentation = ( + "Qualified SPM members approximate the economic household. The federal " + "qualified-noncitizen indicator is used without SNAP-specific bars. Foster " + "residents, tax-dependent students away at school, and separate roomer/boarder " + "households require correct SPM membership; not all protected immigration " + "statuses have an enum choice." + ) adds = ["is_citizen_or_legal_immigrant"] diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py index 4c83073d78d..70d5db6f291 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py @@ -14,7 +14,13 @@ class nj_liheap_income_limit(Variable): "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", "https://www.nj.gov/dca/hmfa/about/regulations/docs/noticeofadoption10.20.25njr.pdf#page=6", ) - documentation = "FY2026 handbook and published limits use 60% SMI rather than the codified 175%-FPG ceiling. Chapter 5:49 was readopted without change effective September 22, 2025; its 2017 expiration does not resolve this conflict. This draft follows the operating handbook while legal reconciliation remains open. Annualized monthly limits control this monthly-income eligibility test." + documentation = ( + "FY2026 handbook and published limits use 60% SMI rather than the codified " + "175%-FPG ceiling. Chapter 5:49 was readopted without change effective " + "September 22, 2025; its 2017 expiration does not resolve this conflict. This " + "draft follows the operating handbook while legal reconciliation remains open. " + "Annualized monthly limits control this monthly-income eligibility test." + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nj.dca.liheap.eligibility diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py index 79254d4069e..47b4c0d161d 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py @@ -12,7 +12,12 @@ class nj_liheap_countable_income(Variable): # PDF pages 6, 9, 10. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6", ) - documentation = "Annual inputs approximate the four-week verification period. The summed monthly income is rounded to the nearest dollar, with half dollars rounded up. WFNJ benefits are counted once at the unit level; rental income is assumed nonnegative." + documentation = ( + "Annual inputs approximate the four-week verification period. The summed " + "monthly income is rounded to the nearest dollar, with half dollars rounded " + "up. WFNJ benefits are counted once at the unit level; rental income is " + "assumed nonnegative." + ) def formula(spm_unit, period, parameters): # The annual TANF aggregate applies take-up to WFNJ entitlement. diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py index 42459325e79..8e9437a8753 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py @@ -12,7 +12,15 @@ class nj_liheap_countable_income_person(Variable): # PDF pages 6, 7, 8, 9, 10. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6", ) - documentation = "Uses existing net self-employment inputs without extra deductions; flooring losses is a modeling convention. Child earnings follow the FY2026 plan. Social Security of children and documented veterans benefits are excluded by the handbook. SSI Lifeline supplements, gifts, foster payments, royalties and roomer receipts cannot be separately identified. The handbook uses a $500 monthly nonqualified-member disregard while the readopted regulation still says $268." + documentation = ( + "Uses existing net self-employment inputs without extra deductions; flooring " + "losses is a modeling convention. Child earnings follow the FY2026 plan. " + "Social Security of children and documented veterans benefits are excluded by " + "the handbook. SSI Lifeline supplements, gifts, foster payments, royalties and " + "roomer receipts cannot be separately identified. The handbook uses a $500 " + "monthly nonqualified-member disregard while the readopted regulation still " + "says $268." + ) def formula(person, period, parameters): p = parameters(period).gov.states.nj.dca.liheap.income diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py index 64205b072cb..d114b5e4ce6 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py @@ -15,7 +15,14 @@ class nj_liheap(Variable): # PDF pages 9, 10. "https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=9", ) - documentation = "Annual regular heating payment, verified for FY2026. Earlier years use backfilled parameters and are unverified historical estimates. Amounts preserve all published grid anomalies; no expense cap applies. Unknown/unsupported direct fuels return zero. Separate fuel charges paid to landlords cannot be distinguished from vendor bills without a direct benefit override. Crisis, cooling, furnace and utility-program benefits are excluded." + documentation = ( + "Annual regular heating payment, verified for FY2026. Earlier years use " + "backfilled parameters and are unverified historical estimates. Amounts " + "preserve all published grid anomalies; no expense cap applies. " + "Unknown/unsupported direct fuels return zero. Separate fuel charges paid to " + "landlords cannot be distinguished from vendor bills without a direct benefit " + "override. Crisis, cooling, furnace and utility-program benefits are excluded." + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nj.dca.liheap.payment diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py index 160ca69889d..9095b4673a6 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py @@ -12,7 +12,11 @@ class nj_liheap_income_band(Variable): # PDF pages 7, 9, 12. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", ) - documentation = "The grid does not label the income period; monthly follows the handbook income test and the historical monthly thresholds used in the grid. Three identical initial rows are combined." + documentation = ( + "The grid does not label the income period; monthly follows the handbook " + "income test and the historical monthly thresholds used in the grid. Three " + "identical initial rows are combined." + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nj.dca.liheap.payment diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py index 70453bd77c2..556fe716e7a 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py @@ -8,7 +8,10 @@ class nj_liheap_region(Variable): label = "New Jersey LIHEAP payment region" defined_for = StateCode.NJ reference = ("https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf",) - documentation = "Region 2 is Warren/Sussex; region 1 is the other nineteen counties. Zero means a county is unknown or outside New Jersey." + documentation = ( + "Region 2 is Warren/Sussex; region 1 is the other nineteen counties. Zero " + "means a county is unknown or outside New Jersey." + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nj.dca.liheap.payment.regions From 1abb5bf9d7defeb825eb4a6fc6808fee56a1dd22 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 6 Oct 2026 17:07:05 -0400 Subject: [PATCH 8/9] Address review round 1 on New Jersey LIHEAP - Pay the renter level to rent-subsidy and public-housing households that pay their own heating bill (N.J.A.C. 5:49-2.2(d)1.i). - Count Social Security net of the Medicare Part B premium; floor every unearned source. - Derive the additional-member increment from the size-12 and size-11 limits; add the FY2027 handbook, matrix, fact sheet and plan; verified_years "2026-2027"; document the FY2027 474 renters cell. - Read the electric panel for solar heat. - Add cases for subsidized direct payers, the FY2027 limits and amounts, size-group edges, heat in rent over gas, age 18, the student arms and the Atlantic County default. - Re-template descriptions, unquote keys, add separators and retarget the reference anchors. Co-Authored-By: Claude Fable 5.1 --- changelog.d/nj-liheap.added.md | 2 +- .../liheap/eligibility/max_table_size.yaml | 4 +- .../nj/dca/liheap/eligibility/smi_rate.yaml | 9 ++ .../nj/dca/liheap/income/adult_age.yaml | 8 +- .../income/nonqualified_member_disregard.yaml | 6 +- .../nj/dca/liheap/income/sources/earned.yaml | 12 +- .../dca/liheap/income/sources/unearned.yaml | 12 +- .../liheap/payment/amount/deliverables.yaml | 20 +-- .../dca/liheap/payment/amount/electric.yaml | 12 +- .../nj/dca/liheap/payment/amount/gas.yaml | 10 +- .../nj/dca/liheap/payment/amount/renters.yaml | 12 +- .../liheap/payment/household_size_group.yaml | 4 +- .../nj/dca/liheap/payment/income_band.yaml | 10 +- .../dca/liheap/payment/regions/region_1.yaml | 6 +- .../dca/liheap/payment/regions/region_2.yaml | 6 +- policyengine_us/programs.yaml | 4 +- .../eligibility/nj_liheap_eligible.yaml | 55 +++++-- .../eligibility/nj_liheap_income_limit.yaml | 49 +++--- .../income/nj_liheap_countable_income.yaml | 2 - .../nj_liheap_countable_income_person.yaml | 90 +++++++++-- .../gov/states/nj/dca/liheap/integration.yaml | 32 ++++ .../gov/states/nj/dca/liheap/nj_liheap.yaml | 148 +++++++++++++++++- .../liheap/eligibility/nj_liheap_eligible.py | 6 + .../eligibility/nj_liheap_income_limit.py | 44 +++--- .../income/nj_liheap_countable_income.py | 11 +- .../nj_liheap_countable_income_person.py | 45 ++++-- .../gov/states/nj/dca/liheap/nj_liheap.py | 49 ++++-- .../liheap/payment/nj_liheap_income_band.py | 4 +- .../nj/dca/liheap/payment/nj_liheap_region.py | 8 +- 29 files changed, 528 insertions(+), 152 deletions(-) diff --git a/changelog.d/nj-liheap.added.md b/changelog.d/nj-liheap.added.md index 5770adc16c0..31437ef6299 100644 --- a/changelog.d/nj-liheap.added.md +++ b/changelog.d/nj-liheap.added.md @@ -1 +1 @@ -Add New Jersey LIHEAP regular heating assistance for FY2026. +Add New Jersey LIHEAP regular heating assistance for FY2026 and FY2027. diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml index e598e0f49e1..b1428c91d48 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml @@ -1,4 +1,4 @@ -description: New Jersey prints income limits through this household size before using a fixed monthly increment under the Low Income Home Energy Assistance Program. +description: New Jersey sets income limits through this household size, with a fixed monthly increment for each additional member, under the Low Income Home Energy Assistance Program. values: 2025-10-01: 12 metadata: @@ -8,3 +8,5 @@ metadata: reference: - title: FFY2026 LIHEAP and USF fact sheet, income guidelines href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 + - title: FFY2027 LIHEAP and USF fact sheet, income guidelines + href: https://nj.gov/dca/dhcr/offices/docs/FY2027%20USFHEA%20Factsheet%20-%20English.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml index ea9f5738d2c..61a22552b75 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml @@ -1,4 +1,7 @@ description: New Jersey limits monthly income to this share of state median income under the Low Income Home Energy Assistance Program. +# In force since FY2022, when the test moved from a poverty-level standard to +# 60% SMI (BPU announcement of October 19, 2021). Earlier periods carry the +# rate back as unverified estimates. values: 2025-10-01: 0.6 metadata: @@ -8,5 +11,11 @@ metadata: reference: - title: FY2026 LIHEAP Handbook, section 2.3.A href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7 + - title: FY2027 LIHEAP Handbook, section 2.3.A + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=7 - title: FY2026 LIHEAP State Plan, section 2.1 href: https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=9 + - title: FY2027 LIHEAP State Plan, section 2.1 + href: https://www.nj.gov/dca/dhcr/offices/docs/LIHEAP_Detailed_Model_Plan.pdf#page=9 + - title: NJ Board of Public Utilities, Utility Assistance Week announcement, October 19, 2021 + href: https://www.nj.gov/bpu/newsroom/2021/approved/20211019.html diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml index c971201c2a3..a401d38c895 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml @@ -6,7 +6,11 @@ metadata: period: year label: New Jersey LIHEAP adult income age reference: - - title: FY2026 LIHEAP Handbook, section 2.3.E, PDF pages 8, 9 - href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=8 + - title: FY2026 LIHEAP Handbook, section 2.3.E.9 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=9 + - title: FY2027 LIHEAP Handbook, section 2.3.E.9 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=9 - title: FY2026 LIHEAP State Plan, section 1.9 href: https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=7 + - title: FY2027 LIHEAP State Plan, section 1.9 + href: https://www.nj.gov/dca/dhcr/offices/docs/LIHEAP_Detailed_Model_Plan.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml index b80fc3c8efc..ab92b7eaf99 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml @@ -1,4 +1,4 @@ -description: New Jersey excludes this much monthly income of a nonqualified member before adding the excess to household income under the Low Income Home Energy Assistance Program. +description: New Jersey excludes this amount of monthly income of a nonqualified member before adding the excess to household income under the Low Income Home Energy Assistance Program. values: 2025-10-01: 500 metadata: @@ -6,5 +6,7 @@ metadata: period: month label: New Jersey LIHEAP nonqualified member income disregard reference: - - title: FY2026 LIHEAP Handbook + - title: FY2026 LIHEAP Handbook, section 2.2.5 href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6 + - title: FY2027 LIHEAP Handbook, section 2.2.5 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml index 80f254e0dce..facdd4b6b7b 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml @@ -1,4 +1,6 @@ -description: New Jersey uses these reported earnings sources without any additional business expense deduction under the Low Income Home Energy Assistance Program. +description: New Jersey uses these sources as earned income under the Low Income Home Energy Assistance Program. +# Self-employment and farm sources are the model's net inputs; no further +# business-expense deduction is applied. values: 2025-10-01: - employment_income @@ -10,5 +12,11 @@ metadata: period: year label: New Jersey LIHEAP earned sources reference: - - title: FY2026 LIHEAP Handbook, PDF pages 7, 8, 9 + - title: FY2026 LIHEAP Handbook, sections 2.3.C and 2.3.E.3, PDF pages 7, 8 href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7 + - title: FY2027 LIHEAP Handbook, sections 2.3.C and 2.3.E.3, PDF pages 7, 8 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=7 + - title: FY2026 LIHEAP State Plan, section 1.9, PDF pages 6, 7 + href: https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=6 + - title: FY2027 LIHEAP State Plan, section 1.9, PDF pages 6, 7 + href: https://www.nj.gov/dca/dhcr/offices/docs/LIHEAP_Detailed_Model_Plan.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml index f028d63e948..6ff97acf96e 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml @@ -1,4 +1,4 @@ -description: New Jersey counts these available unearned income sources under the Low Income Home Energy Assistance Program. +description: New Jersey uses these sources as unearned income under the Low Income Home Energy Assistance Program. values: 2025-10-01: - unemployment_compensation @@ -22,5 +22,11 @@ metadata: period: year label: New Jersey LIHEAP unearned sources reference: - - title: FY2026 LIHEAP Handbook, PDF pages 7, 8, 9, 10 - href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7 + - title: FY2026 LIHEAP Handbook, sections 2.3.D and 2.3.E, PDF pages 8, 9 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=8 + - title: FY2027 LIHEAP Handbook, sections 2.3.D and 2.3.E, PDF pages 8, 9 + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=8 + - title: FY2026 LIHEAP State Plan, section 1.9, PDF pages 6, 7 + href: https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=6 + - title: FY2027 LIHEAP State Plan, section 1.9, PDF pages 6, 7 + href: https://www.nj.gov/dca/dhcr/offices/docs/LIHEAP_Detailed_Model_Plan.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml index dbb2bf934a5..854030e364f 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml @@ -1,14 +1,14 @@ -description: New Jersey pays this annual regular heating benefit in the deliverables panel under the Low Income Home Energy Assistance Program, by county region, monthly income band and household size group. -'1': +description: New Jersey provides this annual regular heating benefit to households in the deliverables panel, by county region, monthly income band and household size group, under the Low Income Home Energy Assistance Program. +1: 1: 1: 2025-10-01: 641 2: 2025-10-01: 859 3: - 2025-10-01: 1025 + 2025-10-01: 1_025 4: - 2025-10-01: 1128 + 2025-10-01: 1_128 2: 1: 2025-10-01: 535 @@ -36,16 +36,16 @@ description: New Jersey pays this annual regular heating benefit in the delivera 2025-10-01: 513 4: 2025-10-01: 564 -'2': +2: 1: 1: 2025-10-01: 961 2: 2025-10-01: 983 3: - 2025-10-01: 1162 + 2025-10-01: 1_162 4: - 2025-10-01: 1278 + 2025-10-01: 1_278 2: 1: 2025-10-01: 613 @@ -54,7 +54,7 @@ description: New Jersey pays this annual regular heating benefit in the delivera 3: 2025-10-01: 979 4: - 2025-10-01: 1077 + 2025-10-01: 1_077 3: 1: 2025-10-01: 491 @@ -82,5 +82,7 @@ metadata: - range(1, 5) - range(1, 5) reference: - - title: FY2026 heating benefit grid + - title: FY2026 Benefit Matrix href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + - title: FY2027 Benefit Matrix + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml index 8e2fafdab30..ac77465c1ea 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml @@ -1,5 +1,5 @@ -description: New Jersey pays this annual regular heating benefit in the electric panel under the Low Income Home Energy Assistance Program, by county region, monthly income band and household size group. -'1': +description: New Jersey provides this annual regular heating benefit to households in the electric panel, by county region, monthly income band and household size group, under the Low Income Home Energy Assistance Program. +1: 1: 1: 2025-10-01: 529 @@ -36,7 +36,7 @@ description: New Jersey pays this annual regular heating benefit in the electric 2025-10-01: 424 4: 2025-10-01: 466 -'2': +2: 1: 1: 2025-10-01: 606 @@ -45,7 +45,7 @@ description: New Jersey pays this annual regular heating benefit in the electric 3: 2025-10-01: 970 4: - 2025-10-01: 1067 + 2025-10-01: 1_067 2: 1: 2025-10-01: 506 @@ -82,5 +82,7 @@ metadata: - range(1, 5) - range(1, 5) reference: - - title: FY2026 heating benefit grid + - title: FY2026 Benefit Matrix href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + - title: FY2027 Benefit Matrix + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml index 0b9b4d33f70..615dfeaad78 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml @@ -1,5 +1,5 @@ -description: New Jersey pays this annual regular heating benefit in the gas panel under the Low Income Home Energy Assistance Program, by county region, monthly income band and household size group. -'1': +description: New Jersey provides this annual regular heating benefit to households in the gas panel, by county region, monthly income band and household size group, under the Low Income Home Energy Assistance Program. +1: 1: 1: 2025-10-01: 334 @@ -36,7 +36,7 @@ description: New Jersey pays this annual regular heating benefit in the gas pane 2025-10-01: 267 4: 2025-10-01: 294 -'2': +2: 1: 1: 2025-10-01: 383 @@ -82,5 +82,7 @@ metadata: - range(1, 5) - range(1, 5) reference: - - title: FY2026 heating benefit grid + - title: FY2026 Benefit Matrix href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + - title: FY2027 Benefit Matrix + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml index 42363c5eec4..f46a9eb73e4 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml @@ -1,5 +1,5 @@ -description: New Jersey pays this annual regular heating benefit in the renters panel under the Low Income Home Energy Assistance Program, by county region, monthly income band and household size group. -'1': +description: New Jersey provides this annual regular heating benefit to households in the renters panel, by county region, monthly income band and household size group, under the Low Income Home Energy Assistance Program. +1: 1: 1: 2025-10-01: 234 @@ -36,7 +36,7 @@ description: New Jersey pays this annual regular heating benefit in the renters 2025-10-01: 186 4: 2025-10-01: 205 -'2': +2: 1: 1: 2025-10-01: 267 @@ -44,6 +44,8 @@ description: New Jersey pays this annual regular heating benefit in the renters 2025-10-01: 360 3: 2025-10-01: 428 + # The FY2027 matrix prints 474 in the $2,001 to $6,439 row of this cell + # and 471 in the band's other two rows; the combined band keeps 471. 4: 2025-10-01: 471 2: @@ -82,5 +84,7 @@ metadata: - range(1, 5) - range(1, 5) reference: - - title: FY2026 heating benefit grid + - title: FY2026 Benefit Matrix href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + - title: FY2027 Benefit Matrix + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml index 59ecd17a79b..8abcde28a01 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml @@ -23,5 +23,7 @@ metadata: period: year label: New Jersey LIHEAP household size group reference: - - title: FY2026 heating benefit grid + - title: FY2026 Benefit Matrix href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + - title: FY2027 Benefit Matrix + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml index b2cb767faff..17888b6460d 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml @@ -6,15 +6,15 @@ brackets: amount: 2025-10-01: 1 - threshold: - 2025-10-01: 6440 + 2025-10-01: 6_440 amount: 2025-10-01: 2 - threshold: - 2025-10-01: 8887 + 2025-10-01: 8_887 amount: 2025-10-01: 3 - threshold: - 2025-10-01: 9660 + 2025-10-01: 9_660 amount: 2025-10-01: 4 metadata: @@ -24,5 +24,7 @@ metadata: period: month label: New Jersey LIHEAP monthly income band reference: - - title: FY2026 heating benefit grid + - title: FY2026 Benefit Matrix href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + - title: FY2027 Benefit Matrix + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml index 6698cb7fcbf..c969c0a447e 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml @@ -1,4 +1,4 @@ -description: New Jersey assigns these counties to payment region 1 under the Low Income Home Energy Assistance Program. +description: New Jersey uses these counties as payment region 1 under the Low Income Home Energy Assistance Program. values: 2025-10-01: - ATLANTIC_COUNTY_NJ @@ -25,5 +25,7 @@ metadata: period: year label: New Jersey LIHEAP region 1 counties reference: - - title: FY2026 heating benefit grid, county headings + - title: FY2026 Benefit Matrix, county headings href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + - title: FY2027 Benefit Matrix, county headings + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml index 5d0916f60c3..26ff07d2c7f 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml @@ -1,4 +1,4 @@ -description: New Jersey assigns these counties to payment region 2 under the Low Income Home Energy Assistance Program. +description: New Jersey uses these counties as payment region 2 under the Low Income Home Energy Assistance Program. values: 2025-10-01: - SUSSEX_COUNTY_NJ @@ -8,5 +8,7 @@ metadata: period: year label: New Jersey LIHEAP region 2 counties reference: - - title: FY2026 heating benefit grid, county headings + - title: FY2026 Benefit Matrix, county headings href: https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf + - title: FY2027 Benefit Matrix, county headings + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 6c2bb44480f..d0db805a7c3 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -877,8 +877,8 @@ programs: full_name: New Jersey Low Income Home Energy Assistance Program variable: nj_liheap parameter_prefix: gov.states.nj.dca.liheap - verified_years: "2026" - notes: FY2026 regular heating only, covering eligibility, countable income and the benefit grid. Crisis, cooling and equipment assistance are out of scope. + verified_years: "2026-2027" + notes: FY2026-FY2027 regular heating only, covering eligibility, countable income and the benefit grid; the FY2027 grid repeats FY2026 except one printed renters cell. Crisis, cooling and equipment assistance are out of scope. - state: TX status: partial name: Texas CEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml index d87abeac636..6b15e9404d2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml @@ -4,6 +4,8 @@ # - FY2026 LIHEAP Handbook, sections 2.2 (pages 5 and 6), 2.3.B (page 7) and # 3.1.a.2 (page 11): # https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5 +# - N.J.A.C. 5:49-2.3(b), the public housing and rent subsidy denials: +# https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-3 # - FY2026 Benefit Matrix (one page): # https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf @@ -25,24 +27,28 @@ output: nj_liheap_eligible: [true, false] -# Two renters with heat included in rent and no income. Handbook section 2.2 -# (page 6) makes a renter whose heating costs are included in rent eligible, -# and lists as not eligible households "receiving a rent subsidy which includes -# all heating costs". -# - No rent subsidy: eligible. -# - Rent subsidy: not eligible, even with a heating bill reported. -- name: Case 2, heat included in subsidized rent is ineligible. +# Three renters with heat included in rent, no bill of their own and no income. +# Handbook section 2.2 (page 6) makes a renter whose heating costs are included +# in rent eligible, and lists as not eligible "Households residing in publicly +# operated housing where their heat is included in their rent or are receiving +# a rent subsidy which includes all heating costs" (also N.J.A.C. +# 5:49-2.3(b)1 and 2). +# - Unsubsidized rent: eligible. +# - Section 8 voucher: not eligible. +# - Public housing: not eligible. +- name: Case 2, heat included in subsidized or public housing rent is ineligible. period: 2026 input: - state_code: [NJ, NJ] - county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] - nj_liheap_countable_income: [0, 0] - has_heating_expense: [true, true] - heating_type: [NATURAL_GAS, NATURAL_GAS] - heat_expense_included_in_rent: [true, true] - receives_housing_assistance: [false, true] + state_code: [NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_countable_income: [0, 0, 0] + has_heating_expense: [false, false, false] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + heat_expense_included_in_rent: [true, true, true] + receives_housing_assistance: [false, true, false] + is_in_public_housing: [false, false, true] output: - nj_liheap_eligible: [true, false] + nj_liheap_eligible: [true, false, false] # Handbook section 2.2 (page 6), ineligible households item 3, and section # 2.3.B.5 (page 7): "Households consisting entirely of students who are tax @@ -90,10 +96,27 @@ period: 2026 input: state_code: [NJ, NJ, NY] - county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, KINGS_COUNTY_NY] nj_liheap_countable_income: [0, 0, 0] has_heating_expense: [false, true, true] heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] immigration_status: [CITIZEN, UNDOCUMENTED, CITIZEN] output: nj_liheap_eligible: [false, false, false] + +# The students-only denial (handbook section 2.2, page 6, item 3) needs both +# conditions: a full-time student who is nobody's tax dependent, and a tax +# dependent who is not a student, each living alone with a heating bill and no +# income, are both eligible. +- name: Case 6, a student who is not a dependent and a dependent who is not a student are eligible. + period: 2026 + input: + state_code: [NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_countable_income: [0, 0] + has_heating_expense: [true, true] + heating_type: [NATURAL_GAS, NATURAL_GAS] + is_full_time_student: [true, false] + is_tax_unit_dependent: [false, true] + output: + nj_liheap_eligible: [true, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml index c3f8e5f9eb2..c4880b9d560 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml @@ -1,23 +1,36 @@ -# Source for the expected values in this file: FFY 2026 fact sheet, page 2, -# "FY2026 Program Income Limit ... (60% State Median Income)": -# https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 +# Sources for the expected values in this file: +# - FFY 2026 fact sheet, page 2, "FY2026 Program Income Limit ... (60% State +# Median Income)": +# https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2 +# - FFY 2027 fact sheet, page 2: +# https://nj.gov/dca/dhcr/offices/docs/FY2027%20USFHEA%20Factsheet%20-%20English.pdf#page=2 # The income test is monthly (FY2026 LIHEAP Handbook section 2.3.A, page 7), so -# each expected value is the published monthly limit times 12. This file -# asserts the odd sizes of the published table (1, 3, 5, 7, 9 and 11) plus the -# additional-member increment; the grid cases in ../nj_liheap.yaml use the even -# sizes. -# size 1: 4,167 * 12 = 50_004 size 7: 10,819 * 12 = 129_828 -# size 3: 6,732 * 12 = 80_784 size 9: 11,299 * 12 = 135_588 -# size 5: 9,296 * 12 = 111_552 size 11: 11,780 * 12 = 141_360 +# each expected value is the published monthly limit times 12. + +# FY2026 monthly limits for sizes 1 to 12: +# 4,167 5,449 6,732 8,014 9,296 10,578 +# 10,819 11,059 11,299 11,540 11,780 12,021 # "Household members greater than 12 - Please add $241 for each additional -# member for monthly income limit", starting from the size-12 limit of 12,021: -# size 13: (12,021 + 241) * 12 = 12,262 * 12 = 147_144 -# size 14: (12,021 + 2 * 241) * 12 = 12,503 * 12 = 150_036 -- name: Case 1, published monthly limits for the odd sizes 1 to 11 and the additional-member increment. +# member for monthly income limit": size 13 = 12,262 and size 14 = 12,503. +- name: Case 1, FY2026 published monthly limits for sizes 1 to 12 and the additional-member increment. period: 2026 input: - heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] - state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] - nj_liheap_household_size: [1, 3, 5, 7, 9, 11, 13, 14] + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + nj_liheap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] output: - nj_liheap_income_limit: [50_004, 80_784, 111_552, 129_828, 135_588, 141_360, 147_144, 150_036] + nj_liheap_income_limit: [50_004, 65_388, 80_784, 96_168, 111_552, 126_936, 129_828, 132_708, 135_588, 138_480, 141_360, 144_252, 147_144, 150_036] + +# FY2027 monthly limits for sizes 1 to 12: +# 4,273 5,587 6,902 8,217 9,532 10,846 +# 11,093 11,339 11,586 11,832 12,079 12,325 +# "Household members greater than 12 - Please add $246 for each additional +# member for monthly income limit": size 13 = 12,571 and size 14 = 12,817. The +# increment is the difference between the size-12 and size-11 limits in both +# years (12,021 - 11,780 = 241; 12,325 - 12,079 = 246). +- name: Case 2, FY2027 published monthly limits for sizes 1 to 12 and the additional-member increment. + period: 2027 + input: + state_code: [NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ] + nj_liheap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] + output: + nj_liheap_income_limit: [51_276, 67_044, 82_824, 98_604, 114_384, 130_152, 133_116, 136_068, 139_032, 141_984, 144_948, 147_900, 150_852, 153_804] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml index d4e0a549993..a66f6e9c358 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml @@ -13,7 +13,6 @@ - name: Case 1, monthly household income rounds to the nearest dollar after TANF is added once. period: 2026 input: - heating_type: [NATURAL_GAS, NATURAL_GAS] state_code: [NJ, NJ] nj_liheap_countable_income_person: [10_001, 10_002] tanf: [1_200, 1_200] @@ -30,7 +29,6 @@ period: 2026 input: state_code: [NJ, NJ] - heating_type: [NATURAL_GAS, NATURAL_GAS] age: [40, 40] nj_wfnj: [1_200, 1_200] takes_up_tanf_if_eligible: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml index 8af43e42f9e..0de079349e7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml @@ -1,10 +1,11 @@ # Sources for the expected values in this file: -# - FY2026 LIHEAP Handbook, sections 2.2.5 (page 6), 2.3.C (page 7), 2.3.E.3 -# (page 8), 2.3.E.9 and 2.3.E.10 (page 9) and 2.3.F.7 (page 10): +# - FY2026 LIHEAP Handbook, sections 2.2.5 (page 6), 2.3.C (page 7), 2.3.D and +# 2.3.E.3 (page 8), 2.3.E.8, 2.3.E.9 and 2.3.E.10 (page 9) and 2.3.F.7 +# (page 10): # https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6 -# - FY2026 LIHEAP State Plan, section 1.9 (pages 6 and 7; the child earnings -# box is on page 7): -# https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=7 +# - FY2026 LIHEAP State Plan, sections 1.8 and 1.9 (pages 6 and 7; the child +# earnings box is on page 7): +# https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=6 # Household 1 is a parent (person4) living with a 17-year-old (person1) and a # 20-year-old full-time student (person2). Household 2 is a 20-year-old @@ -61,10 +62,8 @@ spm_units: spm_unit1: members: [person1, person2, person4] - heating_type: NATURAL_GAS spm_unit2: members: [person3] - heating_type: NATURAL_GAS households: household1: members: [person1, person2, person4] @@ -79,15 +78,15 @@ # and 5_000 of veterans benefits. # - Age 17: "Social Security benefits for children under 18 years old shall be # excluded" (handbook section 2.3.E.9, page 9), leaving the SSI: 600. -# - Age 40 paying a 1_200 Medicare Part B premium: 12_000 + 600 = 12_600. -# Section 2.3.F.7(a) (page 10) deducts the premium from gross Social Security; -# the model counts Social Security gross and does not read the premium yet. +# - Age 40 paying a 1_200 Medicare Part B premium: section 2.3.F.7(a) (page +# 10) deducts the premium from gross Social Security, and 2.3.E.8 (page 9) +# excludes the Part B buy-in withheld from the check: +# 12_000 - 1_200 + 600 = 11_400. # - Age 40 with no premium: 12_000 + 600 = 12_600. # Veterans benefits are excluded for all three (section 2.3.E.10, page 9). -- name: Case 2, child Social Security is excluded and adult Social Security counts gross. +- name: Case 2, child Social Security is excluded and adult Social Security counts net of the Part B premium. period: 2026 input: - heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] state_code: [NJ, NJ, NJ] age: [17, 40, 40] social_security: [12_000, 12_000, 12_000] @@ -95,7 +94,7 @@ ssi: [600, 600, 600] veterans_benefits: [5_000, 5_000, 5_000] output: - nj_liheap_countable_income_person: [600, 12_600, 12_600] + nj_liheap_countable_income_person: [600, 11_400, 12_600] # Three undocumented adults with wages only. Handbook section 2.2.5 (page 6): # "If the non-qualified citizens have a monthly income of more than $500.00, @@ -107,7 +106,6 @@ - name: Case 3, each nonqualified member has the monthly disregard. period: 2026 input: - heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] state_code: [NJ, NJ, NJ] age: [40, 40, 40] immigration_status: [UNDOCUMENTED, UNDOCUMENTED, UNDOCUMENTED] @@ -115,3 +113,67 @@ ssi: [0, 0, 0] output: nj_liheap_countable_income_person: [0, 0, 1_200] + +# Two adults with 60_000 of wages who each own a rental property. State Plan +# section 1.8 (page 6) counts gross income and handbook section 2.3.D (page 8) +# counts "receipts from the rental of property", so each source is floored at +# zero and a loss does not offset the wages. +# - A 20_000 rental loss: 60_000 + 0 = 60_000. +# - 20_000 of rental income: 60_000 + 20_000 = 80_000. +- name: Case 4, a rental loss is floored at zero and rental income counts. + period: 2026 + input: + state_code: [NJ, NJ] + age: [40, 40] + employment_income: [60_000, 60_000] + rental_income: [-20_000, 20_000] + ssi: [0, 0] + output: + nj_liheap_countable_income_person: [60_000, 80_000] + +# Two people who are not students, each with 12_000 of wages and 6_000 of +# Social Security and no Part B premium. "Earned income of a child under the +# age of 18" (State Plan section 1.9, page 7) and "Social Security benefits for +# children under 18 years old" (handbook section 2.3.E.9, page 9) are excluded, +# so 18 is the first counted age. +# - Age 17: 0. +# - Age 18: 12_000 + 6_000 = 18_000. +- name: Case 5, earnings and Social Security count from age 18. + period: 2026 + input: + state_code: [NJ, NJ] + age: [17, 18] + is_full_time_student: [false, false] + employment_income: [12_000, 12_000] + social_security: [6_000, 6_000] + medicare_part_b_premium: [0, 0] + ssi: [0, 0] + output: + nj_liheap_countable_income_person: [0, 18_000] + +# One adult with every listed unearned source (handbook section 2.3.D, page 8; +# parameter gov.states.nj.dca.liheap.income.sources.unearned) at 100 times its +# position in the list, 100 to 1_400, and no earnings or Social Security: +# 100 * (1 + 2 + ... + 14) = 10_500. +- name: Case 6, every listed unearned source counts. + period: 2026 + input: + state_code: NJ + age: 40 + social_security: 0 + unemployment_compensation: 100 + strike_benefits: 200 + ssi: 300 + pension_income: 400 + survivor_benefits: 500 + general_assistance: 600 + rental_income: 700 + farm_rent_income: 800 + alimony_income: 900 + child_support_received: 1_000 + interest_income: 1_100 + ordinary_dividend_income: 1_200 + workers_compensation: 1_300 + disability_benefits: 1_400 + output: + nj_liheap_countable_income_person: 10_500 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml index 6f0e3db7403..09644c34318 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml @@ -199,3 +199,35 @@ # Gas panel, "All Other (19) counties", row "$6440 - $8886", column # "5 to 8": $373. nj_liheap: 373 + +# Two Hudson County retirees aged 70 living alone, each with $4,200 a month of +# Social Security ($50,400 a year) and natural gas billed in their own name +# (about $1,200 a year). The first pays a Medicare Part B premium of about +# $2,435 a year; the second has it paid by a Medicare Savings Program. +- name: Case 5, Social Security counts net of the Medicare Part B premium the person pays. + period: 2026 + input: + state_code: [NJ, NJ] + county: [HUDSON_COUNTY_NJ, HUDSON_COUNTY_NJ] + age: [70, 70] + social_security: [50_400, 50_400] + medicare_part_b_premium: [2_435, 0] + ssi: [0, 0] + tanf: [0, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_200, 1_200] + output: + # Handbook section 2.3.F.7(a) (page 10) deducts the Part B premium from + # gross Social Security: 50_400 - 2_435 = 47_965. The second retiree pays + # no premium, so 50_400 counts. + nj_liheap_countable_income_person: [47_965, 50_400] + # 47_965 / 12 = 3,997.08 -> 3,997 a month (section 2.3.F, page 9); + # 3,997 * 12 = 47_964. 50_400 / 12 = 4,200, a whole dollar. + nj_liheap_countable_income: [47_964, 50_400] + # One person: $4,167 a month (fact sheet, page 2); 4,167 * 12 = 50_004. + nj_liheap_income_limit: [50_004, 50_004] + # 3,997 does not exceed 4,167; 4,200 does (section 2.3.A, page 7). + nj_liheap_eligible: [true, false] + # Gas panel, "All Other (19) counties", row "$2001 - $6439", column + # "1 to 4": $334. + nj_liheap: [334, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml index 4c2552a94f3..e2622c2d95d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml @@ -7,6 +7,11 @@ # - FY2026 LIHEAP Handbook, sections 2.2 (page 5), 2.3.A (page 7), 3.1.a.3 # (page 11) and 3.2.F (page 12): # https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5 +# - FY2027 Benefit Matrix (one page; identical to FY2026 except one Warren & +# Sussex renters cell, Case 18): +# https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png +# - N.J.A.C. 5:49-2.2(d)1.i, the renter's level for subsidized direct payers +# (Case 13): https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-2 # # Cases 1 to 8 read the printed cells of one panel and one county column each. # Eligibility is set directly because these cases test the grid lookup, not the @@ -17,8 +22,9 @@ # and "$2001 - $6439" print the same amounts as "$0 - $1000" (Case 10). # - Sizes 2, 6, 10 and 14 are the smallest even sizes in the printed columns # "1 to 4", "5 to 8", "9 to 12" and "13 or More". One even size stands for -# each size group here; the odd sizes are asserted in -# eligibility/nj_liheap_income_limit.yaml. +# each size group here; Case 15 crosses the column edges at sizes 8, 9, 12 +# and 13, and eligibility/nj_liheap_income_limit.yaml asserts the published +# limit for every size. # Deliverables panel, "All Other (19) counties", sizes 2, 6, 10 and 14 (columns # "1 to 4", "5 to 8", "9 to 12" and "13 or More"). Printed cells by row: @@ -182,8 +188,11 @@ # - Electricity: Electric panel, $529. Natural gas: Gas panel, $334. # - Oil, kerosene, propane, wood and coal are the delivered fuels (section # 3.1.a.3, page 11) and read the Deliverables panel: $641 each. -# - Solar, other, unspecified and no heating are not listed fuel types, and no -# panel applies to a household paying its own heating bill: $0. +# - Solar: a grid-tied solar home pays an electricity bill, the pairing +# heating_expense uses, so it reads the Electric panel: $529. +# - Other, unspecified and no heating are not listed fuel types, and no panel +# applies to a household paying its own heating bill: $0. The unspecified +# default is tracked in #9754. - name: Case 9, each heating fuel reads its own panel. period: 2026 input: @@ -193,7 +202,7 @@ nj_liheap_countable_income: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] heating_type: [ELECTRICITY, NATURAL_GAS, FUEL_OIL, KEROSENE, PROPANE, WOOD, COAL, SOLAR, OTHER, UNSPECIFIED, NONE] output: - nj_liheap: [529, 334, 641, 641, 641, 641, 641, 0, 0, 0, 0] + nj_liheap: [529, 334, 641, 641, 641, 641, 641, 529, 0, 0, 0] # Gas panel, "All Other (19) counties", column "1 to 4" (size 4). Annual incomes # divided by 12 are the last and first dollars of each printed row: @@ -247,13 +256,10 @@ state_code: NJ county: SUSSEX_COUNTY_NJ age: 45 - immigration_status: CITIZEN employment_income: 36_000 farm_rent_income: 24_000 - rental_income: 0 ssi: 0 tanf: 0 - snap: 0 heating_type: NATURAL_GAS gas_expense: 1_200 output: @@ -264,3 +270,129 @@ nj_liheap_income_limit: 50_004 nj_liheap_eligible: false nj_liheap: 0 + +# Three Essex County adults with $12,000 of wages who heat with electricity +# billed in their own name (about $1,500 a year). Row "$0 - $1000", column +# "1 to 4", "All Other (19) counties". +# - No housing subsidy: Electric panel, $529 (handbook section 3.2.F.1, +# page 12). +# - Section 8 voucher: N.J.A.C. 5:49-2.2(d)1.i, "Households receiving a rent +# subsidy which does not include all of their heating costs and have a +# heating bill in their name are entitled to assistance at a renter's +# benefit level": Renters panel, $234. Handbook section 2.2 (page 6) copies +# (d)1 without that subparagraph and prints no contrary rule. +# - Public housing with its own bill: eligible under N.J.A.C. 5:49-2.3(b)1 and +# read with the rent subsidy, so also $234. +- name: Case 13, subsidized tenants paying their own heating bill receive the renters level. + period: 2026 + input: + state_code: [NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + age: [40, 40, 40] + employment_income: [12_000, 12_000, 12_000] + ssi: [0, 0, 0] + tanf: [0, 0, 0] + heating_type: [ELECTRICITY, ELECTRICITY, ELECTRICITY] + pre_subsidy_electricity_expense: [1_500, 1_500, 1_500] + receives_housing_assistance: [false, true, false] + is_in_public_housing: [false, false, true] + output: + has_heating_expense: [true, true, true] + nj_liheap_eligible: [true, true, true] + nj_liheap: [529, 234, 234] + +# Essex County tenant with $12,000 of wages whose natural-gas heat is included +# in an unsubsidized rent. Handbook section 3.2.F.2 (page 12): households +# whose heat is included in the rent "shall receive benefits as heat is +# included in the rent fuel type", so the known fuel does not read the Gas +# panel ($334). Renters panel, row "$0 - $1000", column "1 to 4": $234. +- name: Case 14, heat included in rent outranks a known heating fuel. + period: 2026 + input: + state_code: NJ + county: ESSEX_COUNTY_NJ + age: 40 + employment_income: 12_000 + ssi: 0 + tanf: 0 + heating_type: NATURAL_GAS + heat_expense_included_in_rent: true + output: + nj_liheap_eligible: true + nj_liheap: 234 + +# Gas panel, "All Other (19) counties", row "$0 - $1000", at the sizes on each +# side of the printed column edges: size 8 is the last of "5 to 8" (448), size +# 9 the first of "9 to 12" (535), size 12 the last of "9 to 12" (535) and size +# 13 the first of "13 or More" (589). +- name: Case 15, household size group edges at 8, 9, 12 and 13. + period: 2026 + input: + state_code: [NJ, NJ, NJ, NJ] + county: [ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ, ESSEX_COUNTY_NJ] + nj_liheap_eligible: [true, true, true, true] + nj_liheap_household_size: [8, 9, 12, 13] + nj_liheap_countable_income: [0, 0, 0, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + output: + nj_liheap: [448, 535, 535, 589] + +# A New Jersey household with no county input takes the first New Jersey +# county, Atlantic, which is under "All Other (19) counties". Single adult, +# $12,000 of wages, natural gas billed in their own name: Gas panel, row +# "$0 - $1000", column "1 to 4": $334. +- name: Case 16, a household with no county input is paid under the other nineteen counties. + period: 2026 + input: + state_code: NJ + age: 40 + employment_income: 12_000 + ssi: 0 + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_300 + output: + nj_liheap_region: 1 + nj_liheap: 334 + +# Essex County adult with $60,000 of wages and a $20,000 rental loss, heating +# with natural gas billed in their own name. State Plan section 1.8 (page 6) +# counts gross income and handbook section 2.3.D (page 8) counts receipts from +# the rental of property, so the loss is floored at zero and does not offset +# the wages: 60_000 / 12 = 5,000 a month exceeds the one-person limit of +# $4,167 (fact sheet, page 2). +- name: Case 17, a rental loss does not offset wages. + period: 2026 + input: + state_code: NJ + county: ESSEX_COUNTY_NJ + age: 40 + employment_income: 60_000 + rental_income: -20_000 + ssi: 0 + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_200 + output: + nj_liheap_countable_income: 60_000 + nj_liheap_eligible: false + nj_liheap: 0 + +# FY2027 Benefit Matrix, Renters panel, "Warren & Sussex Counties", column +# "13 or More": the rows "$0 - $1000" and "$1001 - $2000" print 471 and the +# row "$2001 - $6439" prints 474, where every other year prints 471 in all +# three. The model combines the three rows and keeps 471 for all of them. +# Monthly incomes 12_000 / 12 = 1,000 and 36_000 / 12 = 3,000. +- name: Case 18, FY2027 Warren and Sussex renters with 13 members keep the combined band value. + period: 2027 + input: + state_code: [NJ, NJ] + county: [WARREN_COUNTY_NJ, WARREN_COUNTY_NJ] + nj_liheap_eligible: [true, true] + nj_liheap_household_size: [13, 13] + nj_liheap_countable_income: [12_000, 36_000] + heating_type: [UNSPECIFIED, UNSPECIFIED] + heat_expense_included_in_rent: [true, true] + output: + nj_liheap_income_band: [1, 1] + nj_liheap: [471, 471] diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py index c4d48941db6..45308824e2b 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py @@ -10,6 +10,10 @@ class nj_liheap_eligible(Variable): reference = ( # PDF pages 5, 6, 7, 11, 12. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5", + # PDF pages 5, 6, 7, 12, 13. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=5", + "https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-2", + "https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-3", ) documentation = ( "Automatic enrollment does not waive the income test, and regular heating has " @@ -20,6 +24,8 @@ class nj_liheap_eligible(Variable): def formula(spm_unit, period, parameters): heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + # Handbook 2.2 (page 6) and N.J.A.C. 5:49-2.3(b)1-2 deny public housing + # and rent-subsidy households only when the subsidy covers the heat. subsidized = spm_unit( "receives_housing_assistance", period ) | spm_unit.household("is_in_public_housing", period) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py index 70d5db6f291..d2a857ca933 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py @@ -11,35 +11,41 @@ class nj_liheap_income_limit(Variable): defined_for = StateCode.NJ reference = ( "https://nj.gov/dca/dhcr/offices/docs/FY2026%20USFHEA%20Factsheet%20-%20English.pdf#page=2", + "https://nj.gov/dca/dhcr/offices/docs/FY2027%20USFHEA%20Factsheet%20-%20English.pdf#page=2", "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=7", + "https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf#page=2", "https://www.nj.gov/dca/hmfa/about/regulations/docs/noticeofadoption10.20.25njr.pdf#page=6", + "https://www.nj.gov/bpu/newsroom/2021/approved/20211019.html", ) documentation = ( - "FY2026 handbook and published limits use 60% SMI rather than the codified " - "175%-FPG ceiling. Chapter 5:49 was readopted without change effective " - "September 22, 2025; its 2017 expiration does not resolve this conflict. This " - "draft follows the operating handbook while legal reconciliation remains open. " - "Annualized monthly limits control this monthly-income eligibility test." + "The FY2026 and FY2027 handbooks and published limits use 60% SMI rather " + "than the codified 175%-FPG ceiling. Chapter 5:49 was readopted without " + "change effective September 22, 2025; the readoption does not reconcile the " + "conflict, and the model follows the handbooks. The 60% SMI test began in " + "FY2022 (BPU announcement of October 19, 2021); earlier periods carry it " + "back and are unverified. Annualized monthly limits control this " + "monthly-income eligibility test." ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nj.dca.liheap.eligibility size = max_(spm_unit("nj_liheap_household_size", period), 1) - capped_size = min_(size, p.max_table_size) state = spm_unit.household("state_code_str", period) smi_parameters = parameters(period).gov.hhs.smi base = smi_parameters.amount[state] - factor = smi(capped_size, state, period, parameters) / base - # Inferred two-stage flooring reproduces all 12 annual limits; - # their monthly column uses half-up rounding (not half-to-even). - annual = np.floor(factor * np.floor(base * p.smi_rate)) - monthly = np.floor(annual / MONTHS_IN_YEAR + 0.5) - # The published monthly increment is rounded up separately. Applying - # the size factor to the whole household would miss the 13+ rows. - step = np.ceil( - base - * p.smi_rate - * smi_parameters.household_size_adjustment.additional_person - / MONTHS_IN_YEAR - ) + + def monthly_limit(table_size): + factor = smi(table_size, state, period, parameters) / base + # ACF LIHEAP IM 2025-02 Attachment 4 (page 2) floors 60% of the + # four-person SMI, then floors each size's share of it; the fact + # sheet's monthly column rounds that half up (not half to even). + annual = np.floor(factor * np.floor(base * p.smi_rate)) + return np.floor(annual / MONTHS_IN_YEAR + 0.5) + + monthly = monthly_limit(min_(size, p.max_table_size)) + # The fact sheet's increment for each member above the table ($241 for + # FY2026, $246 for FY2027) is the difference between its last two + # monthly limits, which rounds the 3% size step where they do. + step = monthly_limit(p.max_table_size) - monthly_limit(p.max_table_size - 1) return (monthly + max_(size - p.max_table_size, 0) * step) * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py index 47b4c0d161d..3d4bc496f8c 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py @@ -10,17 +10,22 @@ class nj_liheap_countable_income(Variable): defined_for = StateCode.NJ reference = ( # PDF pages 6, 9, 10. - "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6", + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=9", + # PDF pages 6, 10, 11. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=10", ) documentation = ( "Annual inputs approximate the four-week verification period. The summed " "monthly income is rounded to the nearest dollar, with half dollars rounded " - "up. WFNJ benefits are counted once at the unit level; rental income is " - "assumed nonnegative." + "up. WFNJ benefits are counted once at the unit level. Every per-person " + "source is floored at zero, so a rental or farm-rent loss does not offset " + "other income." ) def formula(spm_unit, period, parameters): # The annual TANF aggregate applies take-up to WFNJ entitlement. # Benefits received are counted once at the household level. income = add(spm_unit, period, ["nj_liheap_countable_income_person", "tanf"]) + # Handbook 2.3.F (page 9): "Cents shall be rounded to the nearest + # dollar"; an exact half dollar rounds up. return np.floor(max_(income, 0) / MONTHS_IN_YEAR + 0.5) * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py index 8e9437a8753..e9d126ae6f0 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py @@ -11,15 +11,22 @@ class nj_liheap_countable_income_person(Variable): reference = ( # PDF pages 6, 7, 8, 9, 10. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=6", + # PDF pages 6, 7, 8, 9, 11. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=6", + # PDF pages 6, 7. + "https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=6", ) documentation = ( - "Uses existing net self-employment inputs without extra deductions; flooring " - "losses is a modeling convention. Child earnings follow the FY2026 plan. " - "Social Security of children and documented veterans benefits are excluded by " - "the handbook. SSI Lifeline supplements, gifts, foster payments, royalties and " - "roomer receipts cannot be separately identified. The handbook uses a $500 " - "monthly nonqualified-member disregard while the readopted regulation still " - "says $268." + "Uses existing net self-employment inputs without extra deductions. Each " + "earned and unearned source is floored at zero, so a loss in one source " + "does not offset another. Child earnings follow the FY2026 plan. Social " + "Security counts net of the computed Medicare Part B premium; Social " + "Security of children and documented veterans benefits are excluded by the " + "handbook. The SSI variable carries no Tenants Lifeline supplement, so the " + "handbook's SSI deduction has nothing to remove. Gifts, foster payments, " + "royalties and roomer receipts cannot be separately identified. The " + "handbook uses a $500 monthly nonqualified-member disregard while the " + "readopted regulation still says $268." ) def formula(person, period, parameters): @@ -32,11 +39,25 @@ def formula(person, period, parameters): person.spm_unit("spm_unit_size", period) > 1 ) earned = where(adult & ~student_in_larger_household, earned, 0) - # Handbook section 2.3.F.7(a) (page 10) deducts the Medicare Part B premium - # from gross Social Security. The premium is not deducted yet: neither - # medicare_part_b_premium nor medicare_part_b_premiums_reported is wired in. - social_security = where(adult, person("social_security", period), 0) - income = earned + social_security + add(person, period, p.sources.unearned) + # Handbook section 2.3.F.7(a) (page 10) deducts the Medicare Part B + # premium from gross Social Security, and 2.3.E.8 (page 9) excludes the + # Part B buy-in withheld from the check. The computed + # medicare_part_b_premium is the out-of-pocket Part B premium, zero when + # a Medicare Savings Program pays it. + social_security = max_( + person("social_security", period) + - person("medicare_part_b_premium", period), + 0, + ) + social_security = where(adult, social_security, 0) + # Plan 1.8 (page 6) counts gross income and handbook 2.3.D (page 8) + # counts receipts from rental property, so each unearned source is + # floored like the earned sources: a loss in one source cannot offset + # another. + unearned = 0 + for source in p.sources.unearned: + unearned = unearned + max_(person(source, period), 0) + income = earned + social_security + unearned qualified = person("is_citizen_or_legal_immigrant", period) # Read the handbook's singular-member rule as a per-person disregard. return where( diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py index d114b5e4ce6..0b8dd176ef2 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py @@ -10,18 +10,29 @@ class nj_liheap(Variable): defined_for = "nj_liheap_eligible" reference = ( "https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf", - # PDF pages 7, 12, 17, 18. - "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png", + # PDF pages 12, 18. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=12", + # PDF pages 13, 19. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=13", # PDF pages 9, 10. "https://liheapch.acf.gov/docs/2026/state-plans/NJ_Plan_2026.pdf#page=9", + "https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-2", + "https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-3-2", ) documentation = ( - "Annual regular heating payment, verified for FY2026. Earlier years use " - "backfilled parameters and are unverified historical estimates. Amounts " - "preserve all published grid anomalies; no expense cap applies. " - "Unknown/unsupported direct fuels return zero. Separate fuel charges paid to " - "landlords cannot be distinguished from vendor bills without a direct benefit " - "override. Crisis, cooling, furnace and utility-program benefits are excluded." + "Annual regular heating payment, verified for FY2026 and FY2027. Earlier " + "years use backfilled parameters and are unverified historical estimates. " + "Amounts preserve the published grid anomalies, except that the FY2027 " + "matrix prints 474 in one of the three identical low-income rows of the " + "Warren and Sussex renters column for 13 or more members, where the band " + "keeps 471; no expense cap applies. A household with a rent subsidy or in " + "public housing that pays its own heating bill receives the renters level " + "under N.J.A.C. 5:49-2.2(d)1.i. Region 1 holds nineteen of the twenty-one " + "counties. Other and unspecified direct fuels return zero as a coverage " + "gap. Separate fuel charges paid to landlords cannot be distinguished from " + "vendor bills without a direct benefit override. Crisis, cooling, furnace " + "and utility-program benefits are excluded." ) def formula(spm_unit, period, parameters): @@ -41,13 +52,23 @@ def formula(spm_unit, period, parameters): | (fuel == types.WOOD) | (fuel == types.COAL) ) - # FY2026 handbook 3.2.F assigns direct payers by their heating fuel. - # The codified renter-level rule for subsidized direct payers differs. - # Chapter 5:49 was readopted in 2025; the conflict remains unresolved. + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + # N.J.A.C. 5:49-2.2(d)1.i pays a household with a rent subsidy that does + # not cover all heating costs and a heating bill in its name at the + # renter's level. The FY2026 handbook (2.2, page 6) copies (d)1 without + # that subparagraph and prints no contrary rule, so the codified rule + # applies. Public housing is read with the rent subsidy because 2.2(d)1 + # treats the two as one class; the rule names only the subsidy. + subsidized = spm_unit( + "receives_housing_assistance", period + ) | spm_unit.household("is_in_public_housing", period) + # Handbook 3.2.F (page 12) assigns other direct payers by heating fuel. A + # grid-tied solar home pays an electricity bill, the same pairing + # heating_expense uses. amount = select( [ - spm_unit("heat_expense_included_in_rent", period), - fuel == types.ELECTRICITY, + heat_in_rent | subsidized, + (fuel == types.ELECTRICITY) | (fuel == types.SOLAR), fuel == types.NATURAL_GAS, deliverable, ], @@ -57,6 +78,8 @@ def formula(spm_unit, period, parameters): p.amount.gas[region][band][size], p.amount.deliverables[region][band][size], ], + # Other and unspecified fuels have no panel; the unspecified default + # is tracked in #9754. default=0, ) # Unknown county is a payment-table coverage gap, not a legal denial. diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py index 9095b4673a6..b58acb705f0 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py @@ -9,13 +9,15 @@ class nj_liheap_income_band(Variable): defined_for = StateCode.NJ reference = ( "https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf", + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png", # PDF pages 7, 9, 12. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7", ) documentation = ( "The grid does not label the income period; monthly follows the handbook " "income test and the historical monthly thresholds used in the grid. Three " - "identical initial rows are combined." + "identical initial rows are combined; the one FY2027 cell that breaks that " + "pattern is noted in the renters table." ) def formula(spm_unit, period, parameters): diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py index 556fe716e7a..6fdaacb2b4f 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py @@ -7,10 +7,14 @@ class nj_liheap_region(Variable): definition_period = YEAR label = "New Jersey LIHEAP payment region" defined_for = StateCode.NJ - reference = ("https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf",) + reference = ( + "https://nj.gov/dca/dhcr/offices/docs/FY2026%20Benefit%20Matrix.pdf", + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png", + ) documentation = ( "Region 2 is Warren/Sussex; region 1 is the other nineteen counties. Zero " - "means a county is unknown or outside New Jersey." + "means a county is unknown or outside New Jersey. A household with no county " + "input takes the first New Jersey county, Atlantic, in region 1." ) def formula(spm_unit, period, parameters): From 5befaf93f68f649c4c716feb7498a8adf2190898 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 7 Oct 2026 15:20:44 -0400 Subject: [PATCH 9/9] Address review round 2 on New Jersey LIHEAP - Store the FY2027 Warren and Sussex renters cell (474) by giving the $2,001 to $6,439 income row its own band. - Gate the program to FY2022 onward with eligibility/in_effect and date smi_rate from 2021-10-01. - Point the FY2027 handbook anchor in nj_liheap_countable_income at page 9. - Note the FY2027 plan 1.9 conflict on strike pay, general assistance and TANF. Co-Authored-By: Claude Fable 5.1 --- .../nj/dca/liheap/eligibility/in_effect.yaml | 17 ++++++ .../nj/dca/liheap/eligibility/smi_rate.yaml | 6 +-- .../dca/liheap/income/sources/unearned.yaml | 4 ++ .../liheap/payment/amount/deliverables.yaml | 28 ++++++++-- .../dca/liheap/payment/amount/electric.yaml | 28 ++++++++-- .../nj/dca/liheap/payment/amount/gas.yaml | 28 ++++++++-- .../nj/dca/liheap/payment/amount/renters.yaml | 33 +++++++++--- .../nj/dca/liheap/payment/income_band.yaml | 14 +++-- policyengine_us/programs.yaml | 2 +- .../gov/states/nj/dca/liheap/integration.yaml | 6 +-- .../gov/states/nj/dca/liheap/nj_liheap.yaml | 53 ++++++++++++++++--- .../liheap/eligibility/nj_liheap_eligible.py | 10 +++- .../eligibility/nj_liheap_income_limit.py | 4 +- .../income/nj_liheap_countable_income.py | 9 ++-- .../gov/states/nj/dca/liheap/nj_liheap.py | 11 ++-- .../liheap/payment/nj_liheap_income_band.py | 6 +-- 16 files changed, 203 insertions(+), 56 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/in_effect.yaml diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/in_effect.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/in_effect.yaml new file mode 100644 index 00000000000..5f35fd12c9f --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/in_effect.yaml @@ -0,0 +1,17 @@ +description: New Jersey provides regular heating assistance under the modeled rules when this is true under the Low Income Home Energy Assistance Program. +# The modeled rules begin with FY2022, when the income standard moved from a +# poverty-level test to 60 percent of state median income (BPU announcement of +# October 19, 2021). The earlier standard is not encoded, so the program is not +# modeled before 2021-10-01; the explicit early false stops backdating. +values: + 0000-01-01: false + 2021-10-01: true +metadata: + unit: bool + period: year + label: New Jersey LIHEAP modeled rules in effect + reference: + - title: NJ Board of Public Utilities, Utility Assistance Week announcement, October 19, 2021 + href: https://www.nj.gov/bpu/newsroom/2021/approved/20211019.html + - title: FY2026 LIHEAP Handbook, section 2.3.A + href: https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml index 61a22552b75..ec02466a4ab 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml @@ -1,9 +1,9 @@ description: New Jersey limits monthly income to this share of state median income under the Low Income Home Energy Assistance Program. # In force since FY2022, when the test moved from a poverty-level standard to -# 60% SMI (BPU announcement of October 19, 2021). Earlier periods carry the -# rate back as unverified estimates. +# 60% SMI (BPU announcement of October 19, 2021). Earlier periods are not +# modeled (eligibility/in_effect). values: - 2025-10-01: 0.6 + 2021-10-01: 0.6 metadata: unit: /1 period: year diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml index 6ff97acf96e..57ebb40cfe0 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml @@ -2,6 +2,10 @@ description: New Jersey uses these sources as unearned income under the Low Inco values: 2025-10-01: - unemployment_compensation + # The FY2027 plan (1.9, page 6) leaves Strike Pay and General Assistance + # unchecked where the FY2026 plan checks them; handbook 2.2 (page 6) counts GA + # grants toward the standard and 2.2.3 makes striker households ineligible, + # so the handbook controls and both stay listed. - strike_benefits - ssi - pension_income diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml index 854030e364f..8261fe226b6 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml @@ -10,6 +10,15 @@ description: New Jersey provides this annual regular heating benefit to househol 4: 2025-10-01: 1_128 2: + 1: + 2025-10-01: 641 + 2: + 2025-10-01: 859 + 3: + 2025-10-01: 1_025 + 4: + 2025-10-01: 1_128 + 3: 1: 2025-10-01: 535 2: @@ -18,7 +27,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 855 4: 2025-10-01: 941 - 3: + 4: 1: 2025-10-01: 428 2: @@ -27,7 +36,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 685 4: 2025-10-01: 754 - 4: + 5: 1: 2025-10-01: 321 2: @@ -47,6 +56,15 @@ description: New Jersey provides this annual regular heating benefit to househol 4: 2025-10-01: 1_278 2: + 1: + 2025-10-01: 961 + 2: + 2025-10-01: 983 + 3: + 2025-10-01: 1_162 + 4: + 2025-10-01: 1_278 + 3: 1: 2025-10-01: 613 2: @@ -55,7 +73,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 979 4: 2025-10-01: 1_077 - 3: + 4: 1: 2025-10-01: 491 2: @@ -64,7 +82,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 784 4: 2025-10-01: 862 - 4: + 5: 1: 2025-10-01: 366 2: @@ -79,7 +97,7 @@ metadata: label: New Jersey LIHEAP deliverables payment breakdown: - range(1, 3) - - range(1, 5) + - range(1, 6) - range(1, 5) reference: - title: FY2026 Benefit Matrix diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml index ac77465c1ea..6f86032bcc0 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml @@ -10,6 +10,15 @@ description: New Jersey provides this annual regular heating benefit to househol 4: 2025-10-01: 931 2: + 1: + 2025-10-01: 529 + 2: + 2025-10-01: 710 + 3: + 2025-10-01: 846 + 4: + 2025-10-01: 931 + 3: 1: 2025-10-01: 442 2: @@ -18,7 +27,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 705 4: 2025-10-01: 776 - 3: + 4: 1: 2025-10-01: 352 2: @@ -27,7 +36,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 564 4: 2025-10-01: 620 - 4: + 5: 1: 2025-10-01: 265 2: @@ -47,6 +56,15 @@ description: New Jersey provides this annual regular heating benefit to househol 4: 2025-10-01: 1_067 2: + 1: + 2025-10-01: 606 + 2: + 2025-10-01: 821 + 3: + 2025-10-01: 970 + 4: + 2025-10-01: 1_067 + 3: 1: 2025-10-01: 506 2: @@ -55,7 +73,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 807 4: 2025-10-01: 888 - 3: + 4: 1: 2025-10-01: 404 2: @@ -64,7 +82,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 646 4: 2025-10-01: 711 - 4: + 5: 1: 2025-10-01: 304 2: @@ -79,7 +97,7 @@ metadata: label: New Jersey LIHEAP electric payment breakdown: - range(1, 3) - - range(1, 5) + - range(1, 6) - range(1, 5) reference: - title: FY2026 Benefit Matrix diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml index 615dfeaad78..898183f9e73 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml @@ -10,6 +10,15 @@ description: New Jersey provides this annual regular heating benefit to househol 4: 2025-10-01: 589 2: + 1: + 2025-10-01: 334 + 2: + 2025-10-01: 448 + 3: + 2025-10-01: 535 + 4: + 2025-10-01: 589 + 3: 1: 2025-10-01: 278 2: @@ -18,7 +27,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 446 4: 2025-10-01: 491 - 3: + 4: 1: 2025-10-01: 222 2: @@ -27,7 +36,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 355 4: 2025-10-01: 391 - 4: + 5: 1: 2025-10-01: 167 2: @@ -47,6 +56,15 @@ description: New Jersey provides this annual regular heating benefit to househol 4: 2025-10-01: 673 2: + 1: + 2025-10-01: 383 + 2: + 2025-10-01: 512 + 3: + 2025-10-01: 612 + 4: + 2025-10-01: 673 + 3: 1: 2025-10-01: 318 2: @@ -55,7 +73,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 509 4: 2025-10-01: 560 - 3: + 4: 1: 2025-10-01: 254 2: @@ -64,7 +82,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 408 4: 2025-10-01: 445 - 4: + 5: 1: 2025-10-01: 191 2: @@ -79,7 +97,7 @@ metadata: label: New Jersey LIHEAP gas payment breakdown: - range(1, 3) - - range(1, 5) + - range(1, 6) - range(1, 5) reference: - title: FY2026 Benefit Matrix diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml index f46a9eb73e4..e1a4b73209e 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml @@ -10,6 +10,15 @@ description: New Jersey provides this annual regular heating benefit to househol 4: 2025-10-01: 411 2: + 1: + 2025-10-01: 234 + 2: + 2025-10-01: 312 + 3: + 2025-10-01: 374 + 4: + 2025-10-01: 411 + 3: 1: 2025-10-01: 196 2: @@ -18,7 +27,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 312 4: 2025-10-01: 343 - 3: + 4: 1: 2025-10-01: 156 2: @@ -27,7 +36,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 250 4: 2025-10-01: 275 - 4: + 5: 1: 2025-10-01: 118 2: @@ -44,11 +53,21 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 360 3: 2025-10-01: 428 - # The FY2027 matrix prints 474 in the $2,001 to $6,439 row of this cell - # and 471 in the band's other two rows; the combined band keeps 471. 4: 2025-10-01: 471 2: + 1: + 2025-10-01: 267 + 2: + 2025-10-01: 360 + 3: + 2025-10-01: 428 + # The FY2027 matrix prints 474 in this cell, the $2,001 to $6,439 row of + # the Warren and Sussex column for 13 or more members; FY2026 prints 471. + 4: + 2025-10-01: 471 + 2026-10-01: 474 + 3: 1: 2025-10-01: 222 2: @@ -57,7 +76,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 358 4: 2025-10-01: 394 - 3: + 4: 1: 2025-10-01: 179 2: @@ -66,7 +85,7 @@ description: New Jersey provides this annual regular heating benefit to househol 2025-10-01: 286 4: 2025-10-01: 315 - 4: + 5: 1: 2025-10-01: 134 2: @@ -81,7 +100,7 @@ metadata: label: New Jersey LIHEAP renters payment breakdown: - range(1, 3) - - range(1, 5) + - range(1, 6) - range(1, 5) reference: - title: FY2026 Benefit Matrix diff --git a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml index 17888b6460d..0de0d9a2c90 100644 --- a/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml @@ -1,4 +1,6 @@ -# The first three published income rows have identical payments and are combined. +# The published rows "$0 - $1000" and "$1001 - $2000" print identical payments +# in every year and are combined. The row "$2001 - $6439" is its own band +# because the FY2027 matrix prints a different renters amount there in one cell. description: New Jersey uses these monthly income band boundaries under the Low Income Home Energy Assistance Program. brackets: - threshold: @@ -6,17 +8,21 @@ brackets: amount: 2025-10-01: 1 - threshold: - 2025-10-01: 6_440 + 2025-10-01: 2_001 amount: 2025-10-01: 2 - threshold: - 2025-10-01: 8_887 + 2025-10-01: 6_440 amount: 2025-10-01: 3 - threshold: - 2025-10-01: 9_660 + 2025-10-01: 8_887 amount: 2025-10-01: 4 +- threshold: + 2025-10-01: 9_660 + amount: + 2025-10-01: 5 metadata: type: single_amount threshold_unit: currency-USD diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 84eb310b09b..a774c584d0a 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -883,7 +883,7 @@ programs: variable: nj_liheap parameter_prefix: gov.states.nj.dca.liheap verified_years: "2026-2027" - notes: FY2026-FY2027 regular heating only, covering eligibility, countable income and the benefit grid; the FY2027 grid repeats FY2026 except one printed renters cell. Crisis, cooling and equipment assistance are out of scope. + notes: FY2026-FY2027 regular heating only, covering eligibility, countable income and the benefit grid, including the one renters cell that changes in FY2027; the program is not modeled before FY2022. Crisis, cooling and equipment assistance are out of scope. - state: TX status: partial name: Texas CEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml index 09644c34318..16468f8d13c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml @@ -50,7 +50,7 @@ # One person: $4,167 a month (fact sheet, page 2); 4,167 * 12 = 50_004. nj_liheap_income_limit: 50_004 # $1,000 a month is in the printed row "$0 - $1000". Band 1 covers the - # first three printed rows, which pay the same amounts. + # first two printed rows, which pay the same amounts. nj_liheap_income_band: 1 # Sussex is in the "Warren & Sussex Counties" column. nj_liheap_region: 2 @@ -189,8 +189,8 @@ nj_liheap_countable_income: 86_004 # Five people: $9,296 a month (fact sheet, page 2); 9,296 * 12 = 111_552. nj_liheap_income_limit: 111_552 - # $7,167 a month is in the printed row "$6440 - $8886", which is band 2. - nj_liheap_income_band: 2 + # $7,167 a month is in the printed row "$6440 - $8886", which is band 3. + nj_liheap_income_band: 3 # Middlesex is in the "All Other (19) counties" column. nj_liheap_region: 1 # 7,167 does not exceed 9,296 (section 2.3.A, page 7). The same income diff --git a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml index e2622c2d95d..9b8d25740cb 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml @@ -8,7 +8,7 @@ # (page 11) and 3.2.F (page 12): # https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=5 # - FY2027 Benefit Matrix (one page; identical to FY2026 except one Warren & -# Sussex renters cell, Case 18): +# Sussex renters cell, Cases 18 and 19): # https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20Benefit%20Matrix.png # - N.J.A.C. 5:49-2.2(d)1.i, the renter's level for subsidized direct payers # (Case 13): https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-2 @@ -19,7 +19,8 @@ # - Monthly income is 0, 77_280 / 12 = 6,440, 106_644 / 12 = 8,887 and # 115_920 / 12 = 9,660: the first dollar of the printed rows "$0 - $1000", # "$6440 - $8886", "$8887 - $9659" and "$9660 +". The rows "$1001 - $2000" -# and "$2001 - $6439" print the same amounts as "$0 - $1000" (Case 10). +# and "$2001 - $6439" print the same amounts as "$0 - $1000" (Case 10); the +# model keeps "$2001 - $6439" as its own band for the FY2027 cell of Case 18. # - Sizes 2, 6, 10 and 14 are the smallest even sizes in the printed columns # "1 to 4", "5 to 8", "9 to 12" and "13 or More". One even size stands for # each size group here; Case 15 crosses the column edges at sizes 8, 9, 12 @@ -380,10 +381,9 @@ # FY2027 Benefit Matrix, Renters panel, "Warren & Sussex Counties", column # "13 or More": the rows "$0 - $1000" and "$1001 - $2000" print 471 and the -# row "$2001 - $6439" prints 474, where every other year prints 471 in all -# three. The model combines the three rows and keeps 471 for all of them. -# Monthly incomes 12_000 / 12 = 1,000 and 36_000 / 12 = 3,000. -- name: Case 18, FY2027 Warren and Sussex renters with 13 members keep the combined band value. +# row "$2001 - $6439" prints 474, where FY2026 prints 471 in all three. Monthly +# incomes 12_000 / 12 = 1,000 (band 1) and 36_000 / 12 = 3,000 (band 2). +- name: Case 18, FY2027 Warren and Sussex renters with 13 members read 474 in the $2,001 to $6,439 row. period: 2027 input: state_code: [NJ, NJ] @@ -394,5 +394,42 @@ heating_type: [UNSPECIFIED, UNSPECIFIED] heat_expense_included_in_rent: [true, true] output: - nj_liheap_income_band: [1, 1] - nj_liheap: [471, 471] + nj_liheap_income_band: [1, 2] + nj_liheap: [471, 474] + +# The same household in FY2026 reads the FY2026 Benefit Matrix, whose +# "$2001 - $6439" row prints 471 in that cell. +- name: Case 19, FY2026 Warren and Sussex renters with 13 members read 471 in the $2,001 to $6,439 row. + period: 2026 + input: + state_code: NJ + county: WARREN_COUNTY_NJ + nj_liheap_eligible: true + nj_liheap_household_size: 13 + nj_liheap_countable_income: 36_000 + heating_type: UNSPECIFIED + heat_expense_included_in_rent: true + output: + nj_liheap_income_band: 2 + nj_liheap: 471 + +# The modeled rules begin with FY2022, when the income test moved to 60% of +# state median income (BPU announcement of October 19, 2021); the earlier +# poverty-level standard is not encoded (parameter eligibility/in_effect), so +# a household that would qualify under the FY2026 rules receives nothing in +# period 2021. Essex County adult, $12,000 of wages, natural gas billed in +# their own name (about $1,300 a year). +- name: Case 20, periods before FY2022 are not modeled. + period: 2021 + input: + state_code: NJ + county: ESSEX_COUNTY_NJ + age: 40 + employment_income: 12_000 + ssi: 0 + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_300 + output: + nj_liheap_eligible: false + nj_liheap: 0 diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py index 45308824e2b..9d2bf976a34 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py @@ -14,15 +14,18 @@ class nj_liheap_eligible(Variable): "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=5", "https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-2", "https://www.law.cornell.edu/regulations/new-jersey/N-J-A-C-5-49-2-3", + "https://www.nj.gov/bpu/newsroom/2021/approved/20211019.html", ) documentation = ( "Automatic enrollment does not waive the income test, and regular heating has " - "no asset test. Striker and institutional-residence exclusions, full " + "no asset test. The program is modeled from FY2022, when the 60% SMI standard " + "began; earlier periods return false. Striker and institutional-residence exclusions, full " "utility-allowance coverage and payments by people outside the household need " "inputs not available here. Unknown county is unsupported, not a legal denial." ) def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.nj.dca.liheap.eligibility heat_in_rent = spm_unit("heat_expense_included_in_rent", period) # Handbook 2.2 (page 6) and N.J.A.C. 5:49-2.3(b)1-2 deny public housing # and rent-subsidy households only when the subsidy covers the heat. @@ -34,8 +37,11 @@ def formula(spm_unit, period, parameters): person("is_full_time_student", period) & person("is_tax_unit_dependent", period) ) + # The modeled 60% SMI rules begin with FY2022 (BPU, October 19, 2021); + # the earlier poverty-level standard is not encoded. return ( - (spm_unit("has_heating_expense", period) | heat_in_rent) + p.in_effect + & (spm_unit("has_heating_expense", period) | heat_in_rent) & ~(heat_in_rent & subsidized) & ~dependent_students_only & (spm_unit("nj_liheap_household_size", period) > 0) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py index d2a857ca933..21bfbd4c8a5 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py @@ -23,8 +23,8 @@ class nj_liheap_income_limit(Variable): "than the codified 175%-FPG ceiling. Chapter 5:49 was readopted without " "change effective September 22, 2025; the readoption does not reconcile the " "conflict, and the model follows the handbooks. The 60% SMI test began in " - "FY2022 (BPU announcement of October 19, 2021); earlier periods carry it " - "back and are unverified. Annualized monthly limits control this " + "FY2022 (BPU announcement of October 19, 2021); earlier periods are not " + "modeled (eligibility/in_effect). Annualized monthly limits control this " "monthly-income eligibility test." ) diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py index 3d4bc496f8c..e69f43368c1 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py @@ -11,8 +11,8 @@ class nj_liheap_countable_income(Variable): reference = ( # PDF pages 6, 9, 10. "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=9", - # PDF pages 6, 10, 11. - "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=10", + # PDF pages 6, 9, 11. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2027%20LIHEAP%20Handbook.pdf#page=9", ) documentation = ( "Annual inputs approximate the four-week verification period. The summed " @@ -24,7 +24,10 @@ class nj_liheap_countable_income(Variable): def formula(spm_unit, period, parameters): # The annual TANF aggregate applies take-up to WFNJ entitlement. - # Benefits received are counted once at the household level. + # Benefits received are counted once at the household level. Handbook + # 2.2 (page 6) counts TANF and GA grants toward the standard; the FY2027 + # plan 1.9 (page 6) leaves TANF, General Assistance and Strike Pay + # unchecked where the FY2026 plan checks them, and the handbook controls. income = add(spm_unit, period, ["nj_liheap_countable_income_person", "tanf"]) # Handbook 2.3.F (page 9): "Cents shall be rounded to the nearest # dollar"; an exact half dollar rounds up. diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py index 0b8dd176ef2..6d6ff005020 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py @@ -22,11 +22,12 @@ class nj_liheap(Variable): ) documentation = ( "Annual regular heating payment, verified for FY2026 and FY2027. Earlier " - "years use backfilled parameters and are unverified historical estimates. " - "Amounts preserve the published grid anomalies, except that the FY2027 " - "matrix prints 474 in one of the three identical low-income rows of the " - "Warren and Sussex renters column for 13 or more members, where the band " - "keeps 471; no expense cap applies. A household with a rent subsidy or in " + "years back to FY2022 use backfilled parameters and are unverified estimates; " + "before FY2022 the program is not modeled (eligibility/in_effect). Amounts " + "preserve the published grid anomalies, including the FY2027 renters cell " + "for Warren and Sussex households of 13 or more at $2,001 to $6,439 a month " + "(474 against 471 in FY2026); no expense cap applies. A household with a " + "rent subsidy or in " "public housing that pays its own heating bill receives the renters level " "under N.J.A.C. 5:49-2.2(d)1.i. Region 1 holds nineteen of the twenty-one " "counties. Other and unspecified direct fuels return zero as a coverage " diff --git a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py index b58acb705f0..da8785cff67 100644 --- a/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py @@ -15,9 +15,9 @@ class nj_liheap_income_band(Variable): ) documentation = ( "The grid does not label the income period; monthly follows the handbook " - "income test and the historical monthly thresholds used in the grid. Three " - "identical initial rows are combined; the one FY2027 cell that breaks that " - "pattern is noted in the renters table." + "income test and the historical monthly thresholds used in the grid. The two " + "lowest rows pay the same in every cell and are combined; the $2,001 to " + "$6,439 row is its own band because one FY2027 renters cell differs there." ) def formula(spm_unit, period, parameters):