Repository navigation
Add a national LIHEAP total, an Illinois regular heating payment and LIHEAP cooling registry notes - #10730
Conversation
Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
PR Review: Add a national LIHEAP total, an Illinois regular heating payment and LIHEAP cooling registry notesHead reviewed: SummaryThe PR does what it says, and no result changes for any household that was covered before.
Two test gaps need closing before merge: the Michigan case passes whether or not the Home Heating Credit is in the list, and two list lines (California liquid fuel, and the choice of the Illinois variable) can be changed with no test failing. Everything else is a suggestion. Critical (must fix)None. Should address1. The Michigan case does not test the Michigan exclusion
Case 2 is named "a Michigan household gets nothing because the Home Heating Credit is not in the total". Its household (one adult aged 41, wages $24,000, gas bill $1,020) has a Home Heating Credit of $0, so the case would pass with the credit in the list:
Nothing else pins the exclusion.
2. Two list lines are pinned by no test, because the registry check sees one variable per state
The new check compares each state implementation's single
For comparison, these would be caught: deleting line 21 (Cases 3 and 5), deleting the wood line (Case 4), deleting the utility line or the line of any of the 48 single-variable jurisdictions (the registry check), and adding Fix.
Suggestions
Verified correctThe 52 list entriesAll 52 are
|
| # | Formula (entity) | Read | Read's entity and period | Same value |
|---|---|---|---|---|
| 1 | az_liheap_countable_unearned_income (Person) |
18 unearned sources | ssi Person MONTH; 17 Person YEAR |
yes |
| 2 | co_leap_countable_income_person (Person) |
ssi |
Person MONTH | yes |
| 3 | ct_ceap_categorically_eligible (SPMUnit) |
ssi, ct_ssp_person through members; ct_ssp |
Person MONTH; SPMUnit MONTH | yes |
| 4 | fl_liheap_categorically_eligible (SPMUnit) |
add of snap, tanf, ssi |
SPMUnit MONTH; SPMUnit YEAR; Person MONTH | yes |
| 5 | fl_liheap_countable_income (SPMUnit) |
18 unearned sources through members; add of tanf |
ssi MONTH, rest YEAR; tanf YEAR (no-op) |
yes |
| 6 | hi_liheap_eligible (SPMUnit) |
ssi through members |
Person MONTH | yes |
| 7 | hi_liheap_points (SPMUnit) |
ssi through members |
Person MONTH | yes |
| 8 | ia_liheap_countable_unearned_income (Person) |
16 unearned sources | ssi, ia_ssa MONTH; 14 YEAR |
yes |
| 9 | ia_liheap_fixed_income_only (SPMUnit) |
earned plus non-fixed unearned sources | all 17 Person YEAR | yes (option was a no-op) |
| 10 | id_liheap_income_eligible (SPMUnit) |
snap over the October-September year; ssi through members |
SPMUnit MONTH; Person MONTH | yes, same 12 months |
| 11 | la_liheap_countable_income (SPMUnit) |
ssi through members |
Person MONTH | yes |
| 12 | mn_eap_countable_income (SPMUnit) |
11 unearned sources | ssi MONTH; 10 YEAR |
yes |
| 13 | mt_liheap_categorical_eligibility (SPMUnit) |
snap |
SPMUnit MONTH | yes |
| 14 | mt_liheap_countable_income (SPMUnit) |
5 earned, 19 unearned sources | ssi, mt_ssp MONTH; rest YEAR |
yes |
| 15 | mt_liheap_benefit_income (SPMUnit) |
mt_tanf_payment_standard |
SPMUnit MONTH | yes |
| 16 | nm_liheap_countable_income (SPMUnit) |
21 unearned sources | ssi, nm_ssi_state_supplement MONTH; rest YEAR |
yes |
| 17 | nv_liheap_countable_income (SPMUnit) |
23 unearned sources | ssi, nv_oss MONTH; rest YEAR |
yes |
| 18 | oh_liheap_countable_income (SPMUnit) |
5 earned, 20 unearned sources | ssi MONTH; rest YEAR |
yes |
| 19 | ok_liheap_countable_income (Person) |
add of each of 20 unearned sources |
ssi MONTH; rest YEAR |
yes |
| 20 | ok_liheap_net_income (SPMUnit) |
ok_ccs_copay |
SPMUnit MONTH | yes |
| 21 | pa_liheap_supplement (SPMUnit) |
ssi through members |
Person MONTH | yes |
| 22 | sd_liheap_countable_income (SPMUnit) |
17 unearned sources | ssi MONTH; rest YEAR |
yes |
| 23 | tn_liheap_countable_income (SPMUnit) |
14 unearned sources | ssi MONTH; rest YEAR |
yes |
| 24 | va_eap_countable_income (SPMUnit) |
21 unearned sources | ssi, va_ag MONTH; rest YEAR |
yes |
| 25 | wi_wheap_categorically_eligible (SPMUnit) |
snap |
SPMUnit MONTH | yes |
| 26 | wi_wheap_countable_income (SPMUnit) |
16 unearned sources | ssi, wi_ssp_regular, wi_cts MONTH; rest YEAR |
yes |
For a YEAR variable read over its own year, the option summed one period, so it was already a no-op. Person-level reads through spm_unit.members and through add take the same path as direct reads.
DC and Illinois floors
dc_liheap_income_levelreturns 1 to 10 for any DC unit (income at or below the first step, including negative income, is level 1). It is 0 only outside DC.il_liheap_income_bracketfloors the poverty ratio at 0 and its first bracket starts at 0, so an Illinois unit is in bracket 1 to 4. It is 0 only outside Illinois.max_(level, 1)therefore changes no resident's lookup. It is the same line asmd_meap(md_meap_level) andks_liheap_matrix_amount(ks_liheap_income_band,ks_liheap_household_size_group).- Case 5 exercises both floors: its expected
dc_liheap_income_level: [0, 2, 0]andil_liheap_income_bracket: [0, 0, 3]show the level-0 rows that the matrices have no key for.
Registry notes against the plans and the code
Item 1.1 of the FY2026 plan read for all 33 states and Michigan; FY2027 plan read for CT, IL, IN, KS, MA, MI, MN, MO, MS, ND, NJ, NM, NY, OH, PA, RI, SD, TN, TX, UT and WV.
- Regular benefit also covers cooling (7).
- MS, NM, TN, TX, UT: item 1.1 gives cooling dates in both years. In each state's code a home with no heating and an electric bill is paid (MS $600, NM $280, TN $305, TX $1,200, UT $605 in the run), which matches the note. The Utah note now agrees with
ut_heat_eligible. - MO: no cooling component, and the plan says "payments made toward electric accounts may be utilized for cooling costs October through May" (FY2026 and FY2027, p. 9). The note says the same, and the code pays the electric amount only to a home that heats.
- MN: no cooling component; Primary Heat is based on all energy costs, electricity included, and is "first distributed to the household's electric vendor" (FY2026, p. 24). The code counts the electric bill and requires a heating type, which fits the note.
- MS, NM, TN, TX, UT: item 1.1 gives cooling dates in both years. In each state's code a home with no heating and an electric bill is paid (MS $600, NM $280, TN $305, TX $1,200, UT $605 in the run), which matches the note. The Utah note now agrees with
- Crisis, equipment or weatherization only (16). No cooling dates in item 1.1 for IA, ID, IL, KS, MD, MT, NC, NH, OH, PA, WA, WI, WY. ND, NY and WV list a cooling component that pays no bill:
- ND: "NOT for payment of electric bills" (p. 14); the reserved direct payment is on p. 12.
- NY: "NYS does not provide a cash Cooling benefit" (p. 12).
- IL: "Illinois will not administer a separate Cooling assistance program" (p. 4, both years).
- KS: "Kansas does not provide cooling assistance" (FY2027, p. 4).
- WV: see suggestion 6.
- No cooling assistance (9). No cooling dates, and no cooling payment or equipment program, found for AK, CO, CT, IN, MA, ME, RI, SD, VT. AK: "does not operate a Cooling Assistance component" (p. 11). VT: the same (p. 21). RI: "not planning to offer a cooling component in FFY 2026" (p. 19) and no funds expected in FFY2027 (p. 4).
- NJ. "Depending on availability of funds, cooling is a medically necessary program benefit" (FY2026, p. 11; same in FY2027).
- MI. Heating through the Home Heating Credit (p. 4); weatherization covers "Cooling system repair and replacement" (p. 19); year-round crisis pays energy bills, with the cooling-equipment boxes in item 4.15 unchecked (p. 16, viewed as an image).
The coverage line keeps every state on main and adds MI. The count of 33 rewritten notes and the three groups match the body.
Tests (hand-checked from the tables on main; Illinois cells also from the FY2026 matrix PDF)
2026 guideline: $15,960 plus $5,680 per extra person.
liheapCase 1, Texas: 18,720 / 15,960 = 117%, above 75%, cap $1,200; min(1,200, 1,980 + 0) = 1,200.liheap1,200.- Case 2, Michigan: no Michigan entry in the list, 0 (see Should 1).
- Case 3, Illinois: guideline 21,640; 25,740 / 21,640 = 119%, bracket 3; all-electric, two people 425; min(425, 1,800) = 425; crisis 1,500;
il_liheap1,925; regular andliheap425. - Case 4, California: wood min(850, 1,000) = 850; utility 0 because another component pays; liquid 0;
liheap850. - Case 5: Texas 1,200. DC: 9,334 is in the second $5,000 step, level 2; multi-family electricity, one person 529; min(529, 1,320) = 529. Illinois 425.
liheap[1,200, 529, 425]. - Illinois Case 1: guideline 27,320; 31,200 / 27,320 = 114%, bracket 3; natural gas, three people 546; min(546, 1,080); + 1,500 = 2,046; regular 546.
- Illinois Case 2: 31,200 ≤ 2 × 15,960 = 31,920, income eligible; rent 8,400 ≤ 9,360, so not eligible; 31,200 / 15,960 = 195%, bracket 4; cash, one person 310; regular 0.
No existing test expectation changed.
What the new code-health checks do
- Adding the list to
AGGREGATE_LISTScatches: a member that is not a variable; a member with no state gate in itsdefined_forchain; a member dropped between year blocks. - The new registry check catches: a registered dollar variable missing from the list, so a deleted line for any of 49 jurisdictions (48 states and DC), or a new state added to the registry but not the list.
- They miss: the items in Should 1 and 2 and suggestion 7. The Illinois and Michigan exceptions are exact names, which is narrow enough, but they are encoded as a skip only.
Other
- Changelog:
liheap-aggregate.added.mdandliheap-aggregate.fixed.md, both sensible. ma_liheap: onlyunit = USDadded.- Parameter description follows the template; reference is 42 U.S.C. 8624(b)(1)(A).
- Not checked: the DC $529 cell against DOEE's own matrix file (taken from the parameter on main); the microdata run described in the body; FY2027 plans for the 13 states not listed above.
Axiom line assessment
axiom: n/a is valid.
liheapis a sum over existing state rules.il_liheap_regular_heatingexposes a computationil_liheapalready makes (base payment under the same eligibility gate). It encodes no new rule, parameter or eligibility test, so it needs no rulespec-us issue of its own. I found no existing Illinois LIHEAP issue in rulespec-us; that gap predates this PR.- The DC and Illinois floors and the
options=[ADD]removal change no result. - The registry notes are documentation.
CI status
All 36 checks pass on run 43146746119, which ran at the current head 6bee540633. The PR's own tests ran green there: liheap.yaml (5 passed), il_liheap_regular_heating.yaml (2 passed) and test_aggregate_list_integrity.py (including the new registry check). CI cannot show the microsimulation path; that rests on the core source and the mixed-state run above.
Branch status
- 2 commits behind main, 6 ahead. The merge with main is clean.
- One file changed on both sides:
hi_liheap_points.py(main reworded the disability comment; this PR changed thessiread). The merged file is correct, and the merged tree has nooptions=[ADD]. - No main-side guard is affected: the PR adds no conflict-sounding comment, and touches no income list.
- Siblings, each merged with this head (all clean):
- Pay California's regular HEAP utility benefit to cooling-only households #10732 CA:
programs.yamlonly. - Pay Hawaii's LIHEAP Energy Credit on electric (cooling) accounts #10734 HI:
programs.yamlandhi_liheap_eligible.py; the merged file keeps the plainssiread. - Pay Oregon's LIHEAP standard payment to cooling-only households #10736 OR:
programs.yamlonly. - Pay the Nevada LIHEAP Fixed Annual Credit to cooling-only households, assuming an energy account #10738 NV:
programs.yamlonly. - Pay the Florida LIHEAP Home Energy benefit to cooling-only households #10740 FL:
programs.yamlonly. - Pay the DC LIHEAP Regular benefit to cooling-only households #10742 DC:
programs.yamlanddc_liheap_payment.py; the merged formula keeps the level floor. - Add Delaware LIHEAP summer cooling electric benefit eligibility #10762 DE:
programs.yamlonly. It adds a registry entry whose variable is a flag, which the new check skips by design.
- Pay California's regular HEAP utility benefit to cooling-only households #10732 CA:
- None of the seven adds a new dollar variable, so none needs a line in
regular_payments.yaml.
Verdict: REQUEST_CHANGES
DTrim99
left a comment
There was a problem hiding this comment.
Requesting two changes, both test gaps in the new list:
- The Michigan case passes whether or not
mi_home_heating_creditis in the list, because its household's credit is $0, and the code-health check only skips the name; it does not fail if the name is added. Lower the wages to $9,000 and assert the exclusion. - Two list lines are pinned by no test:
ca_liheap_covered_liquid_heatingcan be deleted, and the Illinois line can be swapped foril_liheap_base_payment, with every test still passing by my reading. A mapping in the registry check plus two rows closes it.
Details are in Should Address 1-2 in the report above. Everything else holds: all 52 entries are the state's regular payment on the right entity and period, the 30 options=[ADD] reads return the same annual value without the option, the DC and Illinois floors change no resident's result, and no rewritten registry note contradicts its plan or its state's code. On the open question: yes, add parameter_prefix: gov.hhs.liheap. The eight suggestions are optional. CI is green at 6bee540633.
…ogram prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, David. Both changes are in
Suggestions taken: |
PR Review (round 2): Add a national LIHEAP total, an Illinois regular heating payment and LIHEAP cooling registry notesHead reviewed: SummaryBoth round-1 findings are fixed, and each fix is pinned by a test that fails without it.
CI is green at the new head (37 checks), and the PR's own test files ran and passed there. Two wording suggestions are new; neither blocks. How each claim below was checked is marked: CI (the run at this head), hand (arithmetic from the parameters at the head and the cited form), reading (the code or tests), or stub run (described under "The rewritten registry check"). Prior findings
New findingsCritical (must fix)None. Should addressNone. Suggestions
VerifiedMichigan Case 2 (hand, form and CI)TY2025 MI-1040CR-7, lines 36 to 45, read from the form and its instruction book:
The 0.6 is the line 45 funding percentage ( The household qualifies for both methods at the head:
Moving the case to 2025 breaks nothing: the list parameter starts 2023-01-01, every Michigan parameter used has a 2025 value, and no other state's formula runs for a Michigan-only household. The case passes at the head (CI). The 2025 period also explains the change from the $181.61 I quoted in round 1: that figure used the 2026 allowance, which is an uprating projection. Madera County propane Case 6 (hand and CI)Inputs match Case 5 of
Illinois Case 2 (hand and CI)Unchanged inputs. Rent of 8,400 does not exceed 30% of 31,200 (9,360), so The rewritten registry checkRead whole. It builds the set of float registry variables for the LIHEAP entry, replaces each by its stand-ins from It builds no simulation. It reads Stub run. I executed the head's test function against the head's
What it still does not check is suggestion 7 from round 1, and a mapping key that is no longer a registry variable is not reported as stale. No formula changedFiles the fix commit touches outside tests and the registry:
West Virginia noteThe note now reads: "West Virginia's plans reserve a regular cooling payment of up to $2,000 if funds remain, which is not modeled; Emergency Cooling crisis payments, unit repair or replacement, weatherization and the utility discount are out of scope." I re-opened both plans. FY2026, item 3.6, p. 14: "WV LIHEAP will have a cooling if funds remain to do so, up to the limit of $2000." FY2027, p. 16: "Max benefit for cooling LIHEAP is up to $2000." The note matches both, and the body's registry section now says the same. PR bodyThe body matches the head: 8 cases in 2 files, the 2025 Michigan case at $173.40, the Madera case at $516, the stand-in check, the Axiom
CIAll 37 checks pass on run 43266397351, which ran at the current head
The author did not run tests locally, so CI is the only full run. No check is pending. Branch
Verdict: APPROVE |
DTrim99
left a comment
There was a problem hiding this comment.
Approving. Both round-1 findings are fixed, and each fix is pinned by a test that fails without it:
- Michigan. Case 2 now has a household whose Home Heating Credit is $173.40 (checked line by line against the TY2025 MI-1040CR-7) and asserts
liheap: 0. The registry check also fails ifmi_home_heating_creditoril_liheapis in the list. - California and Illinois list lines. The stand-in mapping, the Madera County propane case ($516) and
liheap: 0on Illinois Case 2 pin all three.
No formula changed in the fix commit. Two optional wording suggestions are in the report above; the Case 6 comment names its two amounts the wrong way round. The options=[ADD] guard stays an open option while policyengine-core#647 is unmerged. CI is green at 4625f4e59a.
Adds a national
liheaptotal that sums each state's regular LIHEAP payment, an Illinois regular heating payment without crisis assistance, a Michigan Home Heating Credit registry entry, and a cooling note for every LIHEAP registry entry that needs no code change. It also fixes the state LIHEAP formulas that raised errors when calculated over microdata.Fixes #10729
What and why
National total.
liheap(SPMUnit, YEAR, USD) adds the variables in a new list parameter,gov.hhs.liheap.regular_payments. The list has 52 entries for 49 states and DC. Each entry is the variable the state's registry entry names, with three exceptions:il_liheap_regular_heatingreplacesil_liheap, which also counts crisis assistance.ca_liheap_utility_heating,ca_liheap_covered_liquid_heating,ca_liheap_wood_heating). They are exclusive by eligibility, so their sum is California's single regular payment.The list is dated 2023-01-01, like
gov.household.household_state_benefits. Each state variable keeps its own effective dates, so the list date changes no result. A later state PR, for example a state cooling payment, adds one line to this list.Massachusetts unit.
ma_liheapdeclared nounit; this addsunit = USD, the only change to that file.Illinois.
il_liheap_regular_heatingisil_liheap_base_paymentfor households that passil_liheap_eligible. The eligibility gate matters: the base payment alone is positive for a heat-in-rent renter who fails the rent test.il_liheapkeeps its current meaning, base plus crisis.Microsimulation fixes.
liheapis the first variable that evaluates every state's LIHEAP formula over a mixed-state population. Two patterns already on main raised errors there, although each state's own tests pass:options=[ADD]on an entity call, in 26 formula files across 19 states. In a microsimulation, Core'sMicrosimulation.calculate_addrejects thedecode_enumskeyword that an entity call passes. The option was redundant: a plain read already sums a monthly variable over the year through the same Core function, so no result changes. The comments that described the option now say that a plain read sums a monthly variable. Fix formula reads with ADD or DIVIDE in a Microsimulation policyengine-core#647 fixes the cause in Core; removing the option here letsliheaprun on today's Core.dc_liheap_payment,il_liheap_base_payment). A payment formula runs for every household once any household in its state qualifies, and a household elsewhere has income level 0, which neither matrix has a row for. Both formulas now floor the level at 1, as Maryland and Kansas already do. The floor changes no in-state result.Registry (
programs.yaml, LIHEAP entry).variable: liheapandparameter_prefix: gov.hhs.liheapat the program level and MI to the coverage line.mi_home_heating_credit(parametersgov.states.mi.tax.income.credits.home_heating), noting that the credit is not in theliheaptotal and that cooling help comes only through crisis and weatherization.Not counted in net income.
liheapis not added tohousehold_benefits, state benefits or SPM resources in this PR. A follow-up PR will:liheapinhousehold_benefits, ashousing_assistanceis, while SPM benefits keepspm_unit_energy_subsidy, the survey-reported energy assistance, so neither total counts both;Test plan
Tests were not run locally. CI passed at
6bee540633; the commit since adds tests and changes comments and registry text.liheap:il_liheap_regular_heating:il_liheapis $2,046)liheapregular_payments.yamladded toAGGREGATE_LISTSintest_aggregate_list_integrity.py, which checks that every member exists, is limited to its own state, and is not dropped between year blocks.il_liheap; California's three components), must be in the list, andil_liheapandmi_home_heating_creditmust not be.liheapcalculated over the default microdata for 2026 (59,900 SPM units), on this branch before its latest merge of main: all 52 list entries and the total evaluate. Every amount is $0, because the microdata has no heating type, fuel bill or cooling-expense input.make format(ruff)changelog.d/axiom: n/a: no policy rule changes; this PR sums existing state payments, edits registry notes, and fixes formulas that raised errors over microdata without changing a result
🤖 Generated with Claude Code