Repository navigation
Conversation
One added changelog fragment for the new program and a one- or two-sentence programs.yaml note; limitations stay in code comments and the PR body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # policyengine_us/programs.yaml
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #10342 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 4 7 +3
Lines 76 119 +43
Branches 2 2
=========================================
+ Hits 76 119 +43
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
PR Review: Add North Dakota LIHEAP regular heating assistancePR #10342 (author: hua7450), head
The PR has no reviews and no comments other than Codecov. It touches no partner test file. Path prefixes:
Sources read for this review:
SummaryWhat is right. The tables and mechanics are encoded carefully:
There is one critical finding:
There are three should-address items:
There are also six suggestions:
Status.
Critical (must fix)C1. The 60% column exceeds the federal ceiling of 60% of HHS's state median income at sizes 2-9, 11 and 12, and the head follows the table over the statute
Should addressS1. Medicare premiums are deducted only when reported, although manual 415-25-05-05-05 allows Medicare premiums and
|
| Case | Arithmetic | Expected |
|---|---|---|
nd_liheap 1 |
20,000 × 0.73 = 14,600; 13,519-20,274 → 95%; 1,000 × 0.95 | 950 ✓ |
nd_liheap 3 |
33,787 > 33,786 → 45% | 450 ✓ |
nd_liheap 5 |
40,531 > 40,530 → 0 | 0 ✓ |
nd_liheap 13 |
2,200 × 0.95 / 12 = 174.17 → 174; × 12 | 2,088 ✓ |
nd_liheap 16 |
2,200 × 0.45 / 12 = 82.50 → 83 (table $83); × 12 | 996 ✓ |
nd_liheap 17 |
1,750 / 12 = 145.83 → 146; 1,752 capped | 1,750 ✓ |
nd_liheap 31 |
700 × 0.45 / 12 = 26.25 → 26; × 12 | 312 ✓ |
nd_liheap 33 |
34,000 − 1,200 − 2,400 − 600 = 29,800 → 65% | 650 ✓ |
nd_liheap 34 |
37,000 − 1,200 − 600 = 35,200 → 45% | 450 ✓ |
nd_liheap 37 |
unit 2: 9,600 + 3,600 = 13,200 ≤ 17,670 → 100% | 3,000 ✓ |
nd_liheap 38 |
20,440 − 1,200 = 19,240 (95%); 18,040 (95%); 20,440 (85%) | 2,850 / 2,850 / 2,550 ✓ |
nd_liheap 39 |
floor 1.1 × (15,650 + 20 × 5,500) = 138,215; 138,000 and 138,214.99 → 45%; 138,215 → 0 | 1,350 / 1,350 / 0 / 0 ✓ |
nd_liheap 42 |
0.52 + 5 × 0.16 + 23 × 0.03 = 2.01; 129,911 × 2.01 = 261,121.11; 40% 104,448.44 < 130,000 ≤ 50% 130,560.56 → 65% | 1,950 ✓ |
| countable 13 | 25,000 + 8,000 × 0.73 | 30,840 ✓ |
| countable 15 | 14,600 − 1,000 − 600 − 2,000 | 11,000 ✓ |
| household size 1 | size 1; 10,000 + 10,000 × 0.73 = 17,300 → 95% | 950 ✓ |
The share-test Case 1 also follows the workbook at all 280 households. Sizes 21-28 at the dollar after the 60% limit get 0.45 through the floor (for example 137,971 < 138,215).
Axiom line assessment
axiom: TheAxiomFoundation/rulespec-us#1902 queued.
- Valid. The issue is OPEN and labelled
pe-parity(updated 2026-10-24). It is dispatch-ready:- module paths;
- corpus manifests and the missing-source blocker;
- verbatim manual, workbook and statute text;
- required outputs by variable;
- companion tests whose expected values come from those sources, not from PolicyEngine output.
- Matches the head. It describes head
62c5fa449bwith 64 cases,total_unemployment_compensationandmilitary_retirement_income. - After the fixes, refresh:
- interpretation 5 and companion tests 2 and 4 (C1's ceiling);
- interpretation 11 and companion test 12(f) (S1);
- interpretation 15 (S2);
- the companion tests for the new cases (S3).
CI status
gh pr checks 10342 at head 62c5fa449b: 34 pass and 3 skipping (the umbrella jobs), with 0 failures and 0 pending. The run is not affected by either known main-caused failure.
Branch status
- Position: 8 commits ahead of
mainand 59 behind. - Merge:
git merge-tree --write-tree PolicyEngine/main <head>reports one conflict, inpolicyengine_us/programs.yaml. It covers the LIHEAP coverage line (mainadded AZ, IA and VA) and the state-implementation block beside VA (Add Virginia EAP Fuel Assistance (LIHEAP regular heating) #10303). That is a sibling conflict, so it is a branch note only.source_conflicts/candidates.yamlmerges cleanly. - Main-side changes: none of the changes on
mainsince the merge base (Add composable Social Security benefit levers #10400, Uprate poverty guidelines over the 9902(2) interval and fix the Trustees wage base #10453, Net spouses' self-employment losses in state EITC helper earned income (IL, CO, DC, IN) #9820 and others) touch the inputs this PR reads.
Verdict: REQUEST_CHANGES
DTrim99
left a comment
There was a problem hiding this comment.
Requesting changes: 1 critical (the 60% income limits exceed the federal ceiling of 60% of HHS's state median income, 42 USC 8624(b)(2)(B), by $2-$12 at sizes 2-9, 11 and 12), 3 should. Full report in the comment above.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # policyengine_us/programs.yaml
|
Thanks for the review, David. The fixes are in 14a5193, and 1f953ba merges current main.
The PR body and TheAxiomFoundation/rulespec-us#1902 are updated for 1f953ba. I did not run the tests locally, so CI will check them. |
PR Review (round 2): Add North Dakota LIHEAP regular heating assistancePR #10342 (author: hua7450), head
The PR still touches no partner test file. Path prefixes:
SummaryAll four blocking findings are fixed, and a test would fail without each fix:
The suggestions. Five of the six were adopted or documented, and the author declined G2 (UNSPECIFIED) with a reason I accept. The merge. The hand-resolved The rulespec-us issue. rulespec-us#1902 has been updated to describe the new head. One new should-address item:
Four new suggestions:
Status.
Prior findings
New findingsCriticalNone. Should addressN1. The new payment selector's public-housing condition is not pinned by any test
Suggestions
VerifiedHand-checked expectations. Every new or changed expectation is hand-checked. The 2026 guideline, Medicare and SMI figures are those in the cases' comments and on
Unchanged behaviour. The other share households keep their round-1 values:
Merge resolution. I checked the one hand-resolved block in
Guards on the merged tree (
Other checks.
Axiom
CI
Branch
Verdict: REQUEST_CHANGES |
DTrim99
left a comment
There was a problem hiding this comment.
Requesting changes, round 2: 0 critical, 1 should. The critical and all three shoulds from round 1 are fixed and pinned. One new should: the public-housing condition in the new payment selector (nd_liheap.py) can be deleted without any test failing; add a public-housing heat-in-rent household with its own electric bill to Case 46. Full report in the comment above.
Adds North Dakota's LIHEAP regular heating benefit for FY2026. The model counts citizens and qualified noncitizens for household size and counts all members' income less a 27% earned-income deduction, reported medical, support and child care costs, and each member's computed out-of-pocket Medicare Part A and Part B premiums. It places the household in one of five bands from the published FY2026 income table (20%, 30%, 40%, 50% and 60% of state median income), with every band capped at the federal maximum of 42 U.S.C. 8624(b)(2)(B), and pays 100%, 95%, 85%, 65% or 45% of the annual bill for the primary heating fuel. Unsubsidized renters whose heat is included in rent receive a monthly amount by fuel, up to a yearly cap of $700 to $2,200; subsidized tenants whose heat is included in rent receive the share of an electric bill in their own name. In FY2026, a 40-year-old living alone with $20,000 of wages and a $1,000 natural gas bill receives $950: $20,000 x (1 - 0.27) = $14,600 of countable income, which is above the one-person 20% limit of $13,518 and at or below the 30% limit of $20,274, so the share is 95%, and $1,000 x 0.95 = $950.
Fixes #10336
Regulatory authority
Eligibility
defined_for = StateCode.NDnd_liheap_household_sizeaddsis_citizen_or_legal_immigrant; a household with no counted member is ineligiblend_liheap_sharelooks up inclusive upper limits inincome_limitsby household size and band; above 28 members it applies the 20% to 60% band rates to the size-adjusted state median income from the sharedsmihelper. It then caps every band's limit at the federal maximum: the greater of 60% of HHS's size-adjusted state median income (liheap_smi_limit; the FY2026 four-person median is $129,911) and 150% of the poverty guideline with a one-year lag (new federal parametergov.hhs.liheap.fpg_limit, 1.5). The table's 60% limits for 2 to 9, 11 and 12 members exceed HHS's amounts by $2 to $12, so the cap lowers them to the Attachment 4 figures (four people: $77,958 to $77,946). Size 1 ($40,530 against $40,531), size 10 (equal) and sizes 13 and up (below 150% of the guideline, $122,475 at 13) keep the table.gov.hhs.liheap.fpg_floor. Within the published table this reaches households of 21 to 28 members, whose 60% limits fall below the floor; a 21-person household's floor is 1.1 x ($15,650 + 20 x $5,500) = $138,215 against a table limit of $137,970.heating_expense > 0for the household'sheating_type, orheat_expense_included_in_rentreceives_housing_assistanceor the household'sis_in_public_housing. A subsidized household with heat in rent is eligible only when itspre_subsidy_electricity_expenseis positive, and it is paid the share of that bill (see Benefit)heating_typeNONE is ineligible; UNSPECIFIED has no bill inheating_expenseand no renter cap, so it pays nothing, including on a subsidized heat-in-rent household's own electric bill; callers must sendheating_type(#9754)Countable income
military_basic_pay), self-employment (including SSTB), farm operations and partnership income, each floored at zero so that a business loss does not offset other incomemilitary_retirement_income), retirement distributions, general assistance, railroad benefits, veterans benefits, disability benefits, survivor benefits, strike benefits, child support and alimony received, rental and farm rental income, S corporation income and estate income, each floored at zero. TANF received (tanf) counts once per household. Investment interest and ordinary dividends are not counted.financial_assistancecounts when it reaches $360 a yearhealth_insurance_premiums) when positive; otherwise reported premiums other than Part B, floored at zero, plus each member's computed out-of-pocketmedicare_part_a_premiumandmedicare_part_b_premium. Those premiums are zero for a member who is not enrolled, has premium-free Part A or has the premium paid by a Medicare Savings Program; that last condition stands in for the manual's bar on Part A and B premiums of QMB, SLMB, QI-1 and Buy-In members. Also deducted: pretax premiums, other medical expenses, child support paid, alimony paid and child care expenses. The medical deduction has no age or disability condition. Countable income is floored at zero.Benefit
heating_expensefor the primaryheating_type, with no dollar cap. Electric heat uses the same share on the pre-subsidy electricity bill; the 75% electric adjustment in 415-20-05-05-05 was repealed June 1, 2025 and does not apply.pre_subsidy_electricity_expense), with no dollar cap and nothing for the heat in its rent. A 40-year-old with $15,000 of pension income and a $1,200 electric bill receives $1,140: $1,200 x 0.95.heating_typevalues take the $700 cap because 415-30-15-01 codes every fuel other than fuel oil, propane, electricity and natural gas, such as kerosene, wood and coal, as "other". A single renter with $15,000 of pension income and oil heat receives $2,088: $2,200 x 0.95 / 12 = $174.17, rounded to $174, and 12 x $174 = $2,088. Propane at the 100% share gives $146 a month, or $1,752, capped at $1,750.Years covered
The registry entry records
verified_years: "2026". Other years reuse the FY2026 income table, shares and renter caps through parameter backfilling and carry-forward, with the federal floor and maximum following the lagged guideline and that year's state median income, and are unverified estimates. For model years 2015 to 2025 the backfilled values depart from the rules then in force: the 75% electric adjustment in 415-20-05-05-05 applied until June 1, 2025, and Manual Letter 3750 (October 1, 2023) describes an earlier benefit method, while the model pays electric heat at the full share and applies the FY2026 method in every year.Not modeled and source conflicts
source_conflicts/candidates.yamllists this asus-nd:liheap-income-floor-vs-smi-limit.source_conflicts/candidates.yamllists this asus-nd:liheap-table-above-federal-ceiling.source_conflicts/candidates.yamllists this asus-nd:liheap-plan-income-share-design.source_conflicts/candidates.yamllists this asus-nd:liheap-renter-table-vs-subtraction-prose. The nearest-dollar, halves-up rounding reproduces all 20 published monthly amounts, but the manual does not state it.source_conflicts/candidates.yamllists this asus-nd:liheap-six-person-limit-workbook-vs-manual. Both figures exceed the $102,888 federal maximum, so the choice does not change results.source_conflicts/candidates.yamllists this asus-nd:liheap-child-earnings-exclusion.smihelper, capped at the federal maximum; North Dakota's rounding for those sizes is unverified.immigration_statusvalues are not represented.employment_incomemay already include it. Disability benefits are counted as unearned because the payer is not recorded, and rental income is counted as unearned.financial_assistanceis treated as recurring and unconditional. Nonrecurring lump sums, educational aid, royalties, tribal payments, recoupments and military allotments have no separate inputs. Manual 415-25-05-20-20 counts recurring gambling winnings, butgambling_winningsdoes not separate recurring from nonrecurring winnings, so the model does not count it.heating_type: a secondary fuel's bill can sit in its own expense input but is not paid, and incidental charges have no input. The nonresidential-usage caps in 415-20-05-05-15 ($4,300 fuel oil, $3,500 propane, $3,000 electricity, $1,100 natural gas and other) need facts the inputs lack.heating_typehas no bill and no renter cap, so it pays $0, including on a subsidized heat-in-rent household's own electric bill; callers must sendheating_type, and Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754 tracks its default.Test plan
policyengine_us/tests/policy/baseline/gov/states/nd/dhs/liheap/(nd_liheap.yaml48,nd_liheap_countable_income.yaml21,nd_liheap_household_size.yaml2,nd_liheap_share.yaml2); expected values are hand computed from the manual, the FY2026 income table, HHS's FY2026 state median income amounts and the CMS 2026 Medicare premiums. One share case checks all 140 published upper limits and the dollar after each; the ten printed 60% limits above the federal maximum (sizes 2 to 9, 11 and 12) expect 0.nd_liheap.yamlCase 43 pins the four-person federal maximum: $77,946 of pension income pays $1,350 and $77,950 pays $0. Case 35 deducts the computed Part B premium: $34,000 - $2,434.80 = $31,565.20, in the 65% band, so a $1,000 gas bill pays $650. Case 44 deducts nothing when a Medicare Savings Program pays the premium ($950), and Case 45 deducts a $3,732 Part A premium and the Part B premium from a $38,000 pension ($31,833.20, $650). Case 46 pays a subsidized heat-in-rent tenant 95% of a $1,200 electric bill, $1,140 (Case 48 pays $0 when that tenant'sheating_typeis UNSPECIFIED), and Case 47 pays an unsubsidized kerosene renter at the 95% share $660, under the $700 cap. Countable income Case 19 gives all 6 earned and 19 unearned sources distinct amounts ($16,060 + $16,850 = $32,910), Case 20 keeps a $3,000 rental loss from offsetting a $20,000 pension, and Case 21 pins the dependency and school conditions of the student earnings exclusion.nd_liheap.yamlCase 41 counts a $30,000 military survivor annuity less the $2,434.80 Part B premium of the 70-year-old recipient: $27,565.20, 65% of a $3,000 oil bill, $1,950. Case 42 puts a 29-person household on the state median income path: 2.01 x $129,911 = $261,121.11, so $130,000 of pension income falls between the 40% limit of $104,448.44 and the 50% limit of $130,560.56, and 65% of a $3,000 oil bill is $1,950. The review-fix cases were not run locally; CI runs the full suite.# Source conflict <jurisdiction>:<id>marker: not yet. The sixus-nd:liheap-*readings named under source conflicts are insource_conflicts/candidates.yamluntil they are registered in rulespec-us; this PR adds no marker.make formatchangelog.d/axiom: TheAxiomFoundation/rulespec-us#1902 queued
🤖 Generated with Claude Code