diff --git a/changelog.d/nj-liheap.added.md b/changelog.d/nj-liheap.added.md new file mode 100644 index 00000000000..31437ef6299 --- /dev/null +++ b/changelog.d/nj-liheap.added.md @@ -0,0 +1 @@ +Add New Jersey LIHEAP regular heating assistance for FY2026 and FY2027. 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/max_table_size.yaml b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml new file mode 100644 index 00000000000..b1428c91d48 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/max_table_size.yaml @@ -0,0 +1,12 @@ +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: + 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 + - 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 new file mode 100644 index 00000000000..ec02466a4ab --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/eligibility/smi_rate.yaml @@ -0,0 +1,21 @@ +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 are not +# modeled (eligibility/in_effect). +values: + 2021-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: 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 new file mode 100644 index 00000000000..a401d38c895 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/adult_age.yaml @@ -0,0 +1,16 @@ +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.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 new file mode 100644 index 00000000000..ab92b7eaf99 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/nonqualified_member_disregard.yaml @@ -0,0 +1,12 @@ +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: + unit: currency-USD + period: month + label: New Jersey LIHEAP nonqualified member income disregard + reference: + - 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 new file mode 100644 index 00000000000..facdd4b6b7b --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/earned.yaml @@ -0,0 +1,22 @@ +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 + - 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, 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 new file mode 100644 index 00000000000..57ebb40cfe0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml @@ -0,0 +1,36 @@ +description: New Jersey uses these sources as unearned income under the Low Income Home Energy Assistance Program. +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 + # 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 + - alimony_income + - child_support_received + - interest_income + - ordinary_dividend_income + - workers_compensation + - disability_benefits +metadata: + unit: list + period: year + label: New Jersey LIHEAP unearned sources + reference: + - 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 new file mode 100644 index 00000000000..8261fe226b6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/deliverables.yaml @@ -0,0 +1,106 @@ +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: 1_025 + 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: + 2025-10-01: 715 + 3: + 2025-10-01: 855 + 4: + 2025-10-01: 941 + 4: + 1: + 2025-10-01: 428 + 2: + 2025-10-01: 573 + 3: + 2025-10-01: 685 + 4: + 2025-10-01: 754 + 5: + 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: 1_162 + 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: + 2025-10-01: 820 + 3: + 2025-10-01: 979 + 4: + 2025-10-01: 1_077 + 4: + 1: + 2025-10-01: 491 + 2: + 2025-10-01: 657 + 3: + 2025-10-01: 784 + 4: + 2025-10-01: 862 + 5: + 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, 6) + - range(1, 5) + reference: + - 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 new file mode 100644 index 00000000000..6f86032bcc0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/electric.yaml @@ -0,0 +1,106 @@ +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 + 2: + 2025-10-01: 710 + 3: + 2025-10-01: 846 + 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: + 2025-10-01: 591 + 3: + 2025-10-01: 705 + 4: + 2025-10-01: 776 + 4: + 1: + 2025-10-01: 352 + 2: + 2025-10-01: 473 + 3: + 2025-10-01: 564 + 4: + 2025-10-01: 620 + 5: + 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: 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: + 2025-10-01: 675 + 3: + 2025-10-01: 807 + 4: + 2025-10-01: 888 + 4: + 1: + 2025-10-01: 404 + 2: + 2025-10-01: 541 + 3: + 2025-10-01: 646 + 4: + 2025-10-01: 711 + 5: + 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, 6) + - range(1, 5) + reference: + - 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 new file mode 100644 index 00000000000..898183f9e73 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/gas.yaml @@ -0,0 +1,106 @@ +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 + 2: + 2025-10-01: 448 + 3: + 2025-10-01: 535 + 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: + 2025-10-01: 373 + 3: + 2025-10-01: 446 + 4: + 2025-10-01: 491 + 4: + 1: + 2025-10-01: 222 + 2: + 2025-10-01: 298 + 3: + 2025-10-01: 355 + 4: + 2025-10-01: 391 + 5: + 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: 383 + 2: + 2025-10-01: 512 + 3: + 2025-10-01: 612 + 4: + 2025-10-01: 673 + 3: + 1: + 2025-10-01: 318 + 2: + 2025-10-01: 427 + 3: + 2025-10-01: 509 + 4: + 2025-10-01: 560 + 4: + 1: + 2025-10-01: 254 + 2: + 2025-10-01: 341 + 3: + 2025-10-01: 408 + 4: + 2025-10-01: 445 + 5: + 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, 6) + - range(1, 5) + reference: + - 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 new file mode 100644 index 00000000000..e1a4b73209e --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/amount/renters.yaml @@ -0,0 +1,109 @@ +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 + 2: + 2025-10-01: 312 + 3: + 2025-10-01: 374 + 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: + 2025-10-01: 262 + 3: + 2025-10-01: 312 + 4: + 2025-10-01: 343 + 4: + 1: + 2025-10-01: 156 + 2: + 2025-10-01: 208 + 3: + 2025-10-01: 250 + 4: + 2025-10-01: 275 + 5: + 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: 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: + 2025-10-01: 299 + 3: + 2025-10-01: 358 + 4: + 2025-10-01: 394 + 4: + 1: + 2025-10-01: 179 + 2: + 2025-10-01: 240 + 3: + 2025-10-01: 286 + 4: + 2025-10-01: 315 + 5: + 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, 6) + - range(1, 5) + reference: + - 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 new file mode 100644 index 00000000000..8abcde28a01 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/household_size_group.yaml @@ -0,0 +1,29 @@ +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 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 new file mode 100644 index 00000000000..0de0d9a2c90 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/income_band.yaml @@ -0,0 +1,36 @@ +# 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: + 2025-10-01: 0 + amount: + 2025-10-01: 1 +- threshold: + 2025-10-01: 2_001 + amount: + 2025-10-01: 2 +- threshold: + 2025-10-01: 6_440 + amount: + 2025-10-01: 3 +- threshold: + 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 + amount_unit: /1 + period: month + label: New Jersey LIHEAP monthly income band + reference: + - 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 new file mode 100644 index 00000000000..c969c0a447e --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_1.yaml @@ -0,0 +1,31 @@ +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 + - 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 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 new file mode 100644 index 00000000000..26ff07d2c7f --- /dev/null +++ b/policyengine_us/parameters/gov/states/nj/dca/liheap/payment/regions/region_2.yaml @@ -0,0 +1,14 @@ +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 + - WARREN_COUNTY_NJ +metadata: + unit: list + period: year + label: New Jersey LIHEAP region 2 counties + reference: + - 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 077b93d3a8d..ff794207755 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -808,7 +808,7 @@ programs: category: Benefits agency: HHS status: partial - coverage: DC, Riverside County, MA, IL, IN, KS, KY, MD, MS, NC, NE, NY, TX + coverage: DC, Riverside County, MA, IL, IN, KS, KY, MD, MS, NC, NE, NJ, NY, TX state_implementations: - state: DC status: complete @@ -884,6 +884,14 @@ programs: parameter_prefix: gov.states.ne.dhhs.liheap verified_years: "2026" notes: FY2026 regular heating only, with the single-family and multifamily schedules and the earned-income disregard. Crisis, cooling and weatherization assistance are out of scope. + - 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-2027" + 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: NY status: partial name: New York HEAP 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..6b15e9404d2 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.yaml @@ -0,0 +1,122 @@ +# 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 +# - 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 + +# 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: [50_004, 50_016] + has_heating_expense: [true, true] + heating_type: [NATURAL_GAS, NATURAL_GAS] + snap: [100, 100] + output: + nj_liheap_eligible: [true, false] + +# 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, 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, 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 +# 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 + 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 + +# 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 + county: UNKNOWN + nj_liheap_countable_income: 0 + has_heating_expense: true + heating_type: NATURAL_GAS + output: + nj_liheap_eligible: true + nj_liheap: 0 + +# 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] + 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 new file mode 100644 index 00000000000..c4880b9d560 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.yaml @@ -0,0 +1,36 @@ +# 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. + +# 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": 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: + 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, 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 new file mode 100644 index 00000000000..a66f6e9c358 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.yaml @@ -0,0 +1,37 @@ +# 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: + state_code: [NJ, NJ] + nj_liheap_countable_income_person: [10_001, 10_002] + tanf: [1_200, 1_200] + output: + nj_liheap_countable_income: [11_196, 11_208] + +# 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] + age: [40, 40] + nj_wfnj: [1_200, 1_200] + takes_up_tanf_if_eligible: [false, true] + ssi: [0, 0] + output: + 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 new file mode 100644 index 00000000000..0de079349e7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.yaml @@ -0,0 +1,179 @@ +# Sources for the expected values in this file: +# - 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, 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 +# 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: + 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] + spm_unit2: + members: [person3] + households: + household1: + members: [person1, person2, person4] + state_code: NJ + household2: + members: [person3] + state_code: NJ + output: + 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: 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 net of the Part B premium. + period: 2026 + input: + state_code: [NJ, NJ, NJ] + age: [17, 40, 40] + social_security: [12_000, 12_000, 12_000] + medicare_part_b_premium: [0, 1_200, 0] + ssi: [600, 600, 600] + veterans_benefits: [5_000, 5_000, 5_000] + output: + 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, +# 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: + state_code: [NJ, NJ, NJ] + age: [40, 40, 40] + immigration_status: [UNDOCUMENTED, UNDOCUMENTED, UNDOCUMENTED] + employment_income: [5_000, 6_000, 7_200] + 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 new file mode 100644 index 00000000000..16468f8d13c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/integration.yaml @@ -0,0 +1,233 @@ +# 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: + person1: + age: 40 + employment_income: 18_000 + immigration_status: UNDOCUMENTED + ssi: 0 + person2: + age: 5 + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + tanf: 0 + heating_type: FUEL_OIL + fuel_oil_expense: 2_000 + households: + 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 + # 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 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 + # 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 + +# 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 + age: 40 + 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 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 + # 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 + +# 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 new file mode 100644 index 00000000000..9b8d25740cb --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/nj_liheap.yaml @@ -0,0 +1,435 @@ +# 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 +# - FY2027 Benefit Matrix (one page; identical to FY2026 except one Warren & +# 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 +# +# 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); 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 +# 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: +# $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: [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", 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 +# $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: [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", 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 +# $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: [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", 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 +# $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: [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", 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 +# $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: [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", 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 +# $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: [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", 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 +# $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: [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", 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 +# $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: [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: [267, 360, 428, 471, 222, 299, 358, 394, 179, 240, 286, 315, 134, 179, 216, 238] + +# 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: 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: + 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, 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: +# $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] + 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, 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] + +- 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 + employment_income: 36_000 + farm_rent_income: 24_000 + ssi: 0 + tanf: 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 + +# 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 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] + 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, 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 new file mode 100644 index 00000000000..9d2bf976a34 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_eligible.py @@ -0,0 +1,52 @@ +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 = ( + # 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", + "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. 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. + 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) + ) + # The modeled 60% SMI rules begin with FY2022 (BPU, October 19, 2021); + # the earlier poverty-level standard is not encoded. + return ( + 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) + & ( + 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..e7b2b3420e1 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_household_size.py @@ -0,0 +1,22 @@ +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 = ( + # 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." + ) + + 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..21bfbd4c8a5 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/eligibility/nj_liheap_income_limit.py @@ -0,0 +1,51 @@ +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://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 = ( + "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 are not " + "modeled (eligibility/in_effect). 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) + state = spm_unit.household("state_code_str", period) + smi_parameters = parameters(period).gov.hhs.smi + base = smi_parameters.amount[state] + + 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 new file mode 100644 index 00000000000..e69f43368c1 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income.py @@ -0,0 +1,34 @@ +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 = ( + # PDF pages 6, 9, 10. + "https://www.nj.gov/dca/dhcr/offices/docs/FY2026%20LIHEAP%20Handbook%20.pdf#page=9", + # 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 " + "monthly income is rounded to the nearest dollar, with half dollars rounded " + "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. 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. + 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..e9d126ae6f0 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/income/nj_liheap_countable_income_person.py @@ -0,0 +1,67 @@ +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 = ( + # 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. 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): + 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) + # 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( + 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..6d6ff005020 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/nj_liheap.py @@ -0,0 +1,87 @@ +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/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 and FY2027. Earlier " + "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 " + "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): + 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) + ) + # 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 = ( + (fuel == types.FUEL_OIL) + | (fuel == types.KEROSENE) + | (fuel == types.PROPANE) + | (fuel == types.WOOD) + | (fuel == types.COAL) + ) + 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( + [ + heat_in_rent | subsidized, + (fuel == types.ELECTRICITY) | (fuel == types.SOLAR), + 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], + ], + # 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. + 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 new file mode 100644 index 00000000000..da8785cff67 --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_income_band.py @@ -0,0 +1,26 @@ +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/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. 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): + 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..6fdaacb2b4f --- /dev/null +++ b/policyengine_us/variables/gov/states/nj/dca/liheap/payment/nj_liheap_region.py @@ -0,0 +1,27 @@ +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", + "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. A household with no county " + "input takes the first New Jersey county, Atlantic, in region 1." + ) + + 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, + )