Skip to content

Add Washington LIHEAP regular heating assistance - #10345

Open
hua7450 wants to merge 12 commits into
mainfrom
wa-liheap-wave2b
Open

hua7450 wants to merge 12 commits into
mainfrom
wa-liheap-wave2b

Conversation

@hua7450

@hua7450 hua7450 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Adds Washington's LIHEAP regular heating benefit for FY2026. The model counts citizens and qualified noncitizens for household size and counts the income of every member, except the earnings of members under 18, after a 20% allowance on wages and 10% deductions on pensions, retirement distributions, military retirement income (including survivor annuities) and unemployment compensation. Social Security counts net of the Medicare Part B premium; workers' compensation, Refugee Cash Assistance and the state supplement to SSI count in full; and child support and alimony paid by members are deducted. It tests that income against 150% of the 2025 poverty guideline and applies the Commerce benefit calculation worksheet: monthly income and a household-size adjuster set a heat cost multiplier, which multiplies the reported annual heating cost. The result is held between $250 and $1,250 and then capped at that cost; a household whose heat is included in rent, with a known fuel and no reported cost, receives the $250 minimum. In FY2026, two adults earning $15,000 each with a $1,000 natural gas bill receive $630: $30,000 x 0.8 = $24,000 of countable income, under the $31,725 two-person limit; $24,000 / 12 / 1.36 = $1,470.59; $1,460.80 / ($3,648.10 - $1,470.59) = 0.67; 1.30 - 0.67 = 0.63; and $1,000 x 0.63 = $630.

Fixes #10339

Regulatory authority

Eligibility

Requirement Source How modeled
Washington residence State program defined_for = StateCode.WA
Household size counts U.S. citizens and qualified noncitizens; excluded members' income still counts Plan section 17.3 (page 37) requires citizen or qualified noncitizen status; the plan does not state a mixed-status counting rule. Commerce's weatherization Policy 1.1.2 (page 15) counts all members' income and only eligible members for household size wa_liheap_household_size adds is_citizen_or_legal_immigrant; a unit with no counted member is ineligible. Counting qualified members, keeping all members' income and applying no further proration is an approved modeling convention
Income at or below 150% of the poverty guideline Plan section 2.1 (page 8); Byrd Barr Place application page 1 wa_liheap_income_limit applies the 1.5 rate to the poverty guideline with a one-year lag (the 2025 guideline for FY2026). The limit is inclusive and uses exact annual amounts, not the agencies' rounded monthly displays
No categorical eligibility and no asset test Plan sections 1.4 (page 5) and 2.3 (page 8) No categorical route or asset condition; subsidized housing does not exclude a household
Heating responsibility: a heating bill or heat included in rent Byrd Barr Place application pages 1 and 2 heating_expense > 0 or heat_expense_included_in_rent
Heating fuel The worksheet multiplier does not vary by fuel heating_type NONE is ineligible and every other type qualifies. UNSPECIFIED has no bill in heating_expense and does not receive the heat-in-rent minimum, so it pays nothing; callers must send heating_type (#9754)

Countable income

Item Source How modeled
Members Plan section 1.9 (page 6); CACLMT FAQ wa_liheap_countable_income counts every SPM unit member, including members excluded from household size. Earnings of members under 18 are excluded; their other income counts.
Earned income Plan section 1.9 (pages 5 to 6); Byrd Barr Place application pages 1 and 13; Policy 1.1.2 (page 15); KCR worksheet employment_income less a 20% allowance. Net self-employment (including SSTB), farm operations and partnership or S corporation income each count floored at zero, with no further deduction.
Retirement and unemployment Plan section 1.9 (page 6); Policy 1.1.2 (page 15) Pension income, retirement distributions and military_retirement_income (military retirement pay and military survivor annuities) less 10%; total_unemployment_compensation less 10%
Social Security Plan section 1.9 (page 6), which marks the Social Security entry "Excluding MediCare deduction" social_security less the person's medicare_part_b_premium, floored at zero per person, so a premium larger than the benefit does not reduce other income. The premium is zero for a person not enrolled or whose premium a Medicare Savings Program pays. No retirement deduction applies.
Other unearned income Plan section 1.9 (page 6) Counted in full: SSI, railroad retirement, survivor benefits other than Social Security, general assistance, strike benefits, cash gifts (financial_assistance), rental and farm rental income, alimony, child support received, interest and ordinary dividends
Workers' compensation Plan section 1.9 has no workers' compensation row; Weatherization Manual Exhibit 1.3.1A (page 445) lists an L&I statement as income documentation; the CACLMT FAQ counts time loss for work-related injuries workers_compensation counted in full, with no deduction
TANF, State Family Assistance, Refugee Cash Assistance and the state supplement Plan sections 1.8 (gross income, page 5) and 1.9 (page 6); WAC 388-474-0012(1) makes the supplement state-funded cash assistance, and WAC 388-400-0030 pays Refugee Cash Assistance on the TANF payment standards Received TANF (tanf, which follows takes_up_tanf_if_eligible), wa_sfa and wa_rca are each added once per SPM unit, and wa_ssp is summed over members. No Washington LIHEAP source names Refugee Cash Assistance or the state supplement; both count as gross cash income, like TANF, State Family Assistance and SSI
Child support and alimony paid Weatherization Manual Exhibit 1.3.1A (page 445) lists "Child support received/paid", and Policy 1.1.1 (page 13) ties the manual to the LIHEAP income guidelines; Clark Public Utilities deducts child support and alimony paid; the CACLMT FAQ deducts child support paid Members' child_support_expense and alimony_expense are subtracted from the unit's countable income, which is floored at zero
Not counted Plan section 1.9 (page 6) VA benefits, insurance payments made directly to the insured (disability_benefits and life_insurance_benefits), one-time lump sums, savings and retirement account balances, tax refunds and other refundable credits

Benefit

  • Adjusted income (worksheet line a): annual countable income divided by 12 and by the printed household-size adjuster (1.00 for one person, 1.36 for two, up to 9.21 for 24), rounded to the cent.
  • Heat cost multiplier (worksheet lines b to d): 1.30 minus 1,460.80 / (3,648.10 - adjusted income), with the quotient rounded to two decimals and the multiplier floored at zero. Zero income gives 1.30 - 0.40 = 0.90; income at the one-person limit of $23,475 gives 1.30 - 0.86 = 0.44.
  • Award: the reported annual heating cost (heating_expense, the bill for the primary fuel) times the multiplier, rounded to whole dollars, then raised to the $250 minimum or lowered to the $1,250 maximum (plan section 2.6, page 10), then capped at the heating cost. Each rounding step rounds half up. At zero income, the $1,250 maximum applies from a $1,389 heating cost.
  • Heat included in rent with a known fuel and no reported cost: the $250 minimum, without the cost cap, as a lower bound. Plan section 9.1 (page 24) pays households whose heat is included in rent by check, and the worksheet's surrogate heat cost schedule is not published. A single adult with $12,000 of wages whose gas heat is included in the rent receives $250. A household that reports a cost keeps the worksheet path, and UNSPECIFIED pays $0.
  • The worksheet's printed example, $500 of monthly income for one person with a $400 annual heat cost, pays $336; a test case reproduces it.

Years covered

Model year Program year Guideline One-person limit
2026 FY2026, starting October 1, 2025 2025 $23,475

Income-limit cases for 2027 check the PY27 eligibility sheet, which applies the 2026 guideline ($23,940 for one person); they do not verify 2027 awards. The registry entry records verified_years: "2026". Years other than 2026 use parameter backfilling and are unverified estimates; for 2025, see the worksheet constants below.

Not modeled and source conflicts

  • Byrd Barr Place can assess one, three or twelve months of income (application page 1); the model uses annual amounts, averaged over twelve months.
  • Self-employment uses the existing net business inputs, floored at zero per source. The model does not apply the 50% standard deduction that agencies offer when receipts are missing (Byrd Barr Place application pages 2 and 13) and cannot apply the KCR worksheet's month-by-month loss floor.
  • Plan section 1.8 (page 5) selects gross income, and section 1.9 has no deduction field. The 20% wage allowance and the 10% retirement and unemployment deductions come from Policy 1.1.2 (page 15), which follows the LIHEAP income guidelines; the Byrd Barr Place application (page 1) also takes the 20% deduction on earned income taxed at payout, and Clark Public Utilities calculates wages at 80% of gross. The model applies them to gross amounts.
  • The plan and Policy 1.1.2 list no deduction for support paid. Weatherization Manual Exhibit 1.3.1A lists "Child support received/paid" among income documents; Clark Public Utilities deducts child support and alimony paid, and CACLMT deducts child support paid. No Washington source says paid support is not deducted, so the model deducts both. Alimony paid rests on the Clark page alone.
  • Plan section 1.9 has no workers' compensation row and leaves "Insurance payments made directly to the insured" unchecked. Exhibit 1.3.1A lists an L&I statement as income documentation and CACLMT counts time loss for work-related injuries, so the model counts workers_compensation in full. disability_benefits (employment-related disability benefits other than workers' compensation) and life_insurance_benefits stay excluded as insurance payments made directly to the insured. VA benefits stay excluded under the plan, although Exhibit 1.3.1A and Byrd Barr Place ask for VA documents.
  • Social Security counts net of the Medicare Part B premium the model computes, following the Medicare deduction marked on the plan's Social Security entry (section 1.9, page 6); other Medicare premiums are not deducted. The sources do not say whether the 10% retirement deduction covers Social Security, SSI, railroad retirement or survivor benefits other than military survivor annuities, so none applies to them. This choice can overstate countable income.
  • The plan also counts repayable loans, jury duty pay, royalties, structured legal settlements and foster care payments, which have no dedicated inputs; work-study and commission pay count only when reported as employment income. Annual inputs cannot separate every excluded subtype, such as a one-time lump-sum retirement distribution.
  • The FY2026 worksheet's constants (3,648.10, 1,460.80 and 1.30) and 24 adjusters are used as printed. The PDF's metadata names the "110 bak working copy 2025 EAP Constant Solver" workbook, created by Multi Service Center on 2025-12-22. Its embedded 150% monthly poverty table uses the 2024 guideline ($1,883 a month for one person), its constants give a 0.90 multiplier at zero income and 0.50 at $1,823 a month (150% of the 2023 guideline), and its adjusters are the 2024 guideline's size ratios (21 of 24 exactly; sizes 10, 17 and 24 print one cent lower). Whether Commerce recalibrated the constants for FY2026 is therefore unverified. The FY2025 matrix is a constant solver with different rounded constants (2,683.5, 506.7 and 1.09) and prints no adjusters or worksheet, so the model adds no FY2025 values: period 2025 uses the FY2026 constants, and 2025 results are unverified estimates. For example, $1,000 of adjusted monthly income and a $1,000 heating cost pays $750 under the FY2026 constants and $790 under the FY2025 constants. Two-decimal intermediate rounding and whole-dollar final rounding, with ties rounded up, reproduce the printed $336 example; the worksheet does not state a tie rule.
  • The plan sets a $250 minimum and a $1,250 maximum but does not say how the minimum applies when the heating cost is smaller. The model applies both bounds and then caps the award at the reported annual heating cost, an approved modeling choice, so a $100 heating cost pays $100. The cap does not apply to heat included in rent with no reported cost, which receives the $250 minimum.
  • Heat included in rent establishes eligibility. With a known fuel and no reported cost, the model pays the $250 minimum as a lower bound: the worksheet's surrogate heat cost schedule was not recovered, so the surrogate award, up to the $1,250 maximum, is unknown. If the schedule is recovered, it replaces the floor. UNSPECIFIED pays $0 because callers must send heating_type (Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754). The model also does not split baseload use, add secondary fuels, value self-supplied fuel or allocate a whole dwelling's cost.
  • Households larger than 24 keep income eligibility but receive $0, because the adjuster table stops at 24 and the model does not extrapolate it.
  • The SPM unit stands in for the household that shares heating costs. Prior receipt in the current season and application verification are not modeled.
  • The FY2027 draft plan changes several income categories (it checks combat-related VA benefits and insurance payments made directly to the insured); those changes are not adopted.
  • No reading in this PR sets a statute against another source, so it adds no # Source conflict marker. The plan-versus-agency choices are recorded as two candidates in source_conflicts/candidates.yaml: us-wa:liheap-plan-agency-income-items (the deductions, paid support, workers' compensation and VA benefits) and us-wa:liheap-minimum-benefit-cost-cap (the $250 minimum against the cost cap).
  • This PR models regular heating assistance only. Crisis assistance, cooling, weatherization and heating-equipment repair are out of scope, as is the $20.01 SNAP nominal payment.

Test plan

  • 5 YAML files with 125 cases under policyengine_us/tests/policy/baseline/gov/states/wa/commerce/liheap/: wa_liheap.yaml 71, wa_liheap_countable_income.yaml 26, wa_liheap_eligible.yaml 10, wa_liheap_household_size.yaml 4 and wa_liheap_income_limit.yaml 14. Expected values are hand computed from the income rules and the worksheet constants, and one case reproduces the worksheet's printed $336 example. Cases pin heat in rent with a known fuel and no bill ($250), the paid-support eligibility change ($460) and its zero floor, workers' compensation ($750), the state supplement ($740), Refugee Cash Assistance, and railroad and survivor benefits counted in full. CI runs the full suite.
  • YAML tests whose expected values come from an external source (statute, official form or worksheet, official calculator)
  • Source-conflict register entry and # Source conflict <jurisdiction>:<id> marker: not applicable; this PR adds no marker. It adds two candidates to source_conflicts/candidates.yaml.
  • make format
  • Changelog fragment in changelog.d/

axiom: TheAxiomFoundation/rulespec-us#1905 queued

🤖 Generated with Claude Code

hua7450 and others added 5 commits October 6, 2026 16:27
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>
hua7450 and others added 3 commits October 23, 2026 22:46
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

codecov Bot commented Oct 24, 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 (a722aae).
⚠️ Report is 702 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main    #10345   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         5    +1     
  Lines           76       111   +35     
  Branches         2         3    +1     
=========================================
+ Hits            76       111   +35     
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
hua7450 requested a review from DTrim99 October 24, 2026 03:15
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DTrim99

DTrim99 commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Add Washington LIHEAP regular heating assistance

PR #10345 (author: hua7450), head 329eb32148. This is a first review. The PR adds Washington's LIHEAP regular heating benefit (Department of Commerce, delivered by local agencies) for FY2026. It includes:

  • 16 parameters and 5 variables;
  • 5 test files (118 cases);
  • a programs.yaml entry (coverage line and state list);
  • a changelog fragment.

The only comment is codecov's. There are no reviews yet, and the PR touches no partner test file.

Path prefixes:

  • P/ = policyengine_us/parameters/gov/states/wa/commerce/liheap/
  • V/ = policyengine_us/variables/gov/states/wa/commerce/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/wa/commerce/liheap/

Sources read for this review:

Summary

What is right. The published FY2026 values and rules are encoded correctly:

There are no critical findings and five should-address items:

  • S1. Heat in rent pays $0. Households eligible through heat in rent get $0, although Washington pays them from a surrogate heat cost, with at least the $250 minimum.
  • S2. Paid support is not deducted. Child support and alimony paid are not deducted. Two Washington LIHEAP agencies deduct them, and Commerce's income checklist lists "Child support received/paid".
  • S3. Workers' compensation is left out. It is not counted and not documented. An agency counts "Time loss for work related injuries", and Commerce's checklist lists the L&I statement.
  • S4. Untested sources. railroad_benefits and survivor_benefits never take a positive value in any test.
  • S5. Descriptions. Three parameter descriptions run past the program name ("... Program benefit worksheet.").

There are also three suggestions:

  • G1: count wa_ssp and wa_rca (item 17).
  • G2: the FY2025 matrix uses different constants (backfill), and the FY2026 worksheet's vintage.
  • G3: record the plan-vs-agency choices in the backlog.

Status.

  • CI: 34 of 34 pass. All 118 Washington cases passed in states-shard-2.
  • Branch: 9 commits ahead of main (two of them merges) and 37 behind. It merges cleanly.
  • Siblings: this PR adds WA to the LIHEAP coverage line, so it conflicts with 15 open LIHEAP siblings in programs.yaml only (branch note).

Critical (must fix)

None.

Should address

S1. Households eligible through heat in rent receive $0, although Washington pays them from a surrogate heat cost, with at least the $250 minimum

  • Where:
    • V/wa_liheap_eligible.py:34 makes a household eligible through heat_expense_included_in_rent.
    • V/wa_liheap.py:54-57 multiplies heating_expense, which is 0 when heat is in the rent (or the fuel is UNSPECIFIED). The cost cap min_(..., expense) then turns the $250 minimum into $0.
    • T/wa_liheap.yaml:502 (Case 50) pins eligible and $0.
  • Sources:
    • The worksheet. It is titled "Actual and Surrogate Heat Cost Benefit Calculation Worksheet" (p. 1).
    • The statewide HIF (10/2024) records "*Primary Heat Source", "*Annual Heat Cost" and "Used Surrogate Data", with a "Heat with rent" box. See Byrd Barr p. 4 and CAP p. 2.
    • The heat-in-rent form. Byrd Barr's form (p. 10) asks the landlord whether "The dwelling's primary heat source comes from: Electricity / Gas".
    • The PY27 sheet, item 2: "Your household pays for residential home heating costs either directly to an energy vendor or indirectly through rent."
    • The plan. Item 2.3 answers No to differing policies for "Renters with utilities included in the rent", and item 2.5 checks "Fuel type" and "Dwelling type", the surrogate's inputs (pp. 8-9). Item 2.6 sets a "Minimum Benefit $250" (p. 10).
    • An agency's account. CACLMT says the grant rests on "housing type and 12 months previous heat usage".
  • Effect (hand-traced, 2026, a single adult aged 40 with $12,000 of wages, a renter whose gas heat is in the rent, no fuel bill):
    • Countable income is 9,600, under 23,475, so the household is eligible.
    • Head: $0.
    • Rule: 9,600 / 12 = 800.00; 3,648.10 − 800.00 = 2,848.10; 1,460.80 / 2,848.10 = 0.513 rounds to 0.51; the multiplier is 0.79. That multiplier applies to the surrogate cost, held to $250–$1,250. So the household gets at least $250, and $711 on a $900 surrogate cost.
    • The PR's own UNSPECIFIED case with heat in rent (main's documented value for a tenant who does not know the building's fuel) gives the same $0.
  • What the PR says. The body, the variable documentation and Axiom interpretation 11 call the $0 "an unsupported amount, not a finding of ineligibility". But wa_liheap is the program's whole regular benefit, so the model returns a wrong $0 for an eligible household in the claimed year. Merged siblings pay heat-in-rent households: Iowa (Add Iowa LIHEAP regular heating assistance #10292) pays the matrix amount, with a heat-in-rent factor and its $80 minimum, and Massachusetts groups heat in rent with the utility category.
  • Severity: should. This is a wrong result in a claimed year with existing inputs, which the wave rates should (Add New Mexico LIHEAP regular heating assistance #10431 S1, Add Rhode Island LIHEAP regular heating assistance #9972 S2).
  • Fix:
    • When a household is eligible with heat_expense_included_in_rent and heating_expense ≤ 0, pay p.minimum as a documented lower bound, without the cost cap: the cost is unknown, not zero.
    • A household that supplies a cost keeps the worksheet path (Case 48).
    • Re-pin Case 50, and update the body, the documentation and Axiom interpretation 11.
    • If the surrogate schedule is recovered later, replace the floor with it.

S2. Child support and alimony paid are not deducted, although two Washington LIHEAP agencies deduct them and Commerce's income checklist lists support paid

  • Where:
    • V/wa_liheap_countable_income.py:71-74 deducts nothing. The comment says the plan and the Commerce manual "list no deduction for child support paid".
    • T/wa_liheap_countable_income.yaml:146 (Case 12) pins $5,000 with $1,200 paid.
    • The body and Axiom interpretation 5 call this settled.
  • Sources:
    • Clark Public Utilities (Clark County's LIHEAP agency; page updated 2025-09-17 with the FY2026 limits): "If you pay child support or alimony, you may deduct those payments from your total monthly income." The same page says "Wages are calculated at 80 percent of gross."
    • CACLMT (Lewis, Mason and Thurston counties): "Child Support received in the household (conversely, if you PAY child support, it can be deducted)".
    • Commerce's checklist. Weatherization Manual Exhibit 1.3.1A, the "Income and Residence Verification Checklist" (page 445), lists "Child support received/paid" under Income Documentation. Policy 1.1.1 says the Weatherization Program "follows the ... LIHEAP income eligibility guidelines" (page 13).
  • Why the PR's reason does not hold:
    • The plan has no deduction field. Plan 1.9 lists countable income types only. It also omits the 20% and 10% deductions, which the PR applies.
    • Policy 1.1.2 does not list them either. Item 5.a says "Apply all current income exclusions: (1) For 150% FPL", naming only the three withheld at the higher thresholds (page 15). So the two documents' silence says nothing against the deduction.
    • The evidence is like the PR's own. The PR takes the 20% wage allowance from the same kind of agency evidence (Byrd Barr page 1). Clark corroborates both rules.
  • Effect (2026, a single adult aged 40 with $30,000 of wages who pays $1,200 a year of child support, and a $1,000 gas bill):
    • Head: 24,000 > 23,475, so $0.
    • With the deduction: 22,800 is eligible. 1,900.00; 1,748.10; 0.836 rounds to 0.84; the multiplier is 0.46, so $460.
  • Severity: should. The agency sources agree and none says otherwise, yet the PR follows silence over them. The wave rates an income-definition error with a hand example should (Add Missouri LIHEAP Energy Assistance #10438 S3).
  • Fix:
    • Subtract child_support_expense and alimony_expense of the unit's members, floored so countable income stays at or above zero.
    • Re-pin Case 12, and add an eligibility-flip case like the one above.
    • Update the body, the comment and Axiom interpretation 5.

S3. Workers' compensation is neither counted nor mentioned, although an agency counts L&I time-loss and Commerce's income checklist lists it

  • Where: no list in P/income/ names workers_compensation. The body's "Not counted" row, the comments and the Axiom issue never mention it.
  • Sources:
    • CACLMT lists "Time loss for work related injuries" among income, beside "Annuity, Pension, Retirement or Survivors benefits".
    • Commerce's checklist. Weatherization Manual Exhibit 1.3.1A (page 445) lists "L & I statement" among the income documents.
    • Byrd Barr's packet lists "L&I, Workers' Compensation" among gross income sources, though only on its utility (PSE HELP) form.
    • The plan has no workers' compensation row. Its unchecked "Insurance payments made directly to the insured" (p. 6) could be read to cover it, but the PR does not make that argument. The draft FFY2027 plan checks that box (page 6).
    • The merged LIHEAP states count it, including AL, AR, FL, GA, IA, IN, KS, KY, MD, MS, NJ, NY, OH, OK, OR, RI and SD.
  • Effect (2026, a single adult aged 45 on L&I time-loss, with a $1,000 gas bill):
    • $12,000 of workers_compensation. Head: countable 0, multiplier 0.90, $900. Counted: 1,000.00; 2,648.10; 0.552 rounds to 0.55; the multiplier is 0.75, so $750.
    • $24,000. Head $900. Counted: 24,000 > 23,475, so $0.
  • Severity: should. The sources conflict, and the PR records no choice. This is the wave's unrecorded agency-vs-plan item, with a wrong result in a claimed year if the agencies' reading holds.
  • Fix:
    • I recommend adding workers_compensation to the unearned list (no deduction), with a test.
    • Alternatively, document the "insurance payments" reading in the body and the list comment, and record it (G3).
    • Either way, state how disability_benefits is treated. CAP's packet asks for "disability benefits" as gross income (page 1), while the PR reads them as insurance payments (Axiom interpretation 7).

S4. railroad_benefits and survivor_benefits have no test that would fail if they were dropped

  • Where: P/income/unearned_sources.yaml lists both. Neither appears in any of the five test files.
  • Pinned elsewhere:
    • all four business sources (countable Case 18);
    • the three retirement sources (Cases 6 and 17, award Cases 65–66);
    • reported unemployment (Case 7);
    • the other ten unearned sources (Cases 9, 12, 15 and 59);
    • Social Security net of Part B, with its floor (award Case 67, countable Case 23);
    • TANF and SFA (Cases 11, 21 and 64);
    • the earned and unearned per-source floors (Cases 3 and 16).
  • Branches. Every eligibility and award branch is pinned:
    • size 0;
    • the inclusive limit;
    • heat in rent;
    • NONE;
    • size 25;
    • the denominator guard;
    • negative income;
    • the floor, ceiling and cost cap;
    • all three rounding steps, including the ties.
  • Severity: should, as in Add New Mexico LIHEAP regular heating assistance #10431 S3, Add Louisiana LIHEAP regular heating assistance #10429 S1 and Add Missouri LIHEAP Energy Assistance #10438 S5 (the mutation rule).
  • Fix: add one countable-income case with distinct positive railroad_benefits and survivor_benefits for an adult. For example, 3,000 + 4,000 = 7,000, with no deduction, which also pins the documented choice not to apply the 10% deduction to them.

S5. Three parameter descriptions end after the program name with "benefit worksheet"

  • Where:
    • P/payment/household_adjuster.yaml:1: "Washington uses this household-size adjuster in the Low Income Home Energy Assistance Program benefit worksheet."
    • P/payment/income_constant.yaml:1: the same ending.
    • P/payment/quotient_numerator.yaml:1: the same ending.
  • The rule. The house template ends the sentence at "under the Low Income Home Energy Assistance Program." with nothing after it (checklist item 6; NJ S6). The other 13 descriptions follow it.
  • Severity: should (off-template).
  • Fix, for example:
    • "Washington divides monthly income by this household-size adjuster under the Low Income Home Energy Assistance Program."
    • "Washington subtracts adjusted monthly income from this constant under the Low Income Home Energy Assistance Program."
    • "Washington divides this amount by the worksheet denominator under the Low Income Home Energy Assistance Program."

Suggestions

G1. Count the Washington SSP (wa_ssp, checklist item 17) and Refugee Cash Assistance (wa_rca).

  • What the PR says. The comment in P/income/unearned_sources.yaml:24-25, the body and Axiom interpretation 6 leave out wa_ssp because "section 1.9 names only Supplemental Security Income". wa_rca is left out because it "has no box".
  • Why the reasons do not settle it:
    • The plan's checklist is a federal template. Besides SSI it checks "General Assistance benefits", TANF and "Other ... funds paid on behalf of the household by a third party for daily living expenses" (pp. 6-7).
    • The PR already counts a program with no box. It counts wa_sfa, a state-funded program that also has no box.
    • Main treats RCA like SFA. spm_unit_benefits treats tanf, wa_sfa and wa_rca as mutually exclusive cash aid, and SNAP's unearned list includes wa_ssp.
  • Examples (hand traces, 2026):
    • SSP. An aged SSI recipient with $11,928 of SSI and a $1,000 bill: 994.00 gives a multiplier of 0.75, $750. With the $35.50 a month STANDARD SSP: 1,029.50 gives 0.56 and a multiplier of 0.74, $740.
    • RCA. A refugee parent and child on RCA of $6,840 a year: the same arithmetic as award Case 64, $900 at the head and $850 with RCA counted.
  • Why only a suggestion. Eligibility does not change, the amounts are small, and the wave rates item 17 a suggestion.
  • Fix: add wa_ssp to the unearned list, and add wa_rca beside tanf and wa_sfa. Alternatively, record the narrower reading (G3).

G2. The FY2025 matrix uses different constants, and the FY2026 worksheet's vintage is worth recording (unclaimed backfill, as in NJ S3).

  • The FY2025 matrix. The FY2025 attachment is a "MAIN WORKSHEET" constant solver.
    • Its targets are 90% at zero income, 70% at "110% Pov" ($1,380.50) and 50% at "150% Pov" ($1,823.00).
    • The rounded constants are 2,683.5, 506.7 and 1.09.
    • Every parameter starts 2025-10-01, so period 2025 uses the FY2026 constants instead. Example: adjusted income of $1,000 a month and a $1,000 cost gives $750 at the head, against $790 under the FY2025 constants.
    • The FY2025 plan's 150%, $250 and $1,250 do match (pp. 8, 10).
  • The FY2026 worksheet's vintage.
    • The FY2026 PDF's metadata names the "110 bak working copy 2025 EAP Constant Solver" workbook, authored by Multi Service Center (a King County agency) on 2025-12-22.
    • Its constants give 90% at zero and 50% at the same $1,823 input, which is 150% of the 2023 guideline.
    • The adjusters are the 2024 guideline ratios: 21 of 24 match exactly and three are one cent lower. On the 2025 ratios, size 4 would be 2.05, not 2.07.
  • The FY2027 draft. It checks "Insurance payments made directly to the insured" and "VA benefits – combat related" (page 6), which the period 2027 carry-forward ignores.
  • Why only a suggestion. The body already says the constants' recalibration is unverified and claims only 2026.
  • Fix:
    • Add 2024-10-01 values from the FY2025 solver if 2025 is wanted; otherwise keep the note.
    • Add the metadata and adjuster vintage to the body's constants paragraph and Axiom interpretation 13.

G3. Record the plan-vs-agency choices in source_conflicts/candidates.yaml.

  • What the PR says. The body says "No reading in this PR sets a statute against another source", which is true, since no statute applies.
  • The precedent. main records same-level conflicts as candidates anyway, for example us-al:liheap-lump-sums-and-refunds and us-sd:liheap-cash-gifts (Add Louisiana LIHEAP regular heating assistance #10429 G4, Add New Mexico LIHEAP regular heating assistance #10431 G2).
  • The choices to record:
    • Deductions. The 20% and 10% deductions (Policy 1.1.2, Byrd Barr, Clark) against plan 1.8's "Gross Income". The deductions are the right choice.
    • VA benefits. Excluded per the unchecked plan box, while Byrd Barr asks for "SSA, SSI, VA, Pension, TANF, and ABD" award letters and the statewide HIF has a VA income box.
    • The cost cap. Plan 2.6 states a "Minimum Benefit $250" without exception, but the model pays less when the cost is lower (Case 34 $249.50; Case 60 $100). The body calls this an approved choice. Recording it makes the departure visible.
    • S2 and S3. Child support paid and workers' compensation, however they are resolved.
  • Fix: one or two us-wa:liheap-... candidates with pe_us.follows, the code paths and prs: [#10345].

Verified correct

Values against sources:

  • Income limit (plan 2.1, "HHS Poverty Guidelines 150.00%", p. 8):
    • FY2026. 1.5 × (15,650 + 5,500 × (n − 1)) gives 23,475, 31,725, 39,975, 48,225, 56,475, 64,725, 72,975 and 81,225. Monthly, these are Byrd Barr's $1,956 / $2,644 / $3,331 / $4,019 / $4,706 (p. 1) and Clark's table.
    • The comparison. "At or below" is <=, on exact annual amounts (documented).
    • The lag. fpg_year_lag 1 gives the 2025 guideline for FY2026.
    • Period 2027 on the 2026 guideline matches all 12 PY27 rows, $23,940 to $117,660.
  • Federal 110% floor: 150% is always above it, so it never binds.
  • Worksheet (pp. 1-2, rendered):
    • Line (a) is monthly income / adjuster; (b) is 3,648.10 − (a); (c) is 1,460.80 / (b); (d) is 1.30 − (c); then cost × (d).
    • Adjusters. All 24 match, from 1.00 to 9.21.
    • Rounding. Two-decimal intermediates with half-up ties are a documented convention that reproduces the printed $336.
    • Size 25 and up paying $0 is documented.
    • Bounds. The $250 minimum and $1,250 maximum come from plan 2.6 (p. 10); the cost cap is G3.
  • Eligibility:
    • no categorical eligibility (plan 1.4 "No", p. 5);
    • no assets test and no differing renter or subsidy policy (2.3, p. 8);
    • heating paid directly or through rent (PY27 item 2);
    • NONE is ineligible;
    • size counts citizens and qualified noncitizens (17.3, p. 37), while every member's income counts. That matches Weatherization Policy 1.1.2 item 4.a: "Account for the income received by all household members" and "Use only eligible household members to determine the household count" (p. 15).
  • Countable income (plan 1.8 "Gross Income", 1.9 boxes, pp. 5-7, rendered):
    • Counted: wages; self-employment; unemployment; strike pay; Social Security; SSI; retirement and pensions; general assistance; TANF; cash gifts; rental income; alimony; child support received; interest and dividends.
    • Excluded: VA benefits; insurance payments; lump sums; savings and retirement balances; tax refunds; "Earned income of a child under the age of 18".
    • Deductions. The 20% wage allowance and the 10% retirement and unemployment deductions apply at 150% FPL under Policy 1.1.2 item 5.a. It reads "(2) For 200% FPL, 60% SMI, and 80% AMI, except: (a) 20 percent allowance for wage earner. (b) 10 percent retirement deduction. (c) 10 percent deduction for unemployment benefits." (p. 15). Byrd Barr applies 20% to "earned income taxed at the time of payout" (p. 1), and Clark applies 80% of gross.
    • Self-employment is net, floored per source, with no 20%. The KCR worksheet zeroes loss months, and the 50% standard deduction is documented.
    • Social Security net of Part B is correct here. Plan 1.9 checks "Excluding MediCare deduction" (p. 6, rendered). medicare_part_b_premium is the enrollee's out-of-pocket premium net of MSP, floored per person. That matches the wave's Medicare precedent, and the Part B-only reading follows the Iowa precedent for check-withheld deductions.
    • Losses do not offset wages (Cases 3 and 16).
  • Heating cost. The worksheet multiplies the "Annual Heat Cost", and the HIF records the primary heat source and its annual cost separately from "Total Annual Electric Costs". So Washington is not a choose-your-bill program like New Mexico or Missouri, and reading the primary fuel's heating_expense is right. Not adding the HIF's "Back Up Heat Cost" and not splitting electric baseload are documented limitations.
  • Interactions with Washington programs on main:
    • TANF and SFA. tanf (take-up gated, includes wa_tanf) and wa_sfa are each added once. wa_sfa is ungated, as in spm_unit_benefits.
    • WFTC. Refundable credits, including the Working Families Tax Credit, are excluded (Case 14).
    • PFML. wa_pfml is a maximum entitlement, not income received, and is rightly not read.
    • SSP and RCA: G1.
    • Readers. No program or aggregate reads wa_liheap, which matches every merged LIHEAP state.
  • References (item 7):
    • Every plan anchor shows its value: 2.1 and 2.3 on p. 8, 1.9 on pp. 5-7 (Social Security and the under-18 box on p. 6), 2.6 on p. 10 and 17.3 on p. 37.
    • The matrix pp. 1-2, Policy 1.1.2 pp. 14-15 (item 5.a on p. 15) and Byrd Barr pp. 1, 2 and 13 also show their values.
    • Multi-page titles use the quoted #page 14-15 / #page 2,13 form, and variables use # PDF pages comments.
  • Descriptions (item 6): 13 of 16 pass (S5).
  • Years:
    • 2026 is verified.
    • 2025 is an unclaimed backfill. The plan's limit and bounds match, but the matrix constants differ (G2).
    • 2027 limits match the PY27 sheet. Its awards and the draft plan's income changes are a documented carry-forward.

Hand-checked expectations (40). All are 2026 unless noted:

  • wa_liheap.yaml Cases 1–2: 500.00 → 3,148.10 → 0.464, rounded to 0.46 → 0.84 × 400 = 336. Zero income gives 0.400 → 0.90, 360.
  • Cases 4 and 26: 8,160 / 12 / 1.36 and 55,260 / 12 / 9.21 both give 500.00, so 336.
  • Cases 27–29: 1,600.00 → 0.713 → 0.59, 590. 24,000 / 12 / 1.36 = 1,470.59 → 2,177.51 → 0.671 → 0.63, 630. 900.00 → 0.532 → 0.77 × 400, 308.
  • Cases 30–31: 1,956.25 → 1,691.85 → 0.863 → 0.44, 440. 23,476 is ineligible, 0.
  • Cases 34–40 (multiplier 0.90):
    • 249.50 gives 224.55 → 225 → 250, capped at 249.50;
    • 277 gives 249.3 → 250, 250;
    • 405 gives 364.5 → 365;
    • 1,388 gives 1,249;
    • 1,389 gives 1,250;
    • 1,390 gives 1,250.
  • Cases 41–44: 506.59 → 3,141.51 → 0.464999, 840. 506.60 → 3,141.50 → 0.465001, 830. 6,079.128 gives 506.594 → 506.59, 840. 6,079.152 gives 506.596 → 506.60, 830.
  • Case 45: −1,000 floors to 0, so 360.
  • Case 59: 9,600 + 3,000 + 1,200 = 13,800; / 12 / 1.36 = 845.59 → 2,802.51 → 0.521 → 0.78, 780.
  • Case 60 (second unit): 0.90 × 100 = 90 → 250, capped at 100.
  • Cases 61–63: 3,479.21 / 12 = 289.934 → 289.93 → 3,358.17 → 0.43499 → 0.87, 870. 3,479.22 / 12 = 289.935, a tie, up to 289.94 → 0.435002 → 0.86, 860. 3,479.23 gives 860.
  • Case 64: no TANF gives 900. TANF 6,840 / 12 / 1.36 = 419.12 → 3,228.98 → 0.452 → 0.85, 850.
  • Cases 65–66: 26,000 × 0.9 = 23,400 → 1,950.00 → 1,698.10 → 0.860 → 0.44, 440 (retired pay and SBP alike).
  • Case 67: 24,000 − 2,434.80 = 21,565.20 → 1,797.10 → 1,851.00 → 0.789 → 0.51, 510.
  • Countable Cases 2, 3 and 6: 9,600 + 12,000 = 21,600; 9,600 + 0 = 9,600; 12,000 × 0.9 = 10,800.
  • Countable Cases 15, 16 and 18: the sum of 1,000 through 9,000 = 45,000; 0 + 2,000 + 9,600 = 11,600; 1,000 + 2,000 + 3,000 + 4,000 = 10,000.
  • Countable Case 23: 30,000 × 0.9 + max(1,800 − 2,434.80, 0) = 27,000.
  • Income-limit Cases 2–14: 23,475; 31,725; 39,975; 48,225; 56,475; 64,725; 72,975; 81,225; 1.5 × 76,150 = 114,225; 1.5 × 142,150 = 213,225; 1.5 × 147,650 = 221,475. In 2027, 1.5 × 15,960 = 23,940 and 1.5 × 21,640 = 32,460, matching the PY27 sheet.
  • Case count: 67 + 23 + 10 + 4 + 14 = 118, as the body says.

Batch checks:

Wiring and housekeeping:

  • Registry. The WA entry sits after TX with verified_years: "2026", and WA is added to the coverage line. test_programs_registry passed.
  • Aggregates. There is no aggregate wiring, which matches every merged LIHEAP state.
  • Gating. defined_for = StateCode.WA is on 4 variables, and wa_liheap is gated by wa_liheap_eligible.
  • Changelog. changelog.d/wa-liheap-wave2b.added.md is top level and typed added.
  • Tests. The files are variable-named, every period is plain, and every benefit and eligibility case sends heating_type.

Checklist results (LIHEAP batch):

  1. State plan and manual: every published value matches: the limit, the worksheet, all 24 adjusters and the bounds. The heat-in-rent surrogate is S1.
  2. Income definition: gross income with the Commerce deductions, Social Security net of Part B, per-source floors and annual amounts are right. Paid support is S2 and workers' compensation is S3.
  3. Backdating: pass for 2026. 2025 is an unclaimed backfill with different matrix constants (G2).
  4. Household and arrangement rules: heat in rent is S1. Subsidized housing, NONE, UNSPECIFIED and mixed status are tested.
  5. Tests: 118 cases, 40 hand-checked, all periods plain. Source coverage is S4.
  6. Descriptions: 3 off-template (S5).
  7. References: pass.
  8. Wiring: pass.
  9. Axiom: valid (CalEITC investment income limit not applied correctly #1905).
  10. Branch and CI: a clean merge with main; 34 of 34 pass.
  11. Integrate modeled state unemployment insurance into income flows #9558: pass.
  12. IIJA / FY2027: not applicable / draft only.
  13. Mutation check: two unearned entries are unpinned (S4).
  14. Document disjoint health premium inputs and correct consumer treatment #10046: not applicable.
  15. State-gated index defaults: safe.
  16. Wire military retirement pay and survivors into federal and state tax (#10181) #10182 / Count military SBP annuities in state benefit income lists #10317: pass.
  17. Merged state SSPs: wa_ssp is not counted (G1).

Axiom line assessment

Valid: axiom: TheAxiomFoundation/rulespec-us#1905 queued.

  • State: OPEN, labelled pe-parity, created 2026-10-24 03:14 UTC.

  • It matches the head. It names head 329eb32148 and merge base ee6c90961d. It lists the 16 parameters (4 business, 3 retirement and 12 unearned sources), the 5 variables and the 118 cases by file. Its required outputs (size, limit, countable income, heating cost, eligibility and benefit) describe the head's code.

  • It is dispatch-ready in the rulespec-us#1467 format:

    • proposed us-wa/ module paths, with corpus status per source;
    • verbatim text of the plan (box states read from renders), the worksheet, Policy 1.1.2, the PY27 sheet, Byrd Barr, KCR and CACLMT;
    • 14 companion tests derived from the sources, not from PE output;
    • 18 interpretations;
    • its blockers: sources missing from the corpus, the bundle's back-year exclusion, an unchecked signed release, billed-run approval and no reviewed oracle revision.
  • Note. The fixes change these interpretations and outputs:

    • S1 changes interpretation 11 and the benefit output;
    • S2 changes interpretation 5, which calls the paid-support reading "settled";
    • S3 changes interpretation 7, which omits workers' compensation;
    • S4 adds cases;
    • G1 changes interpretation 6.

    Update the issue with the head that resolves them. Add Clark Public Utilities' page and Weatherization Exhibit 1.3.1A to its sources.

CI status

34 pass, 0 failed, none pending. Run 40057977009 tested head 329eb32148 (pull_request, created 2026-10-24 03:21 UTC, after #10287 and the 2026-10-21 cutoff). I re-checked gh pr checks 10345 at the end of this review.

  • Washington tests. States-shard-2, batch 13/14 (states/wa), ran all 5 files: 67 + 23 + 10 + 4 + 14 = 118 passed.
  • Guards (Rest Python shard 3):
    • the four test_unemployment_compensation_readers.py tests;
    • the four test_military_retirement_readers.py tests;
    • the test_source_conflicts.py tests, including test_conflict_sounding_comments_do_not_grow and the candidate checks;
    • test_members_are_state_gated;
    • test_programs_registry.
  • Also passing: Microsimulation, Household API Partners, PR validation, Package and compatibility, Quick Feedback, codecov, and every baseline and contrib shard.
  • Known main-caused failure: not applicable.
  • Locally: I ran no tests or model probes. The S1–S3 and G1–G2 examples are hand traces of the code at the head. The only local scripts were the static comment-pattern scan, the worksheet arithmetic and the adjuster-ratio check.

Branch status

0 critical, 5 should and 3 suggestions are open at this head.

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.

The 150% FPG limits, worksheet constants and adjusters, the $250/$1,250 bounds, the deductions, Social Security net of Part B and the per-source loss floors all check out, 40 expectations hand-check, and the guards pass. Five should-address items: (1) heat-in-rent and UNSPECIFIED households are eligible but get $0, while WA pays from a surrogate heat cost (at least the $250 minimum); (2) child support and alimony paid aren't deducted ($0 vs $460); (3) workers' compensation is neither counted nor documented ($900 vs $750); (4) railroad and survivor benefits are never positive in a test; (5) three descriptions run past the program name. Three suggestions, including counting wa_ssp. Full report in the comment above.

@DTrim99 DTrim99 mentioned this pull request Oct 26, 2026
3 of 4 tasks
hua7450 and others added 2 commits October 26, 2026 20:45
Pay the plan's $250 minimum when heat is included in rent with a known fuel and no reported cost; deduct child support and alimony paid; count workers' compensation, the state supplement and refugee cash assistance; add railroad/survivor coverage, description fixes and two source-conflict candidates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hua7450

hua7450 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough review, David. The fixes are in 7214ef4, and ad84271 merges current main.

  • S1 (heat in rent pays $0). Fixed. When an eligible household has heat in rent, a known heating_type and no reported cost, wa_liheap.py now pays the $250 minimum with no cost cap, as a lower bound. It cites plan 2.6 (page 10) and plan 9.1 (page 24), which pays heat-in-rent households by check; the surrogate schedule is not published. A reported cost keeps the worksheet path (Cases 48 and 49). New wa_liheap.yaml Case 68 is your $12,000 gas example and pays $250.
  • S1b (UNSPECIFIED with heat in rent). Declined. Callers must send heating_type, and UNSPECIFIED paying $0 is by design (Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754), so the minimum excludes it. Case 50 stays at $0 and its name now says why. Case 51 now sends FUEL_OIL with fuel_oil_expense instead of UNSPECIFIED.
  • S2 (support paid). Fixed. wa_liheap_countable_income.py subtracts members' child_support_expense and alimony_expense and floors countable income at zero, citing Exhibit 1.3.1A (page 445), Clark Public Utilities and CACLMT. Countable Case 12 is now 3,800, new countable Case 25 pins the zero floor, and new wa_liheap.yaml Case 69 is your $30,000 / $1,200 example ($460).
  • S3 (workers' compensation). Fixed. workers_compensation is on the unearned list in unearned_sources.yaml, with no deduction; new wa_liheap.yaml Case 70 pays $750 on $12,000. disability_benefits and life_insurance_benefits stay excluded as insurance paid directly to the insured (unchecked in plan 1.9), and the list comment and the body now say so.
  • S4 (untested sources). Fixed. New countable Case 24: railroad_benefits 3,000 + survivor_benefits 4,000 = 7,000, with no 10% deduction.
  • S5 (descriptions). Fixed with your three sentences in household_adjuster.yaml, income_constant.yaml and quotient_numerator.yaml.
  • G1 (SSP and RCA). Adopted. wa_rca and wa_ssp now count with tanf and wa_sfa as state cash assistance (WAC 388-400-0030 and WAC 388-474-0012(1)), and the old wa_ssp comment is replaced. New wa_liheap.yaml Case 71 is your SSP example ($740), and new countable Case 26 counts RCA at the one-person standard ($5,400). Countable Case 19 and wa_liheap.yaml Case 59 now include the disabled child's supplement (14,226; the award goes from $780 to $770).
  • G2 (FY2025 constants and worksheet vintage). Documented; no parameters added. The FY2025 matrix prints only the three solver constants, with no adjusters or worksheet, and verified_years stays "2026". The body's constants paragraph and Axiom interpretation 13 now record the workbook metadata, the 2024-guideline adjusters and the FY2025 constants (2,683.5, 506.7 and 1.09), and label 2025 results as unverified estimates.
  • G3 (candidates). Adopted. source_conflicts/candidates.yaml has two new entries: us-wa:liheap-plan-agency-income-items (the deductions, paid support, workers' compensation and VA benefits) and us-wa:liheap-minimum-benefit-cost-cap (ruled; it also notes the uncapped $250 for heat in rent with no cost). No marker is added.

The PR body and TheAxiomFoundation/rulespec-us#1905 are updated for ad84271; the Axiom issue now also lists the Clark page, Exhibit 1.3.1A and plan 9.1 as sources. I did not run the tests locally, so CI will check them.

@hua7450
hua7450 requested a review from DTrim99 October 27, 2026 01:01
@DTrim99 DTrim99 mentioned this pull request Oct 27, 2026
2 of 3 tasks
@DTrim99

DTrim99 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

PR Review (round 2): Add Washington LIHEAP regular heating assistance

PR #10345 (author: hua7450). This round reviews head ad842717e6. Round 1 reviewed 329eb32148 on 2026-10-26 and requested changes. Two commits came in between:

  • 7214ef48c3, "Address review of Washington LIHEAP" (12 files, +331/−42). It answers S1–S5 and G1–G3.
  • ad842717e6, a merge of main at 976b409f4e. It had no hand-resolved conflict and changes no Washington LIHEAP file.

Ziming replied to every finding on 2026-10-27. The PR body and TheAxiomFoundation/rulespec-us#1905 were rewritten for this head. The PR still touches no partner test file.

Path prefixes, as in round 1:

  • P/ = policyengine_us/parameters/gov/states/wa/commerce/liheap/
  • V/ = policyengine_us/variables/gov/states/wa/commerce/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/wa/commerce/liheap/

Summary

Ziming fixed all five round-1 should items:

  • S1, heat in rent. V/wa_liheap.py:67-74 pays the plan's $250 minimum, with no cost cap, when heat is in the rent, the fuel is known and no cost is reported. New Case 68 is the round-1 example: $250 instead of $0. A reported cost keeps the worksheet (Cases 48 and 49). The UNSPECIFIED part is declined, and I accept that, as I did on Add Virginia EAP Fuel Assistance (LIHEAP regular heating) #10303 and Add Arizona LIHEAP Standard benefit #10293.
  • S2, support paid. V/wa_liheap_countable_income.py:86-90 subtracts the members' child_support_expense and alimony_expense and floors countable income at zero. New Case 69 is the round-1 example: $460 instead of $0.
  • S3, workers' compensation. workers_compensation is on the unearned list with no deduction. New Case 70 is the round-1 example: $750 instead of $900.
  • S4, untested sources. Countable Case 24 pins railroad_benefits and survivor_benefits.
  • S5, descriptions. All three now end at the program name.

All three suggestions were taken: G1 counts wa_ssp and wa_rca, G2 documents the worksheet's vintage, and G3 adds two candidates.

There are no new critical or should findings, and one new suggestion:

  • G4: add Wayback captures for the Clark Public Utilities and CACLMT pages, which are now formal references.

Batch checks:

I hand-checked every new or changed expectation: 7 new cases and 5 changed ones. CI is 35/35 green at the head, and states-shard-2 passed all 125 Washington LIHEAP cases. The branch is 12 commits behind main. It now conflicts in programs.yaml only, because #10293 and #10303 merged today; that needs a one-line resolution (branch note).

Prior findings status

Finding Status Evidence
S1: heat-in-rent households eligible but paid $0 Fixed for a known fuel; the UNSPECIFIED part declined (accepted) The code. V/wa_liheap.py:68 sets known_fuel (not UNSPECIFIED). Lines 69-73 set unpriced_heat_in_rent = heat_expense_included_in_rent & (expense <= 0) & known_fuel, and line 74 pays p.minimum for it, outside the cost cap. The size and line (b) gates still apply (line 75). The tests. Case 68 (T/wa_liheap.yaml:944) is one adult aged 40 with $12,000 of wages, gas heat in the rent and no gas bill: heating_expense 0, countable 9,600 ≤ 23,475, eligible, $250. Cases 48 and 49 keep $336 on a reported $400, which pins expense <= 0, and Case 50 pins the fuel gate. The new citation holds. Plan item 9.1 (p. 24) reads: "when heat is included in rent, LIHEAP benefits are awarded directly to the household by check." UNSPECIFIED, declined. Case 50 (line 502) stays eligible at $0. main's HeatingType comment calls UNSPECIFIED the right value for heat in rent with an unknown fuel, and Washington's $250 floor does not depend on the fuel. But #10303 G2 and #10293 G2 settled UNSPECIFIED as an input rule ("heating_type is a required input"). The body's eligibility and benefit rows, the variable documentation, Case 50's name and Axiom interpretation 12 all record the choice and #9754. I accept it. If the house rule changes, dropping & known_fuel is a one-line fix.
S2: child support and alimony paid not deducted Fixed The code. V/wa_liheap_countable_income.py:86-88 sums child_support_expense and alimony_expense (both Person, YEAR on main), and line 90 returns max_(gross - max_(support_paid, 0), 0). The tests. Countable Case 12 (line 146): 5,000 − 1,200 = 3,800. Countable Case 25 (line 346): 6,000 × 0.8 = 4,800, less 3,600 + 2,400, floors at 0. Dropping alimony_expense would give 1,200 and dropping the floor −1,200, so both are pinned. Award Case 69 (line 966): 24,000 − 1,200 = 22,800 ≤ 23,475; 1,900.00; 1,748.10; 0.83565 rounds to 0.84; 0.46 × 1,000 = $460. The documentation. The comment, the variable documentation, the body and Axiom interpretation 5 now cite Exhibit 1.3.1A, Clark and CACLMT, and say alimony paid rests on the Clark page alone. Candidate us-wa:liheap-plan-agency-income-items records the choice.
S3: workers' compensation neither counted nor mentioned Fixed (the recommended option) P/income/unearned_sources.yaml:16 adds workers_compensation, with no deduction. The list comment and the body give the reason (no plan 1.9 row; Exhibit 1.3.1A's L & I statement; CACLMT's time loss). The comment, the body and Axiom interpretation 7 also say that disability_benefits and life_insurance_benefits stay excluded as insurance payments made directly to the insured. Case 70 (line 988): 12,000; 1,000.00; 2,648.10; 0.55164 rounds to 0.55; $750. The candidate records it.
S4: railroad_benefits and survivor_benefits never positive Fixed Countable Case 24 (line 331): age 62, railroad 3,000 + survivor 4,000 = 7,000, which also pins the absence of the 10% deduction. Every entry in the 4 business, 3 retirement and 13 unearned lists now takes a positive value in at least one case. So does each newly read input (child_support_expense, alimony_expense, wa_rca, wa_ssp).
S5: three descriptions ran past the program name Fixed household_adjuster.yaml, income_constant.yaml and quotient_numerator.yaml use the three suggested sentences. All 16 descriptions now follow the template.
G1: count wa_ssp and wa_rca Taken The code. V/wa_liheap_countable_income.py:80 reads add(spm_unit, period, ["tanf", "wa_sfa", "wa_rca", "wa_ssp"]). wa_rca (SPMUnit, MONTH) is added once, and wa_ssp (Person, MONTH) is summed over members. add sums the months, as it already did for wa_sfa. No double count. tanf adds only tanf_if_takes_up and includes neither wa_sfa nor wa_rca, and main has no other Washington cash program. The citations hold. WAC 388-474-0012(1): SSP "is a state-funded cash assistance program for certain clients who the Social Security Administration determines are eligible for supplemental security income". WAC 388-400-0030(3): "We determine your eligibility and benefit level for RCA using the TANF payment standards under WAC 388-478-0020." The tests. The stale "wa_ssp is not counted" comment is gone. Case 71 is the round-1 example: 11,928 + 426 = 12,354; 1,029.50; 2,618.60; 0.55786 rounds to 0.56; $740. Countable Case 26: wa_rca 5,400 (450 × 12, main's one-person standard since 2024) gives 5,400. In Cases 19 and 59, the disabled child (WAC 388-474-0012(2)(e)) gets 35.50 × 12 = 426, and separate marital units keep the child from being read as a spouse.
G2: FY2025 constants and the FY2026 worksheet's vintage Documented (accepted) The body's constants paragraph and Axiom interpretation 13 now record the PDF metadata ("110 bak working copy 2025 EAP Constant Solver", Multi Service Center, 2025-12-22). They also record the 2024-guideline poverty column and adjusters (21 of 24 exact), the FY2025 constants (2,683.5, 506.7 and 1.09) and the $750 vs. $790 example, and they label 2025 an unverified estimate. verified_years stays "2026". No FY2025 values were added, which round 1 allowed.
G3: record the plan-vs-agency choices Taken source_conflicts/candidates.yaml adds two candidates, each with code paths and prs: [#10345]. us-wa:liheap-minimum-benefit-cost-cap: ruled, follows: unknown, citing plan 2.6 and the worksheet. Its example ($90 from the worksheet, $250 at the plan minimum, $100 in PE-US) matches Case 60. us-wa:liheap-plan-agency-income-items: unreviewed, follows: unknown, citing the plan, the manual, Clark, CACLMT and Byrd Barr. Its example is the S2 household. The IDs are sorted and unique, and CI's candidate checks pass. No marker is added, consistent with the body.

New findings

Critical (must fix)

None.

Should address

None.

Suggestions

G4. Add Wayback captures for the two agency web pages that are now formal references.

Verified

Hand-checked expectations (every new or changed one; all 2026):

  • wa_liheap.yaml Case 50 (renamed only): UNSPECIFIED gets no floor, so min(clip(0, 250, 1,250), 0) = 0. It is eligible (true): 6,000 ≤ 23,475, heat is in the rent, and the type is not NONE.
  • Case 51 (inputs changed): FUEL_OIL reads fuel_oil_expense, so heating_expense is 400. Then 500.00; 3,148.10; 0.46403 rounds to 0.46; 0.84 × 400 = 336.
  • Case 59:
    • wa_ssp [0, 426];
    • countable 9,600 + 3,000 + 1,200 + 426 = 14,226;
    • 14,226 / 12 / 1.36 = 871.69; 2,776.41; 0.52615 rounds to 0.53; 0.77 × 1,000 = 770;
    • size 2, limit 31,725, eligible.
  • Case 68: heating_expense 0, size 1, countable 12,000 × 0.8 = 9,600, eligible, 250.
  • Case 69: limit 23,475, countable 22,800, award 460 (traced in the table).
  • Case 70: countable 12,000, award 750.
  • Case 71: wa_ssp 426, limit 23,475, countable 994 × 12 + 426 = 12,354, award 740.
  • Countable Cases 12, 19, 24, 25 and 26:
    • Case 12: 3,800;
    • Case 19: wa_ssp [0, 426] and 14,226;
    • Case 24: 7,000;
    • Case 25: 0;
    • Case 26: 5,400.
  • Case count: 71 + 26 + 10 + 4 + 14 = 125, as the body says (7 added this round).

Mutation check of the new logic:

  • The fuel gate is pinned by Case 50 against Case 68.
  • expense <= 0 is pinned by Cases 48 and 49.
  • No cost cap on the floor is pinned by Case 68, which the cap would turn into 0.
  • The heat_expense_included_in_rent term (line 70) cannot be pinned, because eligibility already requires it when the cost is zero. It is an equivalent mutant, not a gap.
  • The new income items are pinned:
    • the support list and its floor by Cases 12, 25 and 69;
    • wa_rca by Case 26, and wa_ssp by Cases 19, 59 and 71;
    • workers_compensation by Case 70;
    • railroad and survivor benefits by Case 24.

Other checks:

  • Consistency. These all describe the uncapped $250 floor for a known fuel and $0 for UNSPECIFIED:
    • the wa_liheap and wa_liheap_eligible documentation;
    • the minimum.yaml comment;
    • the programs.yaml note;
    • the body and the Axiom issue.
  • References. The new wa_liheap.py comment "Sections 2.6 and 9.1, PDF pages 10,24" points to pages that show both provisions: "Minimum Benefit $250 ... Maximum Benefit $1,250" on p. 10, and item 9.1 on p. 24. The unearned list's new Exhibit 1.3.1A reference (p. 445) is the page round 1 read for the L & I statement.
  • The Case 26 comment. Its $450 one-person standard (WAC 388-478-0020) matches main's Washington TANF payment standard from 2024-01-01.
  • Federal 110% floor: the 150% limit is always above it.

Batch checks:

Axiom line assessment

Valid: axiom: TheAxiomFoundation/rulespec-us#1905 queued.

  • State: OPEN, labelled pe-parity, updated 2026-10-27 01:01 UTC.
  • It matches the head.
    • It names ad842717e6, commit 7214ef48c3 and main at 976b409f4e, and lists the 125 cases by file.
    • Its benefit output has the uncapped $250 floor with UNSPECIFIED excluded. Its countable output has the support deduction with its floor, workers_compensation, wa_rca and wa_ssp.
    • Interpretations 5, 6, 7, 11, 12 and 13 are updated, with companion tests 8(f), 10, 11(c), 15, 16 and 17.
    • Clark, Exhibit 1.3.1A, plan item 9.1 and WAC 388-400-0030 are added as sources.
  • It is still dispatch-ready, with its blockers listed:
    • sources missing from the corpus;
    • the bundle's back-year exclusion;
    • an unchecked signed release;
    • billed-run approval;
    • no reviewed oracle revision.
  • Note: it still says CI passed 118 cases at 329eb32148 and that CI will validate round 2. CI has now passed all 125 at ad842717e6, which can be recorded when the oracle revision is pinned. This is not a finding.

CI status

35 pass, 0 failed, none pending. Run 40428394190 tested head ad842717e6 (pull_request, created 2026-10-27 00:45 UTC). I re-checked gh pr checks 10345 at the end of this review.

  • Washington tests. States-shard-2, batch 13/14 (states/wa), ran all 5 files: 71 + 26 + 10 + 4 + 14 = 125 passed.
  • Guards (Rest Python shards):
    • every test_source_conflicts.py test, including the ratchet and the candidate checks;
    • the four test_unemployment_compensation_readers.py tests;
    • the four test_military_retirement_readers.py tests;
    • test_members_are_state_gated;
    • test_programs_registry.
  • Also passing: Microsimulation, Household API Partners, PR validation, Package and compatibility, Quick Feedback, codecov, and every baseline and contrib shard.
  • Known main-caused failure: not applicable.
  • Locally: I ran no tests or model probes, only plain arithmetic for the hand checks and the static comment-pattern scan. I re-read plan page 24, WAC 388-474-0012 and WAC 388-400-0030 for the new citations.

Branch status

0 critical, 0 should and 1 suggestion are open at this head.

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.

Approving round 2: 0 critical, 0 should. Full report in the comment above. Branch note: programs.yaml now conflicts with main after #10293/#10303 merged; append WA after VA and rerun CI before merging.

# Conflicts:
#	policyengine_us/programs.yaml

This branch has not been deployed

No deployments
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 Washington LIHEAP regular heating assistance

2 participants