Skip to content

Add New Jersey LIHEAP regular heating assistance - #9745

Merged
hua7450 merged 16 commits into
mainfrom
nj-liheap
Oct 8, 2026
Merged

hua7450 merged 16 commits into
mainfrom
nj-liheap

Conversation

@hua7450

@hua7450 hua7450 commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Adds New Jersey's regular LIHEAP heating benefit for FY2026 and FY2027 using the county, fuel, income and household-size grid. A qualifying one-person Sussex County household with $12,000 annual countable income receives the published $961 deliverable-fuel payment.

Fixes #9937.

Implementation

  • Reuses federal SMI size factors. All twelve published monthly limits reconcile for FY2026 and FY2027 with the two-stage flooring ACF IM 2025-02 Attachment 4 prints and monthly half-up rounding; the additional-member increment ($241, then $246) is the difference between the size-12 and size-11 limits. The 60% SMI test began in FY2022 (BPU, October 19, 2021); the program is not modeled before then (eligibility/in_effect), because the BPU figure does not reproduce the "200% FPL" it names and no earlier standard can be encoded from it.
  • Counts qualified members toward size without SNAP-specific immigration bars. Applies the handbook's $500 monthly disregard to each nonqualified member's income, then counts the excess. The per-member interpretation remains explicit because the handbook mixes singular and plural wording.
  • Uses parameterized income sources, existing net business income without additional business/work-expense deductions, child/student earnings exclusions, child Social Security and veterans-benefit exclusions, and monthly half-up rounding. Social Security counts net of the computed Medicare Part B premium (handbook 2.3.F.7(a) and 2.3.E.8; plan 1.9). Every earned and unearned source is floored at zero, so a rental or farm-rent loss does not offset other income (plan 1.8; handbook 2.3.D). Dividends use ordinary_dividend_income; the annual tanf aggregate counts WFNJ receipt once and applies take-up. Survivor benefits count as pensions and annuities under 2.3.D; VA survivor payments inside survivor_benefits cannot be separated from them and are counted despite 2.3.E.10.
  • Uses existing housing, heating and county inputs; adds no empty input. Heat included in unsubsidized rent uses the renter panel regardless of fuel. A household with a rent subsidy or in public housing that pays its own heating bill also receives the renter level under N.J.A.C. 5:49-2.2(d)1.i; the handbook copies that paragraph without the subparagraph and prints nothing contrary. Solar homes read the electric panel, the bill heating_expense assigns them. No bill cap or regular-heating asset test applies.
  • Represents all 192 printed cells with 160 combinations: the rows "$0 - $1000" and "$1001 - $2000" pay the same in every cell and are combined, and the "$2001 - $6439" row is its own band. Keeps the anomalous $961 cell. The FY2027 matrix repeats FY2026 except one Warren & Sussex renters cell (13 or more members, "$2001 - $6439" row: 474 against 471), which is stored with a 2026-10-01 value. A household with no county input is paid under the nineteen-county column; an unknown county leaves the payment unsupported at zero without making the legal eligibility calculation false.
  • Uses undated formulas and verified_years: "2026-2027"; earlier estimates remain unverified.

Source conflicts and remaining coverage

Topic Codified text or plan FY2026/FY2027 handbook and model behavior
Income ceiling Section 5:49-2.3(a): 175% FPG, capped at 60% SMI Section 2.3.A: 60% SMI; the model reproduces the published limits.
Nonqualified member's income Section 5:49-2.2(a)(5): $268 monthly disregard Section 2.2.5: $500 monthly disregard; applied per member as an explicit interpretation. For one member earning $1,000 monthly, the two rules count $732 versus $500.
Subsidized tenant with a heating bill in their name Section 5:49-2.2(d)(1)(i): renter benefit level when the subsidy does not cover all heating costs Section 2.2 copies (d)(1) without subparagraph (i) and section 3.2.F states only the general fuel rule; nothing contradicts the regulation, so the model pays the renter level. Public housing with its own bill (eligible under 2.3(b)(1)) is read with the rent subsidy, although the rule names only the subsidy.
Renters in subsidized housing FY2026 plan 2.3 (page 9) answers "No" to a different policy for renters living in subsidized housing Sections 2.2 and 2.3.B, and 5:49-2.3(b), deny households whose subsidized rent includes the heat; the model follows the handbook.
Strike pay, General Assistance and TANF as income FY2027 plan 1.9 (page 6) leaves all three unchecked; the FY2026 plan (page 6) checks them Handbook 2.2 (page 6) counts TANF and GA grants toward the income standard, and 2.2.3 makes striker households ineligible; the model counts all three.
Categorical eligibility of SNAP, TANF and PAAD households FY2026 state plan 1.4a (page 5): a household whose member receives income-tested assistance such as TANF, SNAP or PAAD is considered categorically eligible Handbook 3.1.a.2 (page 11) keeps the income standard for automatic SNAP payments, and 2.2 (page 6) makes households over the standard ineligible, TANF, GA and SSI grants included. The model applies the income test to every household; a SNAP household over 60% SMI is ineligible in the model and would be eligible under a literal reading of the plan.

The official notice readopted Chapter 5:49 without change effective September 22, 2025, through September 22, 2032, and does not reconcile the differences above. Follow-up research found no amendment or agency clarification settling them; the codified comparison was retrieved through Cornell LII, not a separately verified current Lexis edition. The model's source choices remain provisional.

Medicare Part D premiums are not deducted (no variable). Other limitations include the four-week income window, detailed utility-allowance coverage, striker/institutional exclusions, landlord fuel billing and some income sources; the SSI variable carries no Tenants Lifeline supplement, so that deduction has nothing to remove. Other and unspecified direct fuels return zero as a coverage gap (#9754). Cooling, crisis, equipment and separate utility programs are excluded.

Microsimulation: the datasets carry no heating inputs, so population totals are $0 until the default heating type changes. That change affects API partners and is tracked separately in #9754; callers must send heating_type with the matching fuel bill.

Validation

41 program YAML cases cover every distinct matrix combination, the size-group edges at 8, 9, 12 and 13, all fourteen FY2026 and FY2027 limits, rounding, the subsidized and public-housing renter level, heat in rent over a known fuel, the Medicare deduction, a rental loss, age 18, each arm of the students-only denial, every listed unearned source, the county default, mixed-status income, farm rental income over the limit, TANF take-up, the FY2027 renters cell in both years and the FY2022 start of the modeled rules. Every program case specifies heating_type. A simulation that mixes an eligible New Jersey household with households in other states is covered by a two-state case.

Official sources

axiom: TheAxiomFoundation/rulespec-us#1481 queued

@codecov

codecov Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (909176a) to head (1a8eff0).
⚠️ Report is 300 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9745   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         8    +4     
  Lines           76       137   +61     
  Branches         2         2           
=========================================
+ Hits            76       137   +61     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

hua7450 and others added 8 commits October 3, 2026 01:52
Floor the income band before the grid lookup so units outside New Jersey index a valid key in mixed-state simulations, and add a two-state case. Name the Medicare premium variables that are not wired in. Place New Jersey between IL and TX in programs.yaml and shorten the note. Give the integration cases realistic bills and real income inputs, add income-ineligible and multi-member scenarios, and bring the test files to the shared conventions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Handbook 2.3.D counts pensions and annuities, which covers survivor
pensions and annuities. 2.3.E.10 excludes veterans' benefits, but VA
survivor payments cannot be separated from survivor_benefits, so the
whole amount counts; the parameter comment records this.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Write parameter date keys unquoted, wrap each variable's documentation
string across lines, and split the household-size sweeps between files
so each size is asserted once: odd sizes in the income-limit test, even
sizes in the benefit-grid tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@hua7450
hua7450 marked this pull request as ready for review October 6, 2026 12:51
@hua7450
hua7450 requested a review from DTrim99 October 6, 2026 12:51
@DTrim99

DTrim99 commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

PR Review: New Jersey LIHEAP regular heating assistance

PR #9745: Add New Jersey LIHEAP regular heating assistance (author: hua7450, head 020fbbf346)

Scope: New Jersey's LIHEAP regular heating benefit (DCA Home Energy Assistance), FY2026 only. The PR covers residency and household size, countable income, the 60% SMI monthly limit, the eligibility exclusions, and the benefit grid: 4 panels (Deliverables, Electric, Gas, Renters) × 2 county regions × 4 income bands × 4 size groups. Crisis, cooling, furnace repair, USF, Medicare Part B netting, the SSI Lifeline deduction, strikers and institutions are out of scope. The PR changes 30 files: 15 parameters, 8 variables, 6 test files (27 cases), programs.yaml and a changelog fragment. Every parameter has a single 2025-10-01 value, every test uses period: 2026, and the registry lists verified_years: "2026".

Overall: the FY2026 values are right. All 128 distinct grid cells match the FY2026 Benefit Matrix, and so do the band thresholds, the two regions, the 12 published income limits and the $241 step. The income lists are self-contained, so there is no SNAP-list reuse and no #9672 exposure. One problem is critical:

  • C1: subsidized tenants who pay their own heating bill get the fuel panel. N.J.A.C. 5:49-2.2(d)1.i gives them "a renter's benefit level", and no administered source overrides that rule.

The seven should-address items cover:

  • Social Security counted gross of the Medicare Part B premium (S1);
  • rental losses offsetting other income (S2);
  • the 60% SMI rule carried back into years when New Jersey used a poverty-level test (S3);
  • the FY2027 carry-forward, although the FY2027 tables are published and differ in two places (S4);
  • tests that cover less than the PR claims (S5);
  • parameter descriptions (S6);
  • three wrong page anchors and one partial anchor (S7).

Every critical and should finding was re-verified against the cited code and source pages. The numeric examples were reproduced by running the head code. None was dropped or downgraded. Three corrections came out of verification:

  • C1's overpayment range is $49 to $807. The regulatory pass said $100 to $700.
  • The corrected expectation for S1's pinned test is 11,400. Both passes proposed 12,000.
  • C1's fix is limited to the rent-subsidy households that (d)1.i names.

Duplicates from the regulatory and code passes are merged. The code pass's untested branches and limit-coverage claim, and the regulatory pass's test gaps, are now S5. Both passes' anchor findings are S7; the regulatory pass rated its anchors as suggestions, and they move up to match #9743 S6. One new suggestion was added (G1: SOLAR and OTHER).

Path prefixes used below:

  • P/ = policyengine_us/parameters/gov/states/nj/dca/liheap/
  • V/ = policyengine_us/variables/gov/states/nj/dca/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/
  • HB = FY2026 LIHEAP Handbook (PDF page = printed page + 1)

Line numbers refer to head 020fbbf346. The benefit amounts below were reproduced by running the PR's code on single households.

Source Documents

# Document Link Use
1 FY2026 NJ LIHEAP State Plan (49 pp) NJ_Plan_2026.pdf 1.4/1.4a categorical (p5); 1.8 gross income, 1.9 countable income (p6-7); 2.1 60% SMI, 2.3, 2.5 (p9); 2.6 $118 / $1,278 (p10). The text layer lacks the checkbox states, so the rendered pages were read
2 FY2026 LIHEAP Handbook (25 pp) HB 2.2 (p5-6); 2.3.A-C (p7); 2.3.D-E.7 (p8); E.8-E.10, F (p9); F.3-F.8 (p10); 3.1 (p11); 3.2 (p12); 3.7.B (p18)
3 FY2026 Benefit Matrix (1 page, image only) FY2026 Benefit Matrix All 128 cells, bands, regions, size groups
4 FFY2026 USF/HEA fact sheet Fact sheet, p. 2 Monthly limits for sizes 1-12 and "+$241"
5 FY2025, FY2024 and FY2023 benefit matrices 2025, 2024, 2023 Not cited in the PR. All identical to FY2026, so the grid carries back correctly to 2023-2025
6 FY2027 Benefit Matrix, fact sheet, handbook and state plan Matrix PNG, fact sheet p. 2, handbook, plan Not cited in the PR. All are linked from the DCA HEA page; the plan's report period is 10/01/2026 to 09/30/2027 (S4)
7 ACF LIHEAP IM 2025-02, Attachment 4 (FY2026 SMI table) Att. 4 NJ SMI $160,276 and the floored 60% amounts
8 N.J.A.C. 5:49-2.2, 2.3, 3.2 and 3.6 (Cornell LII) 2.2, 2.3, 3.2, 3.6 The codified rules (C1; the 60% SMI and $500 conflicts)
9 57 N.J.R. 2402, notice of readoption of N.J.A.C. 5:49 Notice, p. 6 Readopted without change, effective September 22, 2025
10 BPU announcement, October 19, 2021 BPU 2021 The change from 200% FPL to 60% SMI in FY2022 (S3)

Critical (Must Fix)

C1. Subsidized tenants who pay their own heating bill get the fuel panel, but N.J.A.C. 5:49-2.2(d)1.i gives them the renter level

  • Where:

    • V/nj_liheap.py:47-61. The select routes only heat_expense_included_in_rent to p.amount.renters. Every other direct payer reads its fuel panel, even when receives_housing_assistance is true.
    • The comment at lines 44-46 acknowledges "The codified renter-level rule for subsidized direct payers differs".
    • V/eligibility/nj_liheap_eligible.py:23-25 already computes subsidized and correctly lets these households in (line 33 excludes only heat_in_rent & subsidized).
  • Sources:

    • 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".
    • 57 N.J.R. 2402, p. 6: the chapter was readopted without change effective September 22, 2025. The notice also describes the readopted rules as serving "as the handbook" for the program.
    • The FY2026 matrix names the fourth panel "Renters", which is the "renter's benefit level" the rule refers to.
  • Why the handbook does not override it:

    • HB 2.2, p. 6 copies the regulation's ineligible list (2.2(d)1-4) almost word for word but drops subparagraph i. It says nothing contrary.
    • HB 3.2.F.1, p. 12 ("shall receive a benefit based on the household's size, income, fuel type, and heating region, as referenced in N.J.A.C. 10:89 3.6") is the general rule. It is identical to reg 3.2(f)1, which sits in the same chapter as the specific (d)1.i. The handbook also cites the chapter, under its former 10:89 number, as its authority.
    • This differs from the PR's other two handbook-over-regulation choices. For 60% SMI (HB 2.3.A, p. 7) and the $500 disregard (HB 2.2.5, p. 6), the handbook prints a replacement rule, and the plan and fact sheet confirm it. For (d)1.i no administered source says anything.
    • The PR's own conflict table concedes "that choice is not an express handbook instruction for subsidized direct payers."
  • Impact in period 2026 (reproduced): an Essex County adult with $12,000 of wages, a $1,500 electric heating bill and receives_housing_assistance: true.

    PR 5:49-2.2(d)1.i
    Panel Electric, All Other (19), band 1, sizes 1-4 Renters, same cell
    Benefit $529 $234

    Across the grid the overpayment runs from $49 (Gas, top income band) to $807 (Deliverables, Warren & Sussex, 13 or more: $1,278 against $471). It reaches every voucher holder who pays their own heating bill, in every band and size.

  • Why critical: the claimed year (2026) pays the wrong amount to a common household type. This is the same class as Add New York HEAP regular heating assistance #9744 C1 (wrong rule for a common household type in 2026).

  • Fix:

    1. In nj_liheap.py, route rent-subsidy direct payers to the Renters panel:
      heat_in_rent = spm_unit("heat_expense_included_in_rent", period)
      rent_subsidy = spm_unit("receives_housing_assistance", period)
      amount = select(
          [
              heat_in_rent | rent_subsidy,
              fuel == types.ELECTRICITY,
              fuel == types.NATURAL_GAS,
              deliverable,
          ],
          [...],  # unchanged
          default=0,
      )
    2. (d)1.i names only rent-subsidy households. Public-housing tenants with their own bill are eligible under 2.3(b)1, but the rule does not set their level. Decide whether they also get the renter level, and say so in the comment either way. Currently they get the fuel panel ($529 in the example).
    3. Add a test: the household above expects nj_liheap: 234.
    4. Update the comment at lines 44-46, the PR conflict table, and rulespec-us#1481 interpretation (3).
    5. If DCA documentation shows that the fuel panel is actually paid, cite it in the variable. This then becomes a documented choice. None was found in the FY2026 or FY2027 handbook, plan, fact sheet or matrix.

Should Address

S1. Social Security is counted gross, but the handbook and the plan count it net of the Medicare Part B premium

  • Where:
    • V/income/nj_liheap_countable_income_person.py:35-38. The comment says "neither medicare_part_b_premium nor medicare_part_b_premiums_reported is wired in".
    • T/income/nj_liheap_countable_income_person.yaml:87-98 (Case 2) pins the gross treatment with medicare_part_b_premium: [0, 1_200, 0].
  • Sources:
    • HB 2.3.F.7(a), p. 10: "the net amount of the monthly check is countable ... must determine if the individual pays a Medicare Part B premium and deduct that amount from the gross amount of the benefit."
    • HB 2.3.E.8, p. 9 excludes the "Medicare Part B Buy-In, which is withheld from the household's Social Security check."
    • Plan 1.9, p. 6: the SSA benefits box is checked, with "Excluding MediCare deduction" checked.
  • Why "not wired in" does not hold: medicare_part_b_premium exists and is computed. Merged policyengine_us/variables/gov/states/ky/dcbs/liheap/ky_liheap_income.py:42-45 already subtracts it. This is the same finding as Add New York HEAP regular heating assistance #9744 S1.
  • Impact in period 2026 (reproduced): a single 70-year-old with $50,400 of Social Security ($4,200 a month) and gas heat. The model's own premium is $2,434.80 a year ($202.90 a month).
    • PR: $4,200 is over the $4,167 limit, so $0.
    • Handbook: $4,200 − $202.90 = $3,997, within the limit, so Gas, band 1 = $334.
  • Fix:
    • For adults, count max_(social_security - medicare_part_b_premium, 0).
    • Change Case 2 to expect [600, 11_400, 12_600]: (12,000 − 1,200) + 600 = 11,400.
    • Update rulespec-us#1481 companion test 15, which encodes the gross amount.

S2. A rental or farm-rent loss offsets wages, Social Security and other income

  • Where:
    • V/income/nj_liheap_countable_income_person.py:39 adds p.sources.unearned with signed values. That list includes rental_income and farm_rent_income (P/income/sources/unearned.yaml:12-13).
    • Earned sources are floored per source (lines 28-29). The unit total is floored only at the end (V/income/nj_liheap_countable_income.py:26).
    • The documentation at V/income/nj_liheap_countable_income.py:18-19 says "rental income is assumed nonnegative", but the input allows negative values.
  • Sources:
    • HB 2.3.D, p. 8 counts "receipts from the rental of property".
    • Plan 1.8, p. 6 checks "Gross Income".
    • Nothing authorizes a loss in one source to reduce another.
  • Impact in period 2026 (reproduced): an Essex County adult with $60,000 of wages and gas heat.
    • With rental_income: -20_000: countable income is $39,996, eligible, $334.
    • With rental_income: 0: $60,000 is over the $50,004 limit, so $0.
  • Consistency: same as Add New York HEAP regular heating assistance #9744 S2. Merged KY floors each unearned source (ky_liheap_income.py:31-35).
  • Fix:
    • Floor each unearned source at zero, as the earned loop does.
    • Replace the "assumed nonnegative" sentence with the rule, and add a rental-loss case like the one above.

S3. The 60% SMI limit is carried back into periods 2021 and earlier, when New Jersey used a poverty-level test

  • Where:

    • P/eligibility/smi_rate.yaml:3 has a single 2025-10-01: 0.6 entry.
    • V/eligibility/nj_liheap_income_limit.py:25-45 applies it to every year.
    • V/nj_liheap.py:19-20 labels earlier years "unverified historical estimates".
  • Source: the BPU announcement of 2021-10-19: "DCA's LIHEAP program's income eligibility criteria changed from 200% of the Federal Poverty Level to 60% of the State Median Income, resulting in an increase of the income threshold for a family of four from $4,039.00 gross monthly income to $6,439.00 gross monthly income."

  • Impact (reproduced): the size-4 monthly limit is $6,172 for period 2021 and $5,922 for period 2020. The published pre-change threshold is $4,039.

  • What is already correct:

    • Period 2022 gives $6,439, matching BPU.
    • The grid carries back correctly: the FY2023, FY2024 and FY2025 matrices are identical to FY2026, and the band thresholds are the FY2022 limits for sizes 4, 8 and 12.
    • Only periods 2021 and earlier are wrong.
  • Why should, not critical: the claimed year is 2026, and the wrong years are unclaimed earlier years. This matches the batch rule (Add New York HEAP regular heating assistance #9744 S3).

  • Fix, either option is acceptable:

    • Encode the pre-FY2022 rule: a dated poverty-guideline test before 2021-10-01, citing BPU.
    • Or gate the program to start on 2021-10-01 and document that.

    Either way, date smi_rate from 2021-10-01.

S4. Period 2027 pairs FY2027 limits with FY2026 tables, but the FY2027 tables are published and differ in two places

  • What happens: the single-dated parameters carry forward, while gov.hhs.smi moves to FY2027 (NJ $164,337 from 2026-10-01). The limits for sizes 1-12 update correctly; the step and the grid do not.
  • Sources:
    • FY2027 fact sheet, p. 2: sizes 1-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, and "Household members greater than 12 - Please add $246 for each additional member for monthly income limit."
    • FY2027 Benefit Matrix ("The 2027 Benefit Grid for: Renters"): Warren & Sussex, "13 or More", row "$2001 - $6439" prints 474. The rows "$0 - $1000" and "$1001 - $2000" still print 471. Every other cell matches FY2026.
    • The FY2027 plan (report period 10/01/2026 to 09/30/2027, "Submission Accepted by CO") keeps $118 / $1,278. The FY2027 handbook keeps 60% SMI, $500 and $1,278.
  • Impact in period 2027 (reproduced):
    • Sizes 1-12 reproduce the fact sheet exactly.
    • The step does not. V/eligibility/nj_liheap_income_limit.py:39-44 computes ceil(98,602.2 × 0.03 / 12) = 247, so size 13 gives 12,572 against the published 12,571, and size 14 gives 12,819 against 12,817.
    • A Warren County heat-in-rent household of 13 with $3,000 a month gets 471 against the published 474. P/payment/income_band.yaml merges rows 1-3 into band 1, so the 474 cell cannot be stored (P/payment/amount/renters.yaml:47-48).
  • The published step equals the size-12 monthly limit minus the size-11 limit in both years: 12,021 − 11,780 = 241 (FY2026) and 12,325 − 12,079 = 246 (FY2027). The ceiling formula matches FY2026 only by coincidence.
  • Why should, not critical: carrying values forward is the normal state, and only 2026 is claimed. Both FY2027 values are in force now, though, and reach is limited to households of 13 or more. This is the same pattern as Add Oregon LIHEAP regular heating assistance #9743 S1.
  • Fix:
    • Compute the step as monthly(12) - monthly(11).
    • Add 2026-10-01 entries. Split band 1 at $2,001 (repeating the FY2026 band-1 values in the new band) so the 474 cell can be stored.
    • Then either claim 2027 (verified_years: "2026-2027", with a period-2027 test such as size 13 = 12,571 × 12) or say in the registry notes that 2027 uses FY2026 tables.

S5. Tests cover less than the PR claims, and four branches have no test that would fail if they broke

  • The claim: the PR body says "27 program YAML cases cover every distinct matrix combination, all published limits, rounding, housing, ...". The matrix part is true: Cases 1-8 hold all 128 cells. The rest is not:
    • Limits. Sizes 4, 6, 8, 10 and 12 (8,014 / 10,578 / 11,059 / 11,540 / 12,021 a month) are never asserted. T/eligibility/nj_liheap_income_limit.yaml:5-8 says "the grid cases in ../nj_liheap.yaml use the even sizes", and T/nj_liheap.yaml:18-21 says "the odd sizes are asserted in eligibility/nj_liheap_income_limit.yaml". The grid cases force eligibility and never compute the limit, so neither file covers what the other claims.
    • Where the coverage went: commit 924519344a ("Tidy New Jersey LIHEAP parameters and tests") cut the limit test from sizes 1-14 to 1, 3, 5, 7, 9, 11, 13 and 14. rulespec-us#1481 companion test 9 still describes the 14-size version.
    • Size-group edges. Only the 4-to-5 edge is crossed (Case 10 at size 4, integration Case 4 at size 5). The grid uses sizes 2/6/10/14, so the thresholds 9 and 13 in P/payment/household_size_group.yaml could move to 10 and 14 without a failure.
  • Untested branches (each change below passes all 27 cases):
    1. Public-housing heat-in-rent exclusion. V/eligibility/nj_liheap_eligible.py:23-25 ORs in is_in_public_housing, but no NJ test sets it. The only exclusion test (T/eligibility/nj_liheap_eligible.yaml:34-45) uses receives_housing_assistance. Deleting the public-housing arm passes. HB 2.3.B.1, p. 7 is a separate rule from B.2.
    2. Heat in rent takes precedence over a known fuel. Every heat-in-rent payment test uses heating_type: UNSPECIFIED (T/nj_liheap.yaml Cases 7-8, T/integration.yaml Case 2), which matches no fuel condition anyway. Moving the heat-in-rent condition to the end of the select would pay a gas-fuelled heat-in-rent tenant $334 instead of $234 (reproduced at head: $234), and no test would catch it. HB 3.2.F.2, p. 12: these households "shall receive benefits as heat is included in the rent fuel type".
    3. Age 18. V/income/nj_liheap_countable_income_person.py:30 uses age >= p.adult_age. The test ages are 5, 6, 10, 14, 17, 20 and 34-45, so changing >= to > passes. Plan 1.9 (p7) and HB 2.3.E.9, p. 9 ("children under 18 years old") make 18 the first counted age. Same gap as Add Oregon LIHEAP regular heating assistance #9743 S5.
    4. Both arms of the dependent-students-only test. V/eligibility/nj_liheap_eligible.py:27-30 requires is_full_time_student & is_tax_unit_dependent. The only case (T/eligibility/nj_liheap_eligible.yaml:50-61) sets both, so dropping either conjunct still gives false.
  • Fix:
    • Extend nj_liheap_income_limit.yaml Case 1 back to sizes 1-14: 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. All reproduce at head. Reword the two comments.
    • Add sizes 8, 9, 12 and 13 to one grid sweep.
    • Add these cases:
      • public housing with heat in rent: ineligible, $0;
      • heat in rent with NATURAL_GAS: $234;
      • an 18-year-old non-student whose wages and Social Security count;
      • a full-time student who is not a dependent, and a dependent who is not a student, each eligible with a bill and no income;
      • the C1, S1 and S2 cases.
    • Correct the PR-body claim.

S6. Parameter descriptions fall outside the house pattern

The house pattern uses one of the template verbs and ends with "under the Low Income Home Energy Assistance Program." Merged KS LIHEAP uses provides/sets/uses (for example, ks/dcf/liheap/payment/matrix/other.yaml:1: "Kansas provides this annual benefit to households heating primarily with other fuels, by ..., under the Low Income Energy Assistance Program.").

File:line Problem Suggested text
P/payment/amount/deliverables.yaml:1, electric.yaml:1, gas.yaml:1, renters.yaml:1 Verb "pays"; ", by county region, monthly income band and household size group" comes after the program name "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."
P/payment/regions/region_1.yaml:1, region_2.yaml:1 Verb "assigns" "New Jersey uses these counties as payment region 1 under the ..."
P/eligibility/max_table_size.yaml:1 Verb "prints" "New Jersey sets income limits through this household size, with a fixed monthly increment for each additional member, under the ..."
P/income/sources/unearned.yaml:1 Verb "counts" "New Jersey uses these sources as unearned income under the ..."
P/income/sources/earned.yaml:1 Implementation wording ("reported earnings sources without any additional business expense deduction") "New Jersey uses these sources as earned income under the ...". Move the expense note to a YAML comment, as KS does
P/income/nonqualified_member_disregard.yaml:1 "this much" (cosmetic) "this amount"

Consistency: #9744 S5 rated the same pattern SHOULD in this batch.

S7. Three handbook anchors open a page without the cited rule, and one is partial

Every anchor is a single valid #page=N. The PDF page is the printed page + 1, and the mapping below was checked against the "Guideline N" footers.

File:line Anchor Page that opens Where the content is
V/nj_liheap.py:14 HB #page=7 2.3.A-C: the income test, subsidized denials, earned income Payment rules: 3.2.F.1-2 on p. 12 and 3.7.B on p. 18
P/income/sources/unearned.yaml:26 HB #page=7 2.3.C, earned income 2.3.D, unearned income, on p. 8 (exclusions E.8-E.10 on p. 9)
P/income/adult_age.yaml:10 HB #page=8 2.3.D-E.7, with no age rule The child Social Security rule, 2.3.E.9, is on p. 9. The child-earnings rule is only in plan 1.9 (p7), already the second reference
V/income/nj_liheap_countable_income.py:13 (partial) HB #page=6 2.2 household and ineligible list The half-up rounding the variable applies is 2.3.F on p. 9

Consistency: #9743 S6 rated four wrong anchors SHOULD. Fix: retarget the three anchors, using a tuple of single-page hrefs where a variable needs more than one page (p12 and p18 for nj_liheap), and add the p9 entry to nj_liheap_countable_income.

Suggestions

G1. SOLAR and OTHER direct payers are eligible but get $0; point the UNSPECIFIED $0 at #9754

  • V/nj_liheap.py:37-61 has no branch for SOLAR or OTHER. The canonical heating_expense reads pre_subsidy_electricity_expense for SOLAR ("Solar-primary homes are assumed grid-tied with electric supplemental heat") and other_heating_fuel_expense for OTHER. So these households have has_heating_expense true, are eligible, and get $0. T/nj_liheap.yaml Case 9 pins the $0 with eligibility forced.
  • Why this is a suggestion here, while Add Oregon LIHEAP regular heating assistance #9743 C2 was critical: Oregon's manual is "fuel blind", and that PR's own test said solar homes pay an electricity bill. HB 3.2.F.1, p. 12 instead pays by fuel type and lists an exhaustive set: "electricity, natural gas, oil, propane, kerosene, coal, wood, and heat included in rent". Merged code is also split: KY, NE and MS pay SOLAR $0, while KS, IL and DC treat it as electric.
  • Still, eligibility and payment disagree. Either pay SOLAR from the Electric panel, since the model's heating bill for SOLAR is the electric bill, or make SOLAR and OTHER ineligible so that the flag matches the $0.
  • A direct payer with UNSPECIFIED fuel is ineligible by construction (heating_expense = 0). The PR body defers that to Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754, which is acceptable. Add a # See #9754 note in V/nj_liheap.py:22 and in Case 9, so the pinned $0 reads as provisional.

G2. Unknown county

  • V/nj_liheap.py:62-63 returns $0 for an eligible household when county is explicitly UNKNOWN or a non-NJ county (T/eligibility/nj_liheap_eligible.yaml Case 4). This is documented and acceptable.
  • With no county input, county falls back to first_county_in_state, which is Atlantic (region 1). Reproduced: a gas household with $12,000 of wages and no county gets $334.
  • No test pins that default. Add one, and optionally say in the documentation that region 1 covers 19 of 21 counties.

G3. Documentation accuracy

  • V/eligibility/nj_liheap_income_limit.py:19-21 says "its 2017 expiration does not resolve this conflict". The readoption notice says the rules "were scheduled to expire on November 5, 2025". Line 21's "This draft follows ..." will ship in API metadata. Suggested wording: "readopted without change effective 2025-09-22; the readoption does not reconcile the conflict. The model follows the FY2026 handbook."
  • Line 33 calls the two-stage flooring "Inferred". ACF Att. 4, p. 2 prints NJ "$160,276" and floored 60% amounts (50,005 ... 144,247). Cite it and drop "Inferred", as in Add New York HEAP regular heating assistance #9744 G6.
  • V/income/nj_liheap_countable_income_person.py:18-20 says SSI Lifeline supplements "cannot be separately identified". PE's ssi is the federal payment only, and no NJ supplement is modeled, so the HB 2.3.F.7(b) deduction is effectively already applied. Reword.

G4. Reference titles and variable comments (checklist #6)

  • Page text in titles:

    • "section 2.3.E, PDF pages 8, 9" in P/income/adult_age.yaml:9;
    • "PDF pages 7, 8, 9" in P/income/sources/earned.yaml:13;
    • "PDF pages 7, 8, 9, 10" in P/income/sources/unearned.yaml:25.

    Use the section in the title, with one entry per page.

  • P/income/nonqualified_member_disregard.yaml:9 has no section. Use "section 2.2.5".

  • Six variables carry a # PDF pages ... comment above a single href: V/nj_liheap.py:13, V/eligibility/nj_liheap_eligible.py:11, V/eligibility/nj_liheap_household_size.py:11, V/income/nj_liheap_countable_income.py:12, V/income/nj_liheap_countable_income_person.py:12 and V/payment/nj_liheap_income_band.py:12. Use a tuple of single-page hrefs, as merged KS does.

  • The grid parameters title the source "FY2026 heating benefit grid". The document is the "FY2026 Benefit Matrix".

  • P/income/sources/unearned.yaml cites only the handbook. Plan 1.9 (pp. 6-7) backs the list directly.

G5. PR body

  • The body still says "PR remains draft" (isDraft is false) and "not re-run locally after the review fixes" (CI is green).
  • It claims "all published limits" and "housing" coverage, which S5 qualifies.
  • The conflict table omits one conflict. Plan 2.3 (p9) answers "No" to differing policies for "Renters Living in subsidized housing?", while the handbook (2.2, 2.3.B) and the regulation deny subsidized heat-in-rent households. The PR follows the handbook, which is right. Add the row.

G6. Digit separators and key style

  • Nine values have no _ separator:

    • P/payment/income_band.yaml:9,13,17 (6440, 8887, 9660);
    • P/payment/amount/deliverables.yaml:9,11,46,48,57;
    • P/payment/amount/electric.yaml:48.

    Merged KS writes 1_200, and the PR's own tests write 1_278.

  • The four amount files quote the top-level keys ('1':) but leave the nested keys bare. Pick one style.

G7. Test hygiene

  • heating_type is set in every case of the limit and income test files, but none of those variables reads it. T/nj_liheap.yaml:250,253-256 sets immigration_status: CITIZEN, rental_income: 0, ssi: 0, tanf: 0 and snap: 0.
  • T/eligibility/nj_liheap_eligible.yaml:93 gives the New York household ESSEX_COUNTY_NJ. Use KINGS_COUNTY_NY, as T/nj_liheap.yaml Case 11 does.
  • T/eligibility/nj_liheap_eligible.yaml:40-42 forces has_heating_expense: true with heat in rent, a state the formula cannot produce. Line 33's "even with a heating bill reported" describes it. Drop both.
  • Twelve of the 14 unearned sources are never nonzero in any NJ test; only ssi and farm_rent_income are. Add one case with every source nonzero.

G8. Optional nj_liheap_income_eligible

V/eligibility/nj_liheap_eligible.py:36-39 folds the income test into the combined flag. Merged KS, KY and NE expose {st}_liheap_income_eligible, which makes the denial reason visible in the API. MS does not, so this is optional.

G9. rulespec-us#1481 is stale

See the Axiom line section.

Verified correct

  • Grid (FY2026 matrix):
    • All 128 distinct cells match: 4 panels × 2 regions × 4 bands × 4 size groups, 0 mismatches. This includes the printed $961 W&S Deliverables cell, which the FY2027 grid also prints.
    • The minimum $118 and maximum $1,278 match plan 2.6, p. 10.
    • The FY2023, FY2024 and FY2025 matrices are identical in every cell, row and column.
  • Bands: monthly thresholds 0 / 6,440 / 8,887 / 9,660, with the three identical top rows merged. Monthly is right: 6,439, 8,886 and 9,659 are the FY2022 60% SMI monthly limits for sizes 4, 8 and 12, and BPU 2021 quotes "$6,439.00 gross monthly income".
  • Regions and size groups:
    • Region 1 has 19 counties and region 2 is Warren and Sussex.
    • Each of New Jersey's 21 County entries appears exactly once.
    • The size groups are 1-4 / 5-8 / 9-12 / 13+, and sizes over 13 cannot index past the table.
  • Income limits:
    • All 12 FY2026 limits reproduce the fact sheet (4,167 / 5,449 / 6,732 / 8,014 / 9,296 / 10,578 / 10,819 / 11,059 / 11,299 / 11,540 / 11,780 / 12,021) and the ACF annual values, with half-up monthly rounding. The FY2026 step is $241.
    • All 12 FY2027 limits also reproduce.
    • The smi() helper is reused.
  • Income rules:
    • Gross income (plan 1.8).
    • Monthly half-up rounding of the summed total (HB 2.3.F, p. 9: "Cents shall be rounded to the nearest dollar").
    • Earned sources floored.
    • Full-time-student earnings excluded in a larger household (E.3).
    • Earnings and Social Security under 18 excluded (plan 1.9; E.9).
    • veterans_benefits excluded (E.10).
    • tanf counted once at the unit level, with take-up.
    • General assistance and federal SSI counted (HB 2.2, ineligible item 4).
    • The nonqualified-member $500 monthly disregard applied per member (HB 2.2.5, p. 6).
  • Eligibility:
    • Residency.
    • Own heating cost or heat in rent.
    • Subsidized or public-housing heat-in-rent denial (5:49-2.2(d)1, 2.3(b)1-2).
    • Dependent-students-only denial.
    • No asset test.
  • Fuel map:
    • Oil, kerosene, propane, wood and coal pay from Deliverables (3.2(f)1.i).
    • Heat in rent pays from Renters (3.2(f)2), including with UNSPECIFIED fuel.
  • Code patterns:
    • No hard-coded policy values.
    • defined_for on every derived variable; nj_liheap is gated by nj_liheap_eligible.
    • Entities and periods are correct, and Household variables are projected with spm_unit.household.
    • Formulas are vectorized.
    • Grid keys are floored before lookup, so the mixed NJ+NY simulation works (Case 11).
    • All 15 parameters are read, and nothing is reinvented.
  • Not findings after verification:
    • 60% SMI over the codified 175% FPI cap, and $500 over $268: the handbook prints the replacement rule, and the plan, fact sheet and FY2027 documents confirm it.
    • The income test applied to SNAP/TANF households despite plan 1.4a: plan 1.4a still requires income documentation, and HB 3.1.a.2 and 5:49-3.2(a) require income eligibility.
  • Tests:
    • 150 of 150 nj_liheap grid expectations recompute from the head parameters.
    • Integration Cases 1-4, the 933.42 / 933.50 rounding pair, the 4,167 / 4,168 limit edge and all six income-row edges were hand-checked.
    • Periods are plain 2026.
  • Microsimulation: the datasets carry no heating inputs, so the NJ total is about $0 until Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754 lands. The PR body says so. nj_liheap feeds no household aggregate, so net income and poverty are unaffected.

Checklist results (LIHEAP batch 2)

  1. SNAP income-list reuse: pass on reuse. The lists are self-contained and use rental_income (not snap_rental_income) plus farm_rent_income, so there is no Stop rental losses from offsetting other income in SNAP #9672 double count. Fail on source treatment: Social Security is gross of Part B (S1), and losses are not floored per source (S2).
  2. Backfill and carry-forward: the grid is correct for 2023-2025 (identical matrices), and the limits are correct from 2022. Periods 2021 and earlier carry back 60% SMI (S3). Period 2027 has a stale step and one stale cell (S4).
  3. Operative state rules: fail on N.J.A.C. 5:49-2.2(d)1.i (C1). The 60% SMI, $500 and categorical-eligibility choices follow administered sources and are defensible.
  4. UNSPECIFIED and microsim defaults: heat in rent with UNSPECIFIED fuel pays Renters ($234). A direct payer with UNSPECIFIED fuel is ineligible by construction, and the deferral to Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754 is acceptable. SOLAR/OTHER are G1, and the unknown county is G2.
  5. Axiom line: valid queued line pointing to a dispatch-ready pe-parity issue. It is stale (see below).
  6. References: no comma #page lists. Three anchors are wrong and one is partial (S7). There is page text in three titles (G4). All editions are current.
  7. programs.yaml: the NJ entry is well formed and sorted NE < NJ < TX, with NE's field order. The coverage-line conflict with main is expected (see Branch status). Not a finding.
  8. Rounding and boundaries: half-up rounding, the limit edge and the six row edges are tested, with plain periods. Gaps: the size-group edges at 9 and 13, the even-size limits, age 18 (S5) and the FY2027 step (S4).

CI status

37/37 checks pass at 020fbbf346 (gh pr checks 9745, 2026-10-06).

Branch status

Axiom line

axiom: TheAxiomFoundation/rulespec-us#1481 queued: valid format, and the issue meets the bar.

  • rulespec-us#1481 is open and labelled pe-parity (plus enhancement), with no comments.
  • It has module paths (us-nj/regulations/njac-5-49/2.2, 2.3, 3.1, 3.2; the handbook, grid and plan modules), corpus citations, verbatim handbook, regulation, plan and fact sheet text, required outputs, and 17 companion tests sourced from the fact sheet, handbook and matrix. It is dispatch-ready under the Add AMT parameters for 2020-2023 #1467 standard.
  • Stale points to update when the fixes land:
    • It records head 0f47f9cd32 and calls the PR an "open draft". Head is 020fbbf346.
    • Companion test 6 lists grid sizes 1, 5, 9, 13 (the PR has used 2, 6, 10, 14 since 924519344a). Test 9 lists sizes 1-14, which S5 would restore.
    • Companion test 15 encodes gross Social Security (12,600) (S1).
    • Interpretation (3) records the fuel-panel choice for subsidized direct payers (C1).
    • The scope needs the S2 rental floor and, if adopted, the FY2027 values (S4).

Next steps

  1. C1: route rent-subsidy direct payers to the Renters panel, decide and document the public-housing reading, and add the $234 test.
  2. S1-S2: net Social Security of medicare_part_b_premium (Case 2 becomes [600, 11_400, 12_600]), and floor each unearned source at zero, with a rental-loss case.
  3. S3-S4: stop the 60% SMI rule before FY2022 (or encode the earlier rule). Compute the step as monthly(12) − monthly(11). Add the FY2027 entries, including the 474 cell, or document the carry-forward.
  4. S5-S7: restore the 14-size limit test, add the size-edge and four branch tests, align the parameter descriptions, and retarget the three anchors.
  5. Rebase on main (coverage line as above), refresh the PR body and rulespec-us#1481, and re-request review.

1 critical and 7 should-address findings, plus 9 suggestions.

Verdict: REQUEST_CHANGES

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes per the review comment above: 1 critical (subsidized tenants who pay their own heating bill get the fuel panel; N.J.A.C. 5:49-2.2(d)1.i gives them the renter level) and 7 should-address items (Social Security counted gross of Part B, rental/farm-rent losses offsetting wages, 60% SMI carried back before FY2022, 2027 paired with FY2026 tables despite published FY2027 tables, test coverage below the PR body's claims, parameter descriptions, wrong handbook anchors). All 128 FY2026 grid cells, bands, regions and income limits match the sources.

hua7450 and others added 2 commits October 6, 2026 17:07
- Pay the renter level to rent-subsidy and public-housing households
  that pay their own heating bill (N.J.A.C. 5:49-2.2(d)1.i).
- Count Social Security net of the Medicare Part B premium; floor every
  unearned source.
- Derive the additional-member increment from the size-12 and size-11
  limits; add the FY2027 handbook, matrix, fact sheet and plan;
  verified_years "2026-2027"; document the FY2027 474 renters cell.
- Read the electric panel for solar heat.
- Add cases for subsidized direct payers, the FY2027 limits and amounts,
  size-group edges, heat in rent over gas, age 18, the student arms and
  the Atlantic County default.
- Re-template descriptions, unquote keys, add separators and retarget
  the reference anchors.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts:
#	policyengine_us/programs.yaml
@hua7450
hua7450 requested a review from DTrim99 October 6, 2026 21:10
@DTrim99

DTrim99 commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

PR Review (round 2): New Jersey LIHEAP regular heating assistance

PR #9745: Add New Jersey LIHEAP regular heating assistance (author: hua7450, head f4d535357b)

Round 1 reviewed head 020fbbf346 and requested changes for 1 critical and 7 should-address findings, plus 9 suggestions. Since then the author has pushed one fix commit, 1abb5bf9d7 ("Address review round 1 on New Jersey LIHEAP"), and merged main into the branch. The author left no reply comment. The commit message, the rewritten PR body and the refreshed rulespec-us#1481 serve as the response.

Overall: the substantive round-1 findings are fixed, and the new FY2027 limits check out against the sources.

  • C1 (subsidized direct payers): these households now get the Renters panel. The round-1 Essex example reproduces at $234, and public housing with its own bill is read the same way and documented.
  • S1 and S2 (income): Social Security now counts net of the computed Part B premium. The round-1 70-year-old example reproduces at $334. Each unearned source is floored per person.
  • S4 (FY2027): the increment is now monthly(12) − monthly(11), and all 14 FY2027 limits reproduce the fact sheet ($246 step).
  • S5 and S6: the four untested branches, the size-group edges and all 14 limits in both years are now tested. The descriptions follow the template.

One new critical finding comes out of the fix:

  • C2 (new, from S4): the PR now claims FY2027 (verified_years: "2026-2027"), but it keeps 471 in the one FY2027 cell that prints 474, and a test pins the 471.

Two should-address items stay open:

  • S3, partially addressed: the 60% SMI carry-back before FY2022 is now documented but still applied.
  • S7, partially addressed: the FY2026 anchors are fixed, but one new FY2027 anchor opens the wrong page.

There is also one new suggestion (N1). Three round-1 suggestions remain open: G4 and G9 are partially addressed, and G8 is optional.

Path prefixes used below:

  • P/ = policyengine_us/parameters/gov/states/nj/dca/liheap/
  • V/ = policyengine_us/variables/gov/states/nj/dca/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/
  • HB26 / HB27 = FY2026 / FY2027 LIHEAP Handbook. In both, the PDF page is the printed page + 1.

Line numbers refer to head f4d535357b. The benefit amounts below were reproduced by running the head code on single households.

Source Documents

# Document Link Use in this round
1 FY2027 Benefit Matrix (one image) FY2027 matrix All 192 printed cells re-read against the PR's tables (C2)
2 FY2027 USF/HEA fact sheet Fact sheet, p. 2 Limits for sizes 1-12 and "add $246 for each additional member"
3 FY2027 LIHEAP Handbook HB27 2.2 (pp. 5-6), 2.3.A-C (p. 7), 2.3.D-E (pp. 8-9), 2.3.F (p. 9), F.7 (p. 11), 3.2.F (p. 13), 3.7.B (p. 19)
4 FY2027 LIHEAP State Plan (report period 10/01/2026 to 09/30/2027) Plan, p. 6 1.8-1.9 (pp. 6-7, read from the rendered checkboxes), 2.1 (p. 9), 2.6 (p. 10)
5 FY2026 LIHEAP State Plan Plan, p. 6 1.9 checkbox comparison with FY2027 (N1)
6 ACF LIHEAP IM 2025-02, Attachment 4 Att. 4, p. 2 Newly cited for the two-stage flooring (NJ $160,276 row)
7 BPU announcement, October 19, 2021 BPU 2021 Pre-FY2022 standard (S3)
8 N.J.A.C. 5:49-2.2 and 2.3 (Cornell LII) 2.2, 2.3 C1, newly cited in the variables

Round-1 findings

Item Status Evidence
C1 Subsidized direct payers got the fuel panel ADDRESSED
  • V/nj_liheap.py:62-76 routes heat_in_rent | subsidized to p.amount.renters. subsidized is receives_housing_assistance | is_in_public_housing. Heat in subsidized rent is still denied at V/eligibility/nj_liheap_eligible.py:39.
  • The public-housing reading is decided and documented at V/nj_liheap.py:60-61 ("the rule names only the subsidy"), as round 1 asked.
  • T/nj_liheap.yaml:286 (Case 13) expects [529, 234, 234] for no subsidy, a voucher and public housing.
  • Reproduced at head: the Essex adult with $12,000 of wages, a $1,500 electric bill and receives_housing_assistance: true gets $234.
  • The comment, the PR conflict table and rulespec-us#1481 interpretation (3) are updated.
S1 Social Security counted gross of Part B ADDRESSED
  • V/income/nj_liheap_countable_income_person.py:47-52 counts max_(social_security - medicare_part_b_premium, 0) for adults. The comment at :42-46 cites HB26 2.3.F.7(a) and E.8.
  • T/income/nj_liheap_countable_income_person.yaml:87 (Case 2) now expects [600, 11_400, 12_600], the value round 1 proposed.
  • New T/integration.yaml:207 (Case 5) covers a premium payer ($334) and a retiree whose premium an MSP pays ($0).
  • Reproduced with the model's own premium ($2,434.80): countable income $47,964, limit $50,004, $334, in both 2026 and 2027.
  • rulespec-us#1481 test 15 now expects 11,400.
S2 Losses offset other income ADDRESSED
  • V/income/nj_liheap_countable_income_person.py:57-59 floors each unearned source per person, so there is no cross-member offset either.
  • The documentation at V/income/nj_liheap_countable_income.py:20-22 states the rule.
  • Person Case 4 (T/income/nj_liheap_countable_income_person.yaml:123) gives 60,000 / 80,000, and T/nj_liheap.yaml:364 (Case 17) gives $60,000, ineligible, $0. Both reproduce.
S3 60% SMI carried back before FY2022 PARTIALLY ADDRESSED: open
  • Documented at P/eligibility/smi_rate.yaml:2-4 and V/eligibility/nj_liheap_income_limit.py:25-27, with the BPU page cited.
  • The program is not gated, and smi_rate is still dated 2025-10-01 only. See S3 below.
S4 Period 2027 paired FY2027 limits with FY2026 tables PARTIALLY ADDRESSED
  • The step is now monthly_limit(12) - monthly_limit(11) (V/eligibility/nj_liheap_income_limit.py:38-51). In period 2027, sizes 13-15 give 12,571 / 12,817 / 13,063, matching the fact sheet.
  • T/eligibility/nj_liheap_income_limit.yaml:30 (Case 2) asserts all 14 FY2027 limits.
  • The FY2027 handbook, matrix, fact sheet and plan are cited throughout.
  • The 474 cell was not stored, while 2027 is now claimed. This is escalated as C2 below.
S5 Tests covered less than claimed; four untested branches ADDRESSED
  • Limits for sizes 1-14 in both years (income-limit Cases 1-2), and the size-group edges 8, 9, 12 and 13 (T/nj_liheap.yaml:328, Case 15).
  • The four branches now have tests: public housing with heat in rent (T/eligibility/nj_liheap_eligible.yaml:39-49), heat in rent with NATURAL_GAS (T/nj_liheap.yaml:309, $234), age 18 (person Case 5, :141) and both arms of the students-only test (eligible Case 6, :111).
  • By inspection, each case fails under the corresponding round-1 mutation.
  • The C1, S1 and S2 cases are added, and the PR-body claim is rewritten.
S6 Parameter descriptions ADDRESSED
  • All six rows use the proposed wording.
  • The expense note moved to a YAML comment (P/income/sources/earned.yaml:2-3).
S7 Three wrong anchors and one partial PARTIALLY ADDRESSED: open
  • Fixed: V/nj_liheap.py:15 → HB26 p. 12; P/income/sources/unearned.yaml:26 → p. 8; P/income/adult_age.yaml:10 → p. 9; V/income/nj_liheap_countable_income.py:13 → p. 9.
  • New: the FY2027 entry at V/income/nj_liheap_countable_income.py:15 opens the wrong page. See S7 below.
G1 SOLAR and OTHER paid $0 ADDRESSED
G2 Unknown county ADDRESSED
  • T/nj_liheap.yaml:344 (Case 16) omits the county and expects region 1, $334.
  • The documentation in V/payment/nj_liheap_region.py and V/nj_liheap.py:31 covers it.
G3 Documentation accuracy ADDRESSED
  • The "2017 expiration" and "This draft" wording is gone (V/eligibility/nj_liheap_income_limit.py:21-28).
  • "Inferred" is replaced with the ACF Att. 4 citation (:17, :40-42).
  • The SSI Lifeline sentence is reworded (V/income/nj_liheap_countable_income_person.py:25-26).
G4 Reference titles and variable comments PARTIALLY ADDRESSED
  • Fixed: the adult_age title, the 2.2.5 section on the disregard, "Benefit Matrix" in the grid titles, and plan 1.9 cited for the unearned list.
  • Still open: eight titles now carry "PDF pages …" text (P/income/sources/earned.yaml:15,17,19,21; unearned.yaml:25,27,29,31, up from three). Twelve # PDF pages … comments sit above single hrefs in six variables, including the new FY2027 entries (for example V/nj_liheap.py:14,16).
G5 PR body ADDRESSED
  • The "remains draft" and "not re-run" lines are gone.
  • The coverage claim is rewritten, and the subsidized-renter row (plan 2.3) is in the conflict table.
  • The new claim that the tests cover "the FY2027 renters cell" is addressed under C2.
G6 Separators and key style ADDRESSED All four-digit values use _, and the top-level keys are unquoted.
G7 Test hygiene ADDRESSED
  • heating_type is removed from the limit and income tests, and the unused inputs are removed from Case 12.
  • The New York unit uses KINGS_COUNTY_NY.
  • Eligible Case 2 no longer forces has_heating_expense with heat in rent.
  • Person Case 6 sets all 14 unearned sources.
G8 Optional nj_liheap_income_eligible NOT ADDRESSED Optional. No change.
G9 rulespec-us#1481 stale PARTIALLY ADDRESSED Refreshed to head f4d535357b, with two stale points left. See the Axiom line section.

Critical (Must Fix)

C2 (new, from round-1 S4). Period 2027 is now claimed, but the one FY2027 cell that differs from FY2026 is pinned at the FY2026 value

  • What changed:

    • The fix sets verified_years: "2026-2027" (policyengine_us/programs.yaml:885).
    • The changelog now reads "for FY2026 and FY2027" (changelog.d/nj-liheap.added.md:1).
    • The documentation says "verified for FY2026 and FY2027" (V/nj_liheap.py:24).
    • The grid parameters still have a single 2025-10-01 value, and P/payment/income_band.yaml still merges the rows "$0 - $1000", "$1001 - $2000" and "$2001 - $6439" into band 1.
  • Source: the FY2027 Benefit Matrix, "The 2027 Benefit Grid for: Renters", "Warren & Sussex Counties", column "13 or More".

    • The rows "$0 - $1000" and "$1001 - $2000" print 471, and the row "$2001 - $6439" prints 474.
    • I re-read the whole image this round. The other 191 printed cells match the PR's tables.
  • Where the PR keeps 471:

    • P/payment/amount/renters.yaml:47-50: the comment says "the combined band keeps 471".
    • V/nj_liheap.py:26-29.
    • T/nj_liheap.yaml:386-398 (Case 18) asserts nj_liheap: [471, 471] at period 2027 for $1,000 and $3,000 a month. The second expectation contradicts the printed cell.
  • Reach (reproduced, period 2027): households in Warren or Sussex with 13 or more members and $2,001 to $6,439 a month. The household must have heat in its rent or, since the C1 fix, a rent subsidy or public housing with its own heating bill.

    • A Sussex voucher holder heating with gas, 13 members, $3,000 a month: $471; the matrix prints $474.
    • Warren heat-in-rent households at $2,500 and $6,416.67 a month: $471.
  • Why critical:

    • Under the batch rule, a value that contradicts the published table in a claimed year is critical (Add Indiana EAP regular heating assistance #9728 C1, Add Oregon LIHEAP regular heating assistance #9743 C1).
    • Round-1 S4 was a should only because "only 2026 is claimed". The fix changed that.
    • Disclosure does not make the value a sourced choice. This is the same reasoning as round-1 C1 (fix item 5): no FY2027 document says to pay 471 in that row. The PR otherwise keeps every printed anomaly ($961, and the 821 and 445 cells).
    • The reach is small, and either fix below is short.
  • Fix, either option:

    1. Store the cell. Split band 1 at $2,001, for all years or from 2026-10-01. Repeat the band-1 values in the new band in all four tables, and give the Renters, Warren & Sussex, 13+ entry of the new band 2025-10-01: 471 and 2026-10-01: 474. Case 18 then expects [471, 474], with the new band for the $3,000 household. Add a period-2026 row at $3,000 that still gives 471.
    2. Narrow the claim to what is verified. Set verified_years: "2026" and return the changelog and documentation to FY2026. Write registry notes saying 2027 uses the FY2027 limits with the FY2026 grid, which differs from the FY2027 matrix in this one cell. Drop Case 18 or recast it as a documented gap; the FY2027 limit test can stay.

    Either way, update the PR body, which lists "the FY2027 renters cell" as covered, and rulespec-us#1481 companion test 23.

Should Address

S3 (round 1, still open). Periods 2021 and earlier still apply 60% SMI, and the documentation calls values that are known to differ "unverified"

  • What changed:
    • A comment at P/eligibility/smi_rate.yaml:2-4, documentation at V/eligibility/nj_liheap_income_limit.py:25-27, and the BPU page in both reference lists.
    • The PR body and rulespec-us#1481 explain why no earlier rule is encoded: the BPU's $4,039 figure for four reproduces at 185% of the 2020 guideline, not the 200% it names. The observation is correct ($26,200 × 1.85 / 12 = $4,039.17, while 200% gives $4,366.67). It is a fair reason not to encode a poverty-level rule from that page alone.
  • What did not change:
    • Round 1's second option, starting the program in FY2022, was neither taken nor answered.
    • smi_rate still has a single 2025-10-01 entry, so the rate and the benefit carry back.
    • Reproduced at head, the size-4 monthly limit is $6,172 for period 2021 and $5,922 for period 2020. The BPU gives $4,039 under the pre-FY2022 test. Periods 2022 and later are unchanged and correct ($6,439 in 2022).
  • "Unverified" understates the problem: the source the PR itself cites shows that these limits are about 50% too high.
  • Severity: should, unchanged. This is a known-different carry-back into unclaimed years.
  • Fix:
    • Gate the program to FY2022 onward and cite BPU. For example, add a dated boolean that nj_liheap_eligible checks. It needs an explicit early false entry, because Backdate parameters before applying reforms #9628 now backdates the earliest value, and true from 2021-10-01.
    • Date smi_rate from 2021-10-01.
    • Add a period-2021 case expecting nj_liheap: 0.
    • Keeping the carry-back with more accurate wording would leave this item open.

S7 (round 1, partially addressed). The new FY2027 anchor in nj_liheap_countable_income opens a page without the rounding rule

  • What is fixed: the three wrong FY2026 anchors and the partial one (see the round-1 table).
  • What is new:
    • V/income/nj_liheap_countable_income.py:15 cites HB27 #page=10, and the comment at :14 lists "PDF pages 6, 10, 11".
    • HB27 p. 10 holds 2.3.F.1-6: zero-income declarations, household composition, foster children and roomer-boarders.
    • The rule the variable applies is 2.3.F, "Cents shall be rounded to the nearest dollar". It is on HB27 p. 9, the same page as in FY2026. Only F.7 moved, to p. 11.
    • The variable's own comment (:29) cites "page 9".
  • Fix: change #page=10 to #page=9, and the comment to "PDF pages 6, 9, 11". Every other new FY2027 anchor opens on its content (see Verified correct).
  • Severity: should, consistent with round-1 S7 and Add Oregon LIHEAP regular heating assistance #9743 S6. The fix is one character.

Suggestions

N1. The FY2027 plan unchecks Strike Pay, General Assistance and TANF, which the model counts

  • FY2027 plan 1.9, p. 6 leaves three boxes unchecked: "Strike Pay", "General Assistance benefits" and "Temporary Assistance for Needy Families (TANF) benefits". FY2026 plan 1.9, p. 6 checks all three.
  • The model counts strike_benefits and general_assistance (P/income/sources/unearned.yaml:5,11) and adds tanf at the unit level (V/income/nj_liheap_countable_income.py:28). unearned.yaml:31-32 now cites FY2027 plan 1.9 as a source for the list.
  • The model's choice is still defensible:
    • HB27 2.2, p. 6, ineligible item 4, still reads "Households whose total income, including any TANF, GA or SSI grants, exceeds the total income eligibility standards". Following the handbook matches the PR's other handbook-over-plan choices.
    • Strike benefits matter little, because 2.2.3 (p. 5) makes households with striking members ineligible.
  • Suggestion: add a conflict-table row and a short comment in unearned.yaml (and next to the tanf add) saying that the FY2027 plan unchecks these sources and the handbook controls. Mirror it in rulespec-us#1481's interpretations.

G4, G8, G9 (round 1, still open)

See the round-1 table. G4 is cosmetic: split the page lists out of the eight titles and use single-page tuples in the variables. G8 remains optional. G9 is covered in the Axiom line section.

Verified correct

Check Result
FY2027 grid (matrix)
  • All 128 parameter cells were compared with the image: 4 panels × 2 regions × 4 bands × 4 size groups.
  • All 128 match the printed rows they represent. The only exception is the "$2001 - $6439" row inside band 1 for Renters, Warren & Sussex, 13+ (474, C2).
  • The row labels, the "All Other (19)" and "Warren & Sussex" columns and the size columns are unchanged from FY2026.
Income limits
  • FY2026 sizes 1-14 (Case 1) and FY2027 sizes 1-14 (Case 2) equal the published monthly limits × 12.
  • FY2027 matches the fact sheet, p. 2: 4,273 / 5,587 / 6,902 / 8,217 / 9,532 / 10,846 / 11,093 / 11,339 / 11,586 / 11,832 / 12,079 / 12,325, then + $246.
  • The new step formula gives $241 and $246.
Period logic
  • No parameter gained a dated value. Period 2027 reads gov.hhs.smi on 2027-01-01, the FY2027 SMI, so the FY2027 limits come from the federal SMI series, and the single-dated NJ scalars carry forward.
  • The FY2027 sources keep every carried scalar:
    • 60% SMI: HB27 2.3.A p. 7; plan 2.1 p. 9.
    • $500 disregard: HB27 2.2.5 p. 6.
    • Child exclusions: HB27 E.9 p. 9; plan 1.9 p. 7, where the child-earnings box is unchecked.
    • Part B netting: HB27 E.8 p. 9 and F.7(a) p. 11; plan 1.9 p. 6, "Excluding MediCare deduction" checked.
    • Fuel rule: HB27 3.2.F p. 13.
    • $1,278 maximum: HB27 3.7.B p. 19; plan 2.6 p. 10.
    • Ineligible list: HB27 2.2 p. 6, again without 5:49-2.2(d)1.i, which supports the C1 reading.
Reproductions (head code)
  • C1: $529 / $234 / $234. A voucher holder with OTHER fuel and its own bill also gets $234, which (d)1.i supports.
  • S1: computed premium $2,434.80 → countable income $47,964 → $334.
  • S2: $60,000 → $0.
  • S4: period 2027, sizes 12-15 = 12,325 / 12,571 / 12,817 / 13,063.
  • The default receives_housing_assistance is false, so unsubsidized cases are unchanged.
New test expectations (hand-checked)
  • Integration Case 5 (all five outputs).
  • T/nj_liheap.yaml Cases 13-17, plus the Case 9 solar value.
  • Person Cases 2, 4, 5 and 6 (100 × (1 + … + 14) = 10,500, in list order).
  • Eligible Cases 2 and 6.
  • All 28 values in income-limit Cases 1-2.
All are correct against the sources. The exception is the Case 18 $3,000 row (C2).
Local run
  • All 39 NJ LIHEAP YAML cases pass on the extracted head tree.
  • tests/code_health/test_reference_urls.py, test_no_concatenated_reference_urls.py, test_known_dead_reference_urls.py and tests/test_programs_registry.py also pass.
  • Two AST guards (test_no_builtin_sum_over_entity_calls.py, test_no_in_place_writes_to_cached_arrays.py) failed only on a Windows encoding error. They pass in UTF-8 mode.
New anchors
  • Each opens on its cited content: HB26 pp. 8, 9 and 12; HB27 pp. 5, 6, 7, 8, 9 and 13; FY2027 fact sheet p. 2; FY2027 plan pp. 6, 7 and 9; ACF Att. 4 p. 2 (the NJ $160,276 row); the LII pages for 5:49-2.2, 2.3 and 3.2; the BPU page.
  • The exception is HB27 p. 10 in nj_liheap_countable_income (S7).
Code
  • The per-person, per-source floor matches the earned loop.
  • The SOLAR mapping matches heating_expense.
  • The renter-level routing never reaches heat in subsidized rent, which eligibility already denies.
  • No hard-coded values, no unused parameters, vectorized throughout, and the mixed NJ/NY case still runs.
  • The changelog fragment is top-level and updated.
Merge of main
  • Of the PR's 30 files, only programs.yaml changed in the merge, and only by main's own entries. The coverage line is now DC, Riverside County, MA, IL, IN, KS, KY, MS, NC, NE, NJ, TX (programs.yaml:811), the OR block is absent, and the NJ entry sits between NE and TX (:879). The round-1 conflict is resolved as proposed.
  • The merge's other change in an NJ path, to nj_medical_expense_deduction.py, is main's and outside this PR.
Main's guards

CI status

gh pr checks 9745 on head f4d535357b (2026-10-06, 22:03 UTC) shows 5 passed, 30 pending and 0 failed.

  • Passed: changelog fragment, committed registry lock, release lock guard, bundle metadata contract, and py3.12 smoke import.
  • Pending: the Full Suite shards have not finished.

Locally, all 39 NJ LIHEAP cases and the reference-URL and registry guards pass (see above). Round 1's head passed 37/37.

Branch status

  • 13 commits ahead of main and 0 behind. The merge base is main's tip, 9eab717e56.
  • GitHub reports MERGEABLE, with merge state BLOCKED (changes requested, CI pending).

Axiom line

axiom: TheAxiomFoundation/rulespec-us#1481 queued. The line is still in the PR body, and the form is valid.

  • The issue was refreshed at 21:38 UTC today. It is open and labelled pe-parity. It now:
    • pins head f4d535357b;
    • scopes FY2026-FY2027 and adds the FY2027 sources and limits;
    • updates test 15 to 11,400 and interpretation (3) to the renter level;
    • adds companion tests 18-27 (subsidized direct payers, heat in rent over gas, size edges, county default, rental loss, age 18, every source, Part B);
    • records the pre-FY2022 decision.
  • Two stale points remain:
    • Companion test 6 still describes grid sizes 1, 5, 9 and 13. The PR has used 2, 6, 10 and 14 since 924519344a. The cells are the same, but the inputs differ. This was carried over from round 1.
    • Companion test 23 expects $471 for the $3,000-a-month row, although the FY2027 grid prints 474. This contradicts two statements in the issue itself: that "None is taken from policyengine-us output", and its advice that "an Axiom encoding should key all six printed rows". Update it together with C2.
  • This stays a suggestion, consistent with round 1.

Next Steps

  1. C2: store the FY2027 474 cell (split band 1 at $2,001) or narrow the claim to 2026. Update Case 18, the PR body and rulespec-us#1481 test 23.
  2. S3: gate the program to FY2022 onward, citing BPU, and date smi_rate from 2021-10-01. Add a period-2021 case.
  3. S7: change the HB27 anchor in nj_liheap_countable_income to #page=9.
  4. Optional: N1 (FY2027 plan 1.9 conflict row), G4, G8, and rulespec-us#1481 test 6. Re-request review once CI is green.

1 critical finding (new: C2) and 2 should-address findings (S3, S7, both partially addressed) are open, plus 1 new suggestion (N1) and 3 open round-1 suggestions (G4, G8, G9).

Verdict: REQUEST_CHANGES

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round 2: C1 (subsidized direct payers now get the renter level), S1, S2, S5 and S6 are addressed and verified. Still open: a new critical C2 — the PR now claims 2027, but the FY2027 matrix prints 474 for Renters / Warren & Sussex / 13+ / $2,001-$6,439 and the PR keeps 471 (split band 1 at $2,001 and store 474, or narrow the claim to 2026); S3 — 60% SMI is still applied before FY2022 (documented but not gated or encoded); S7 — the new handbook anchor in nj_liheap_countable_income.py should be #page=9. CI on the new head was still running at review time.

hua7450 and others added 2 commits October 7, 2026 15:20
- Store the FY2027 Warren and Sussex renters cell (474) by giving the
  $2,001 to $6,439 income row its own band.
- Gate the program to FY2022 onward with eligibility/in_effect and date
  smi_rate from 2021-10-01.
- Point the FY2027 handbook anchor in nj_liheap_countable_income at
  page 9.
- Note the FY2027 plan 1.9 conflict on strike pay, general assistance
  and TANF.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@hua7450

hua7450 commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for round 2. Fixes pushed in ee00db7.

  • C2: the 474 cell is stored. Band 1 is split at $2,001 for all years, so the grid has five bands (160 cells); the Renters, Warren & Sussex, 13+ cell of the new band carries 2025-10-01: 471 and 2026-10-01: 474. Case 18 expects [471, 474] at period 2027, and Case 19 pins the same household at $3,000 a month in period 2026 at 471. The body, registry note and LIHEAP wave 1b: encode New Jersey LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1481 test 23 are updated.
  • S3: the program is gated to FY2022 onward. eligibility/in_effect.yaml (0000-01-01: false, 2021-10-01: true, citing BPU) is checked in nj_liheap_eligible, smi_rate is dated 2021-10-01, and Case 20 expects nj_liheap: 0 in period 2021 for a household the FY2026 rules would pay.
  • S7: the HB27 anchor in nj_liheap_countable_income is #page=9; the comment reads "PDF pages 6, 9, 11".
  • N1: noted in unearned.yaml, at the tanf add and in the body's conflict table: the FY2027 plan unchecks Strike Pay, General Assistance and TANF; handbook 2.2 counts TANF and GA grants toward the standard and 2.2.3 excludes striker households, so the handbook controls.
  • G4: the title convention is now settled in AGENTS.md (one entry per source; a single page in the href only; #page a-b for consecutive pages). The Oregon files carry it; New Jersey's titles follow in a later pass.
  • G8: optional, not added.
  • LIHEAP wave 1b: encode New Jersey LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1481: test 6 now names sizes 2, 6, 10 and 14; test 23 expects 474; the band definitions, the gate and the plan 1.9 note are added.

@hua7450
hua7450 requested a review from DTrim99 October 7, 2026 19:21
@DTrim99

DTrim99 commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

PR Review (round 3): New Jersey LIHEAP regular heating assistance

PR #9745: Add New Jersey LIHEAP regular heating assistance (author: hua7450, head ee00db7d60)

Round 2 reviewed head f4d535357b and requested changes for 1 critical finding (C2) and 2 should-address findings (S3, S7), plus 1 new suggestion (N1) and 3 open round-1 suggestions (G4, G8, G9). Since then the author has pushed one fix commit, 5befaf93f6 ("Address review round 2 on New Jersey LIHEAP"), and merged main into the branch. The author replied point by point on the PR, updated the PR body and refreshed rulespec-us#1481.

Overall: every critical and should-address item is fixed.

  • C2 (FY2027 cell): band 1 is now split at $2,001, and the Renters, Warren & Sussex, 13+ entry of the new band carries 2026-10-01: 474. I re-read the FY2027 matrix against all 160 stored cells and found no mismatch. The FY2026 matrix also matches all 160. The round-2 Sussex example now reproduces at $474 in 2027 and $471 in 2026.
  • S3 (pre-FY2022): the program is gated to FY2022 onward by a new eligibility/in_effect parameter, with an explicit early false. Periods 2020 and 2021 now return $0. Periods 2022 and later are unchanged ($334 for the Case 20 household).
  • S7 (anchor): the FY2027 handbook anchor in nj_liheap_countable_income now opens p. 9, where the rounding rule is.
  • N1 is addressed in the code, the PR body and rulespec-us#1481. G9 is addressed. G4 is deferred by the author, and G8 (optional) is declined.

There is one new suggestion (N2): the new $2,001 band edge has no test that can catch a wrong value. There are no new critical or should-address findings.

Path prefixes used below:

  • P/ = policyengine_us/parameters/gov/states/nj/dca/liheap/
  • V/ = policyengine_us/variables/gov/states/nj/dca/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/nj/dca/liheap/
  • HB26 / HB27 = FY2026 / FY2027 LIHEAP Handbook. In both, the PDF page is the printed page + 1.

Line numbers refer to head ee00db7d60. The benefit amounts below were reproduced by running the head code on single households.

Source Documents

# Document Link Use in this round
1 FY2027 Benefit Matrix (one image) FY2027 matrix All 160 stored cells re-read for period 2027 (C2)
2 FY2026 Benefit Matrix FY2026 matrix All 160 stored cells re-read for period 2026, including the new band 2
3 FY2027 LIHEAP Handbook HB27, p. 9 2.3.F rounding on p. 9 (S7); 2.2.3 strikers on p. 5 and 2.2 item 4 on p. 6 (N1 comments)
4 BPU announcement, October 19, 2021 BPU 2021 The move from "200% of the Federal Poverty Level to 60% of the State Median Income", $4,039 to $6,439 for four (S3 gate)
5 FY2023 and FY2024 Benefit Matrices (ACF clearinghouse) FY2023, FY2024 Context for the now-explicit FY2022-FY2025 backfill (see Verified correct)

Round-2 findings

Item Status Evidence
C2 FY2027 claimed, but the 474 cell was pinned at 471 ADDRESSED
  • The split is encoded as round 2 proposed (option 1). P/payment/income_band.yaml:10-13 adds a threshold at 2_001 for band 2, and the old bands 2-4 become 3-5 (:14-25). The comment at :1-3 explains why.
  • All four tables now break down by range(1, 6) (renters.yaml:103, and :100 in gas.yaml, electric.yaml and deliverables.yaml). Each new band 2 repeats its band 1 values (for example renters.yaml:12-20 and :58-69).
  • P/payment/amount/renters.yaml:67-69 stores 2025-10-01: 471 and 2026-10-01: 474 in the Warren & Sussex, band 2, 13+ entry. The comment at :65-66 names the row.
  • All 160 stored cells match the FY2027 matrix for period 2027 and the FY2026 matrix for period 2026, including the 32 new band-2 cells.
  • T/nj_liheap.yaml:386-398 (Case 18): period 2027, bands [1, 2], [471, 474]. :402-414 (Case 19): period 2026, band 2, $471. I hand-checked both against the two matrices.
  • Reproduced end to end for a 13-member Sussex voucher holder heating with gas. In 2027: $2,000 a month → $471; $2,001, $3,000 and $6,439 → $474; $6,440 → $394. In 2026, the same household gets $471 across $2,001-$6,439.
  • Registry notes (programs.yaml:886), documentation (V/nj_liheap.py:24-30, V/payment/nj_liheap_income_band.py:17-20), the PR body and rulespec-us#1481 test 23 are updated. The changelog keeps "FY2026 and FY2027", which is now accurate.
S3 60% SMI applied before FY2022 ADDRESSED
  • New P/eligibility/in_effect.yaml:6-8: 0000-01-01: false, 2021-10-01: true. The explicit early value prevents Backdate parameters before applying reforms #9628's earliest-value backdating, and 0000-01-01 is the repo's usual form (over 500 files under parameters/ use it).
  • The parameter cites BPU and HB26 2.3.A.
  • V/eligibility/nj_liheap_eligible.py:43 ANDs p.in_effect into eligibility, and nj_liheap is defined_for it. P/eligibility/smi_rate.yaml:6 is dated 2021-10-01.
  • The BPU source supports FY2022 as the start: "DCA's LIHEAP program's income eligibility criteria changed from 200% of the Federal Poverty Level to 60% of the State Median Income, resulting in an increase of the income threshold for a family of four from $4,039.00 gross monthly income to $6,439.00". $6,439 is the FY2022 60% SMI limit for four, which the model produces for period 2022.
  • T/nj_liheap.yaml:422-435 (Case 20) expects ineligible and $0 in period 2021.
  • Reproduced with the Case 20 household: 2020 and 2021 give ineligible, $0; 2022 and 2025 give eligible, $334. With in_effect forced true, 2021 gives $334, so Case 20 fails under that mutation.
  • The "unverified" carry-back wording is replaced (V/eligibility/nj_liheap_income_limit.py:26-27, smi_rate.yaml:2-4, V/nj_liheap.py:24-26, V/eligibility/nj_liheap_eligible.py:21-22).
S7 New FY2027 anchor opened the wrong page ADDRESSED
  • V/income/nj_liheap_countable_income.py:15 now cites HB27 #page=9, and the comment at :14 reads "PDF pages 6, 9, 11".
  • Opened: p. 9 ends with 2.3.F, "Cents shall be rounded to the nearest dollar."
N1 FY2027 plan unchecks Strike Pay, GA and TANF ADDRESSED
  • Comments at P/income/sources/unearned.yaml:5-8 and V/income/nj_liheap_countable_income.py:27-30.
  • A new conflict-table row in the PR body, and an interpretation in rulespec-us#1481.
  • The cited text checks out in HB27: 2.2.3 (p. 5), "Strikers and households that include striking members are ineligible", and 2.2 item 4 (p. 6), "including any TANF, GA or SSI grants".
G4 Reference titles and variable comments ACKNOWLEDGED-DEFERRED
  • The author defers this to "a later pass" under a title convention he places in AGENTS.md. This repo's AGENTS.md at head has no such section, so I could not check the convention he means.
  • Unchanged: eight titles still carry "PDF pages …" (P/income/sources/earned.yaml:15,17,19,21; unearned.yaml:29,31,33,35), and twelve # PDF pages comments remain in the variables.
  • Cosmetic. It stays a suggestion.
G8 Optional nj_liheap_income_eligible NOT ADDRESSED (optional, declined) The author declined. No action needed.
G9 rulespec-us#1481 stale ADDRESSED
  • The issue was refreshed at 19:21 UTC today, alongside the PR comment. It is open and labelled pe-parity.
  • Test 6 now names sizes 2, 6, 10 and 14. Test 23 now expects bands 1 and 2, $471 and $474, plus Case 19's $471 in 2026. A new test 28 covers the gate.
  • The income-band variable lists all five thresholds, and the pre-FY2022 and plan 1.9 interpretations are added.
  • One nit: two sentences still name the old head. One says "Everything below describes head f4d535357b". The other says "Cases are named as in the YAML files at head f4d535357b … Run locally on 2026-10-06: 39 passed", while the header says 41 cases at ee00db7d60.

Critical (Must Fix)

None.

Should Address

None.

Suggestions

N2 (new, from the C2 fix). Pin the new $2,001 band edge, and optionally the new band-2 cells

  • The threshold is unpinned.
    • P/payment/income_band.yaml:11 puts the band 2 edge at $2,001, and the code places $2,000 and $2,001 correctly (reproduced: $471 and $474 in 2027).
    • T/nj_liheap.yaml:216-226 (Case 10) already holds the $2,000 and $2,001 rows (24,000 and 24,012). But it asserts only nj_liheap, which is $334 in both bands in that gas cell.
    • Case 18 uses $1,000 and $3,000, and the integration cases pin band 1 only at $1,000.
    • So any edge from $1,001 to $3,000 passes all 41 cases.
    • Fix, either of:
      • add nj_liheap_income_band: [1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5] to Case 10;
      • add $2,000 and $2,001 rows to Case 18, expecting [471, 474].
  • Most new band-2 cells are untested.
    • Cases 1-8 read bands 1, 3, 4 and 5. Of the 32 new band-2 entries, only gas / All Other / "1 to 4" (Cases 10-11, integration Case 5) and the 474 cell (Cases 18-19) are reached.
    • I checked the other 30 by eye against both matrices, and they are correct.
    • Optional: add a 24,012 row to each of Cases 1-8 so that a later typo in a band-2 copy would fail.
  • Severity: suggestion. Every value is correct today, and checklist item 8 (band-edge tests) is the reason to add it.

G4, G8 (round 1, still open)

  • G4 is deferred by the author and is cosmetic. Split the page lists out of the eight titles, and use single-page anchors in the variables.
  • G8 was declined, which is fine.

Verified correct

Check Result
FY2027 grid (matrix)
  • All 160 parameter cells (4 panels × 2 regions × 5 bands × 4 size groups) match the printed rows they represent, read at period 2027.
  • Band 2 = "$2001 - $6439" in every panel. The 474 cell is the only band-2 value that differs from band 1.
FY2026 grid (matrix) All 160 cells match at period 2026. "$2001 - $6439" prints the band-1 values everywhere, including 471 in the renters cell.
Backfill FY2022-FY2025 (not claimed)
  • The FY2023 and FY2024 matrices print the same 192 cells as FY2026 (FY2025 was already confirmed in round 1), so the grid backfill holds for 2023-2026.
  • FY2022 is unchecked. It sits outside verified_years and is labelled an unverified estimate (V/nj_liheap.py:24-26).
Gate mechanics
  • Period 2021 reads in_effect on 2021-01-01 (false), and period 2022 reads it on 2022-01-01 (true).
  • The pre-gate smi_rate backdates harmlessly, because eligibility is already false.
  • The description follows the existing "provides … when this is true under …" pattern.
  • The new BPU reference on nj_liheap_eligible and the HB26 p. 7 reference on in_effect open on their content.
New and changed test expectations (hand-checked)
  • Case 18: $1,000 → band 1, $471; $3,000 → band 2, $474.
  • Case 19: band 2, $471.
  • Case 20: ineligible, $0.
  • Integration Case 4: $7,167 → band 3 (T/integration.yaml:192-193).
  • The integration Case 1 comment now says "first two printed rows".
  • All are correct against the sources.
Code
  • The lookup p.amount.<panel>[region][band][size] is unchanged and still floors band 0 to 1 for out-of-state units.
  • The split adds no formula logic, no hard-coded values and no unused parameters.
  • nj_liheap is still not in any aggregate (it is referenced only in programs.yaml).
Local run
  • All 41 NJ LIHEAP YAML cases pass on the extracted head tree.
  • These also pass: tests/code_health/test_reference_urls.py, test_no_concatenated_reference_urls.py, test_known_dead_reference_urls.py, test_no_builtin_sum_over_entity_calls.py, test_no_in_place_writes_to_cached_arrays.py and test_uprating_placement.py (in UTF-8 mode), plus tests/test_programs_registry.py. The total is 745 passed and 10 skipped.
Merge of main
  • The merge of b7e4229d86 changed none of the PR's 31 files: git diff 5befaf93f6 ee00db7d60 over them is empty.
  • The coverage line is still DC, Riverside County, MA, IL, IN, KS, KY, MS, NC, NE, NJ, TX (programs.yaml:811), and the NJ entry still sits between NE and TX (:879-886).
  • The changelog fragment is top-level and unchanged.
Main's guards

CI status

Round-2 head f4d535357b (run 37531688983): 34 jobs passed and 1 failed, "Full Suite - Baseline (contrib-hhs)". The failure is unrelated to this PR:

  • Batches 1-4 of test-yaml-no-structural-other-contrib all passed (1, 9, 2 and 3 tests, each with exit 0).
  • During batch 5, the log shows make: *** [...] Terminated, then "The runner has received a shutdown signal" and exit code 143. That is a runner shutdown, not a test failure, and the HHS half of the job never started.
  • No NJ LIHEAP test runs in that shard. The NJ cases run in the states shards, and all eight of those passed on that head.

Current head ee00db7d60 (run 37673787748): the first attempt was cancelled before any job ran, and the re-run (attempt 2) is queued. At 20:58 UTC today, gh pr checks 9745 shows 3 pending, 0 passed and 0 failed: changelog fragment, committed registry lock, and release lock guard tests. The Full Suite jobs are not listed yet.

Locally, all 41 NJ LIHEAP cases and the reference-URL, AST and registry guards pass (see above).

Branch status

  • 15 commits ahead of main and 5 behind. Main moved after the merge, and none of the 5 new commits touches a PR file. git merge-tree against current main is clean.
  • GitHub reports MERGEABLE, with merge state BLOCKED (changes requested, CI pending).

Axiom line

axiom: TheAxiomFoundation/rulespec-us#1481 queued. The line is still in the PR body, and the form is valid.

  • The issue was refreshed to head ee00db7d60. It is open and labelled pe-parity. It now covers the five bands, the 474 cell (test 23, with Case 19), the FY2022 gate (test 28, citing BPU) and the FY2027 plan 1.9 conflict. Test 6 now uses sizes 2, 6, 10 and 14.
  • Both round-2 stale points are fixed. The remaining nit is the two sentences that still name f4d535357b and "39 passed" (see G9).

Next Steps

  1. Optional: N2 (assert nj_liheap_income_band in Case 10 or add $2,000 and $2,001 rows to Case 18, and optionally a band-2 row in Cases 1-8), G4 when convenient, and the two stale sentences in rulespec-us#1481.
  2. Let the re-run on ee00db7d60 finish.

0 critical and 0 should-address findings are open. C2, S3, S7, N1 and G9 are addressed, G4 is deferred and G8 is declined. There is 1 new suggestion (N2).

This approval assumes the CI re-run on ee00db7d60, which is still queued, passes.

Verdict: APPROVE

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round 3: C2, S3 and S7 are all addressed and verified. Band 1 now splits at $2,001 and the FY2027 cell stores 474 (all 160 FY2026/FY2027 cells match the matrices), 60% SMI is gated to start in FY2022 per the BPU 10/19/2021 notice, and the 2.3.F anchor opens on its text. The round-2 contrib-hhs failure was a runner shutdown (exit 143) in a shard with no NJ tests. One optional suggestion: pin the $2,000/$2,001 band edge. The CI re-run on ee00db7 was still queued at review time, so please confirm it is green before merging.

# Conflicts:
#	policyengine_us/programs.yaml
@hua7450
hua7450 merged commit e19f75c into main Oct 8, 2026
28 checks passed
@hua7450
hua7450 deleted the nj-liheap branch October 8, 2026 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement New Jersey LIHEAP regular heating assistance

2 participants