Skip to content

Add Wyoming LIHEAP regular heating assistance - #10346

Merged
hua7450 merged 12 commits into
mainfrom
wy-liheap-wave2b
Oct 27, 2026
Merged

hua7450 merged 12 commits into
mainfrom
wy-liheap-wave2b

Conversation

@hua7450

@hua7450 hua7450 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Adds Wyoming's Low Income Energy Assistance Program (LIEAP) regular heating benefit for FY2026. The model counts U.S. citizens and qualified noncitizens for household size, counts the earnings of members 18 and over less child support paid plus all members' unearned income, with Social Security net of the Medicare Part B premium, tests the total against 60% of state median income (SMI) with the federal protection for income below 110% of the poverty guideline, and pays a share of the FY2026 fuel cost standard for the household's primary heating fuel. The share falls from 80% to 10% as income approaches the limit and is zero at the limit; the model withholds 10% of that amount, rounded to whole dollars, pays nothing when the remainder is below $10 and otherwise pays the remainder up to the heating bill, or the whole remainder when heat is included in rent and no bill is reported. In FY2026, a two-person household with a 40-year-old who earns $12,000 and pays $2,400 of child support and a 17-year-old who is not a full-time student and earns $6,000, heating with fuel oil that costs $3,000 for the season, receives $1,901: the 17-year-old's wages, $3,000 of child support received and $6,000 of POWER cash assistance (Wyoming's TANF program) are excluded, so countable income is $12,000 - $2,400 = $9,600; against the two-person limit of $46,853 (60% of SMI, rounded down), $9,600 / $46,853 = 0.205 falls in the "0 - .20" row of the benefit table, below the 0.21 start of the next row, which pays 80% of the $2,640 fuel oil standard, $2,112; and $2,112 - $211 holdback (10% of $2,112, rounded) = $1,901, below the $3,000 bill.

Fixes #10340

Regulatory authority

Eligibility

Requirement Source How modeled
Wyoming residence Rules sections 3(fff) and 7(b)(iv) defined_for = StateCode.WY; winter presence is not observed
Household size counts U.S. citizens and qualified noncitizens Plan section 17.3 (page 38) requires status verification but gives no mixed-status calculation; rules section 3(kk) defines the household wy_lieap_household_size adds is_citizen_or_legal_immigrant over the SPM unit, a modeling assumption. Other members' income still counts with no further proration, and a unit with no counted member is ineligible.
Gross income at or below 60% of SMI for the household size Plan sections 1.8 and 2.1 (pages 5 and 8); FY2026 SMI table; HHS LIHEAP IM 2025-02 Attachment 4 (pages 3 and 6) wy_lieap_income_limit calls the shared liheap_smi_limit helper, which rounds 60% of the four-person SMI down to whole dollars ($68,902 in FY2026), multiplies it by the size percentage and rounds down again. HHS states the order of these steps but not the rounding. The tests pin the HHS FY2026 amounts for one to eight and ten people ($35,829 to $95,084, and $99,218) and the 2026-2027 handout limits for one to five. Income equal to the limit qualifies.
Federal protection below 110% of the poverty guideline 42 U.S.C. 8624(b)(2)(B) wy_lieap_eligible also accepts income strictly below 110% of wy_lieap_fpg, the poverty guideline with a one-year lag (the 2025 guideline for FY2026) at the counted size, rounded to cents, reusing gov.hhs.liheap.fpg_floor. In FY2026 the floor exceeds the SMI limit only for 17 or more counted members: 110% x $103,650 = $114,015 against $113,688. The model follows the statute; source_conflicts/candidates.yaml lists this as us-wy:lieap-income-floor-vs-smi-limit.
No categorical eligibility and no asset test Plan sections 1.4 and 2.3 (pages 5 and 8); rules section 7(a)(i) Every household takes the income test; assets are not tested. The model follows the plan's "No" to categorical eligibility over rules section 7(a)(i), which lists adults in multi-person households who receive POWER, SNAP, or veteran or survivor pension payments.
Responsibility for the primary heating cost Rules sections 3(kk) and 8(b) heating_expense above zero for the primary heating_type, or heat_expense_included_in_rent. Rule 8(b)(i)(B) makes a household vulnerable when its rent includes a prorated heating cost, and rule 3(kk) allows the energy purchase to be in the form of rent.
Renters, including subsidized renters Rules section 10(e); plan section 2.3 (page 8) Same schedule as owners; receives_housing_assistance does not change the award. A household whose heat is included in rent and that reports no heating bill receives the standard formula for its fuel, with no cost cap (see Benefit).
Heating fuel Benefit matrix Table 1; rules section 3(hh); plan section 2.3 (page 9); DFS LIEAP page The six worksheet fuels use their own standards; kerosene uses the fuel oil standard, solar the electricity standard and other fuels the wood standard (see Benefit). heating_type NONE and UNSPECIFIED have a $0 standard and pay nothing; callers must send heating_type (#9754).

Countable income

Item Source How modeled
Period Rules section 8(a) averages current monthly gross nonexempt income Annual inputs stand in for monthly income. The $30 monthly thresholds below become $360 a year, which assumes even monthly receipts.
Earned income Plan section 1.9 (pages 5 to 6); rules sections 3(w), 3(uu) and 8(a)(ii)(A) Wages, self-employment (including SSTB), farm operations and partnership or S corporation income of members 18 and over, each floored at zero, so business losses do not offset wages. The plan leaves "earned income of a child under the age of 18" unchecked, while the rules exempt only earnings of children under 14 and of full-time students under 18; the model follows the plan.
Child support paid Rules section 8(a)(iii) child_support_expense is subtracted from the payer's own earnings, floored at zero, never from unearned income or another member's earnings. The input does not show whether the support is court ordered or paid monthly.
Unearned income Plan section 1.9; rules section 3(nn) Social Security (next row), SSI, pensions, military retirement pay and Survivor Benefit Plan annuities (military_retirement_income), retirement distributions, railroad retirement, survivor benefits other than Social Security, unemployment compensation (total_unemployment_compensation), workers' compensation, disability benefits, general assistance, alimony, rental and farm rental income, estate and trust income and ordinary dividends, each floored at zero
Medicare deducted from Social Security Rules section 8(a)(ii)(U); plan section 1.9 (page 6) checks Social Security "Excluding MediCare deduction" Each person's social_security less that person's computed medicare_part_b_premium, floored at zero, so a premium larger than the benefit does not reduce other income. The premium is zero for a person not enrolled in Part B and excludes any share a Medicare Savings Program pays.
Interest Rules section 8(a)(i)(A) Counted in full when above $30 a month ($360 a year); the threshold is not a deduction
Cash gifts Plan section 1.9; rules section 8(a)(ii)(D) financial_assistance counted in full when above $30 a month ($360 a year)
Veterans benefits Rules section 8(a)(ii)(S) Total veterans_benefits across the SPM unit, less one exclusion equal to 100% of the household-size poverty guideline (the 2025 guideline in FY2026). Only the excess counts, and an unused exclusion does not offset other income. Total VA income stands in for service-connected disability benefits.
Not counted Plan section 1.9; rules sections 8(a)(ii)(L) and 8(a)(ii)(U); Eligibility Online Manual M1804 POWER (TANF) and child support received, which the plan leaves unchecked; lump sums, including tax refunds, rebates and credits, which the rules exempt although the plan checks one-time lump sums; savings and retirement account balances; and wy_ssp, Wyoming's $20 monthly State Supplemental Payment, which rule 8(a)(ii)(U) exempts as "The optional State Medicaid Supplement Benefit" (M1804 ties the payment to federal Medicaid match)

Benefit

  • Fuel cost standards (benefit matrix, one per worksheet): coal $525, fuel oil $2,640, electricity $1,712.997, natural gas $1,550.85, propane $1,300 and wood $1,225. Kerosene takes the fuel oil standard: rule 3(hh) lists "diesel, oil" fuel types, the oil worksheet is titled "Diesel Heating Oil", and heating_expense reads a kerosene bill as fuel_oil_expense. Solar takes the electricity standard, because heating_expense reads a solar home's bill as its electricity bill. Other fuels take the wood standard, the closest published worksheet. NONE and UNSPECIFIED pay $0.
  • Entitlement fraction (Table 1): each printed row starts at its listed ratio. The model compares countable income with the income limit times 0.21, 0.26, 0.31 and so on through 0.86, then 1.00. Income below the first of these ceilings pays 0.80, income below the next pays 0.75, and so on down to 0.10 below the limit; income at or above the limit (the "1.00 +" row) pays zero, so a household with income exactly at the limit is eligible and receives $0. A ratio exactly at a printed start takes that row (0.21 pays 0.75), and a ratio between printed rows, such as 0.205, takes the earlier row, as truncation to two decimals would. The ratio is never rounded. The denominator is the larger of the SMI limit and 110% of the guideline, which in FY2026 differs from the SMI limit only for 17 or more counted members.
  • Holdback (Table 1): 10% of the scheduled amount, rounded half up to whole dollars, matching the workbook's withheld cells (for example =ROUND(D22*0.1,0) on the Heating Oil worksheet). The award keeps the workbook's unrounded remainder, for example $1,712.997 x 0.80 = $1,370.3976 less $137 = $1,233.3976 for electricity. The hidden 5% and 15% holdback tables on the coal, heating oil, propane and wood worksheets are not used, and the model does not release the holdback.
  • Cutoff and cap (rules sections 10(d), 10(e) and 13(b)(i)): a scheduled amount after the holdback below $10 is not paid; one of exactly $10 is. A payable amount is then limited to heating_expense when the household reports a bill, so a primary fuel cost below $10 is paid in full. A household whose heat is included in rent and that reports no bill receives the payable amount uncapped, because rule 10(e) pays renters on the standard benefit formula: a single adult with $20,000 of wages whose gas heat is included in rent receives $1,550.85 x 0.45 = $697.8825 less the $70 holdback, $627.8825.
  • Before the cost cap, FY2026 scheduled awards run from $47.50 (coal at 0.10: $52.50 - $5) to $1,901 (fuel oil and kerosene at 0.80), so the $10 cutoff does not bind in FY2026. Plan section 2.6 (page 9) estimates $48 and $1,901.

Years covered

Model year Program year Guideline One-person limit
2026 FY2026, October 1, 2025 to September 30, 2026 2025 $35,829

The registry entry records verified_years: "2026". FY2027 benefits are not modeled. For model year 2027, the income limits match the 2026-2027 handout for one to five people ($35,858 for one person), but the model applies the FY2026 fuel standards and fractions. The FY2027 draft plan (section 2.6, page 9) estimates benefits from $50 to $2,252, against $48 to $1,901 for FY2026, and no FY2027 benefit matrix is posted on the LIHEAP Clearinghouse. Model-year 2027 awards are therefore unverified estimates; the draft's maximum is $351 (18%) above the FY2026 maximum. Years before 2026 are also unverified estimates.

Not modeled and source conflicts

  • Table 1 gives no rule for ratios between printed rows, such as 0.205. The model keeps the unrounded ratio and lets each printed ratio start its row, so a ratio between rows takes the earlier row. Households eligible only through the federal protection receive the fraction for their income over the larger denominator; the agency's payment method for those households is unverified.
  • Household size counts citizens and qualified noncitizens while every member's income counts, with no further proration. The SPM unit stands in for the rules' household of people who share heat (section 3(kk)).
  • The veterans exclusion applies once per SPM unit to total veterans_benefits. Section 8(a)(ii)(S) exempts service-connected disability benefits, including dependent and spouse benefits, up to 100% of poverty and does not say how to divide the exclusion among several recipients. The proxy also exempts other VA income up to the guideline, which can understate countable income.
  • The plan and the rules differ on minor earnings, POWER and child support received, categorical eligibility and lump sums. The model follows the plan for minor earnings, POWER, child support received and categorical eligibility (see Eligibility), and the rules for lump sums. The rules list POWER and child support documents among income verification sources (section 9(g)(ii)(B)) without saying they count. Rule 8(a)(iii) deducts child support paid "from earnings" without saying whose; the model uses the payer's own earnings. source_conflicts/candidates.yaml records these five choices as us-wy:lieap-plan-vs-rules-income-items (state: open).
  • W.S. 42-2-501(c) directs the state plan to provide eligibility for households with income up to the lesser of 215% of the poverty level or 60% of state median household income. The clause read "greater of" until 2017: DFS's 2016 statute clean-up request asked to remove the 215% clause because the program uses 60% of SMI, and 2017 SF0063 (Enrolled Act 43), effective July 1, 2017, struck "greater", inserted "lesser" and changed "state median income" to "state median household income". Under "greater of", 215% of the 2025 guideline would exceed both 60% of SMI and the federal maximum from four people ($69,122.50 against $68,902); under "lesser of", a 60%-of-SMI plan always meets the statute. Rules sections 3(oo) and 7(a)(ii), adopted in 2012 under the "greater of" text, call the statutory standard the maximum income. The FY2026 plan sets 60% of SMI for every household size, and the model reads the statute as a coverage minimum that the plan meets. For one to three people, 215% of the 2025 guideline ($33,647.50, $45,472.50 and $57,297.50) is below 60% of SMI ($35,829, $46,853 and $57,877), so the model treats households between those amounts as eligible. source_conflicts/candidates.yaml lists this reading as us-wy:lieap-income-limit-statute-lesser-of, with follows: statute.
  • DFS publishes fuel cost standards for six fuels, while the DFS LIEAP page and the 2026-2027 handout say the seasonal benefit also serves other fuels. The model pays other fuels on the wood standard, the closest published worksheet; DFS's amount for those fuels is not published.
  • With heat included in rent and no reported bill, the model pays the standard formula without a cap. Rule 13(b)(i) treats payment above the actual primary fuel cost as an overpayment, so the model overstates the payment when the prorated heating share in the rent is below the formula amount. Callers who know the share can report it as heating_expense, which restores the cap.
  • Income details the inputs cannot represent: annual Social Security and retirement inputs cannot separate retroactive lump sums or exempt reimbursements; contract, mortgage-sale and royalty income have no inputs; infrequent receipts under $30 a month and sponsor-income deeming (section 8(a)(i)(A)(II)) are not modeled. Callers can supply wy_lieap_countable_income directly when these adjustments are known.
  • Eligibility facts without inputs: the work registration that DFS's September 2026 instructions require of unemployed members aged 18 to 49; the section 7(b) exclusions for a minor living alone, a person on strike, Northern Arapaho and Eastern Shoshone members living on the Wind River Reservation (served by a separately funded program), residents absent in winter and commercial accounts; and the section 8(b)(ii) arrangements (dormitories, subsidized institutions and group homes, nursing homes, employer-provided heat and heat paid by someone outside the household).
  • Application timing, priority intake, vendor payment and benefit adjustments are not modeled.
  • This PR models regular heating assistance only. Crisis assistance, cooling, weatherization and heating-equipment repair are out of scope.

Test plan

  • 5 YAML files with 203 cases under policyengine_us/tests/policy/baseline/gov/states/wy/dfs/lieap/ (wy_lieap.yaml 156, wy_lieap_countable_income.yaml 24, wy_lieap_income_limit.yaml 15, wy_lieap_eligible.yaml 5, wy_lieap_household_size.yaml 3). Cases 1 to 96 of wy_lieap.yaml reproduce every visible Table 1 benefit on the six fuel worksheets. Cases 148 to 150 set one-person FY2026 wages a cent below, exactly at and a cent above every printed row start; in Case 149 each start takes its own row, from $1,782 at 0.21 to $0 at the $35,829 limit. The income-limit cases match the HHS FY2026 table for one to eight and ten people ($95,084 for eight, $99,218 for ten) and the 2026-2027 handout for one to five. At zero income, Cases 135 to 137 pay kerosene, solar and other fuels $1,901, $1,233.3976 and $882 on the fuel oil, electricity and wood standards. Case 155 pays a single adult with $20,000 of wages and a $1,500 kerosene bill $1,069 (0.45 of the $2,640 standard, less $119), and Case 156 pays the same adult $627.8825 when gas heat is included in rent and no bill is reported. Countable-income Case 23 gives self-employment, SSTB, farm operations, partnership or S corporation, workers' compensation, disability and estate income distinct amounts ($11,800 in total), and Case 24 shows that a $2,434.80 Part B premium above $1,000 of Social Security leaves $10,000 of wages counted in full. wy_lieap.yaml Case 153 counts a $40,000 military Survivor Benefit Plan annuity, above the $35,829 one-person limit. Case 154 counts $37,000 of Social Security less the $2,434.80 Part B premium ($202.90 x 12), $34,565.20, which is within the $35,829 limit and above 0.86 of it, so it pays 10% of the $1,550.85 natural gas standard: $155.085 - $16 holdback = $139.085. The other expected values are hand computed; most wy_lieap.yaml cases show the arithmetic in a comment. CI passed the five Wyoming files at 5c968f998b; the review fixes in 5403e87 were not run locally, and 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: pending. source_conflicts/candidates.yaml records three backlog items: the W.S. 42-2-501(c) reading (us-wy:lieap-income-limit-statute-lesser-of) and the federal-floor reading (us-wy:lieap-income-floor-vs-smi-limit), both follows: statute and unreviewed, and the plan-versus-rules income choices (us-wy:lieap-plan-vs-rules-income-items, state: open). This PR adds no rulespec-us register entry and no marker yet.
  • make format
  • Changelog fragment in changelog.d/

axiom: TheAxiomFoundation/rulespec-us#1906 queued

🤖 Generated with Claude Code

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
@hua7450
hua7450 marked this pull request as ready for review October 24, 2026 03:00
@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 (352faf3).
⚠️ Report is 710 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main    #10346   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         6    +2     
  Lines           76       121   +45     
  Branches         2         2           
=========================================
+ Hits            76       121   +45     
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.

@DTrim99

DTrim99 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Add Wyoming LIHEAP regular heating assistance

PR #10346 (author: hua7450), head 5c968f998b. This is a first review. The PR adds Wyoming's Low Income Energy Assistance Program (LIEAP) regular heating benefit for FY2026 (model year 2026). It includes:

  • 12 parameter files and 6 variables (no new inputs);
  • 5 test files (198 cases: wy_lieap 154, countable income 22, income limit 14, eligible 5, household size 3);
  • a programs.yaml entry (coverage line and state block);
  • two source_conflicts/candidates.yaml entries;
  • a changelog fragment.

The PR has no reviews and no comments apart from Codecov. It touches no partner test file.

Path prefixes:

  • P/ = policyengine_us/parameters/gov/states/wy/dfs/lieap/
  • V/ = policyengine_us/variables/gov/states/wy/dfs/lieap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/wy/dfs/lieap/

Sources read for this review:

Summary

What is right. Most of the program is encoded carefully:

There are two critical findings:

  • C1. Band edges. The edges contradict the printed Table 1 at all 15 printed band starts (.21, .26, ..., .86 and 1.00), and 30 test expectations pin the wrong amounts. At exactly 1.00 the head pays $238 for oil, where the "1.00 +" row pays $0. The fix is one character (<= to <).
  • C2. Income limits. The head floors once, so sizes 8-11 come out $1 above HHS's mandatory FY2026 figures (size 8: $95,085 against $95,084), and Case 9 pins $95,085. main's shared liheap_smi_limit helper reproduces the HHS table.

There are five should-address items:

  • S1. Kerosene and other fuels. KEROSENE (and OTHER) households with a bill get $0. Rule 3(hh) lists "diesel, oil" fuel types, DFS serves fuels beyond the six worksheets, and on main a kerosene bill is the fuel_oil_expense.
  • S2. Heat in rent. Heat-in-rent households in main's convention (the flag set, no separate fuel bill) get $0. Rules 3(kk), 8(b)(i)(B) and 10(e) and plan 2.3 serve them on the standard formula.
  • S3. Untested entries. 7 of the 20 income-source entries, and the Social Security floor, have no test that would fail if they were dropped.
  • S4. Rules links. Every rules reference links the Secretary of State's search form, which shows no rule text. Four parameters have no other reference.
  • S5. The 215% candidate. The us-wy:lieap-income-limit-statute-lesser-of candidate says "No amendment history ... was found", but 2017 SF0063 changed "greater of" to "lesser of" at DFS's request. That history supports the PR's reading, yet the candidate is labelled follows: conflicting-source, which the backlog defines as a call for a model change.

There are also six suggestions:

  • G1: backlog candidates for the plan-versus-rule choices.
  • G2: a note that wy_ssp is exempt.
  • G3: SOLAR.
  • G4: FY2027.
  • G5: internal-process wording.
  • G6: merge housekeeping.

Status.

  • CI: 33 pass, 3 skipping and 1 failure. The failure is an infrastructure loss of the hosted runner in a contrib shard, so a re-run is needed.
  • Branch: 9 commits ahead of main and 57 behind. It conflicts with main in programs.yaml and source_conflicts/candidates.yaml (branch note).

Critical (must fix)

C1. The entitlement-band edges contradict the printed Table 1 at every printed band start, and 30 test expectations pin the wrong amounts

  • Where:
    • V/wy_lieap.py:39-46 builds a ceiling of limit × threshold for each threshold in .21, .26, ..., .86 and 1.00. It then selects the fraction with income <= ceiling, so each threshold is an inclusive upper bound of the higher-paying band.
    • P/payment/entitlement_fraction.yaml:184-189 (comment) records this as an "approved convention". The comment says the positive band at exactly 1.00 "differs from the printed zero".
  • The source. Every worksheet's Table 1 (for example Heating Oil 25-26, B22:F37) prints these rows: "0 - .20" 0.80, ".21- .25" 0.75, ..., ".86 - .99" 0.10 and "1.00 +" 0.0.
    • Rule 10(c) makes the table binding: "Payment is based on an entitlement as specified in the LIEAP State Plan". Rule 3(cc) defines the entitlement fraction as "the percentage of fuel cost the household is entitled to receive".
    • The gaps between rows (for example .20 to .21) need a convention. But whether the ratio is truncated or rounded to two decimals, a ratio of exactly .21 is in the ".21- .25" row, and exactly 1.00 is in the "1.00 +" row.
    • The head puts every printed band start in the band above it. The body concedes this ("at a ratio of exactly 0.21 the model pays 0.80 where the table pays 0.75, and at exactly 1.00 it pays 0.10 where the table pays zero").
  • Effect (FY2026, one person, limit $35,829, fuel oil, bill $3,000):
Countable income Ratio Table 1 row Rule award Head
$7,524.09 (Case 149, person 1) exactly .21 .21-.25 → 0.75 1,980 − 198 = $1,782 $1,901
$30,812.94 (Case 149, person 14) exactly .86 .86-.99 → 0.10 264 − 26 = $238 $356
$35,829 (Case 149, person 15) exactly 1.00 1.00 + → 0.0 $0 $238
  • Pinned by tests. T/wy_lieap.yaml Cases 97, 99, 101, ..., 123 (oil at .21 through .86) and Case 125 (oil at 1.00, $238) pin the head's amounts, and so does every entry of Case 149 (line 2169). That is 30 expectations in all.
  • Severity: critical. These are wrong results in the claimed year against the binding benefit table. A convention that matches every printed row exists, and documenting the departure does not make it right. The review rules count a wrong result in a claimed year as critical however rare the case.
  • Fix:
    • In V/wy_lieap.py:44, change income <= ceiling to income < ceiling. Keep the cent-precision ceilings. Each printed start then begins its band (lower-inclusive, the truncation reading that Add Louisiana LIHEAP regular heating assistance #10429 and Add New Mexico LIHEAP regular heating assistance #10431 used), and income at the limit gets the "1.00 +" zero.
    • Case 151's floor household is unchanged (113,900 < 114,015 gives 0.10, $238).
    • Re-pin Cases 97-125 (odd) and Case 149 to the table rows: $1,782, $1,663, ..., $238 and $0. Cases 98-126 (even), 148 and 150 do not change.
    • Update the parameter comment, the wy_lieap documentation, the body's "Not modeled" bullet, Axiom interpretation 1 and companion test 4.

C2. A single floor puts the FY2026 limits for sizes 8-11 $1 above HHS's mandatory figures, and a test pins the wrong value

  • Where:
    • V/wy_lieap_income_limit.py:24 computes floor(smi(size) × 0.6) from the unrounded four-person SMI ($114,837).
    • T/wy_lieap_income_limit.yaml:65 (Case 9) expects $95,085 for eight members.
  • Sources:
    • The order. The Clearinghouse page the code cites gives the method: "60 percent of each state's estimated median income for a 4-person family is multiplied by the following percentages ... For each additional family member above six persons, add 3 percent". So the base is the published four-person figure of $68,902.
    • The values. HHS LIHEAP IM 2025-02 Attachment 4 is "Mandatory Use in LIHEAP for FY26". On page 6 it prints Wyoming sizes 7-12 as $93,017, $95,084, $97,151, $99,218, $101,285 and $103,353.
    • The arithmetic. 68,902 × 1.38 = 95,084.76, floored to $95,084. The head computes 114,837 × 1.38 × 0.6 = 95,085.04, floored to $95,085. Sizes 9-11 are also $1 high ($97,152, $99,219 and $101,286).
    • FY2027 (unclaimed). The single floor also gives $91,026 for size 6 in 2027. Flooring the four-person amount first (68,959 × 1.32 = 91,025.88) gives $91,025, the IM 2026-01 figure according to rulespec-us#1906.
  • main already does this. The shared helper liheap_smi_limit in policyengine_us/variables/gov/hhs/hhs_smi.py (Share one HHS SMI helper for LIHEAP income limits #10019) floors the four-person amount first, "which reproduces the published tables". Every size 1-7 value and every 2027 handout value is the same under both methods.
  • Effect: an eight-person household with countable income of $95,085 is eligible in the head and ineligible under the HHS limit. The same holds at $97,152 (size 9), $99,219 (size 10) and $101,286 (size 11).
  • Severity: critical, because the value mismatch is confirmed against the source and pinned by a test. It is tiny in dollars, and the fix is one line.
  • Fix:
    • Use liheap_smi_limit(size, state, p.smi_rate, period, parameters), keeping the where(size > 0, ...).
    • Re-pin Case 9 to $95,084 and add a size-10 case ($99,218).
    • Drop the "numerical inference" comment and update Axiom interpretation 5 and the required-outputs row.

Should address

S1. KEROSENE and OTHER households with a heating bill get $0, although the rules list oil as a fuel type and DFS serves fuels beyond the six worksheets

  • Where:
    • P/payment/fuel_cost.yaml:13-14 and :23-24 set KEROSENE and OTHER to 0. The comment says this is "no verified mapping", not ineligibility.
    • wy_lieap_eligible passes these households, and the award is then $0.
    • T/wy_lieap.yaml Cases 135 and 137 pin $0 with a $5,000 bill.
  • Sources:
    • Fuel types. Rule 3(hh): "Fuel types are natural gas, electricity, propane, coal, diesel, oil, and wood." The heating-oil worksheet is titled "Diesel Heating Oil", and kerosene is a No. 1 distillate fuel oil.
    • The input convention on main. heating_expense reads fuel_oil_expense for both FUEL_OIL and KEROSENE, so main treats a kerosene bill as a fuel-oil bill.
    • Vulnerability. Rule 8(b)(i)(A) and (C) make a household vulnerable when it is billed for, or pays, "home heating fuel costs", with no fuel requirement. Plan 2.3 (p. 9): "Invoices for unregulated fuel types are eligible for payment beginning October 1, 2025."
    • DFS. The DFS LIEAP page says the program "works with many types of fuel, such as natural gas, electricity, propane, coal, wood, and more". The 2026-27 handout says "and other fuel types".
  • Effect (hand-traced; FY2026, one person, wages $20,000, kerosene heat, fuel_oil_expense $1,500): the ratio .5582 gives 0.45 in both the head and the C1 fix.
    • Head: $0.
    • Oil standard: 2,640 × 0.45 = 1,188, less the 119 holdback = $1,069.
  • Precedent: Maine Add Maine HEAP Fuel Assistance #10437 S3 (an OTHER-fuel household with its own bill at $0 was rated should).
  • Severity: should. A household the state serves gets $0 in the claimed year, with existing inputs, and tests pin it.
  • Fix:
    • Map KEROSENE to the fuel-oil standard ($2,640), or cite a DFS statement that kerosene is not paid.
    • For OTHER (which covers pellets on main), either map it to the wood standard as the closest worksheet, with a note, or keep $0. If you keep $0, say in the body and the documentation that DFS serves other fuels at an amount the model cannot recover.
    • Re-pin Cases 135 and 137, and update Axiom interpretation 9.

S2. Heat-in-rent households in main's convention get $0, although the rules and plan pay them on the standard formula

  • Where:
    • V/wy_lieap_eligible.py:34-35 requires heating_expense > 0.
    • On main, a heat-in-rent household is represented by heat_expense_included_in_rent = true with no separate fuel bill, and heating_type may be UNSPECIFIED. The heating_type docstring says the flag "bypasses the expense cap, so the fuel type is not needed".
    • So the flag alone never qualifies, even with a known fuel. Case 139 pays only because it enters heating_expense: 500 directly.
  • Sources:
    • Household. Rule 3(kk): "The energy purchase may be in the form of rent."
    • Vulnerability. Rule 8(b)(i)(B): a household is vulnerable when "Rent includes a prorated home heating fuel cost on a monthly basis and applicant can prove same with rent receipts and or lease agreement."
    • Benefit. Rule 10(e): "Renters are considered to pay the same heating costs as other households. Therefore, they receive assistance based on the standard benefit formula."
    • Plan 2.3 (p. 8) answers "No" to "additional/differing eligibility policies for ... Renters with utilities included in the rent?"
  • Effect (hand-traced; FY2026, one person, wages $20,000, heating_type NATURAL_GAS, heat_expense_included_in_rent true, no gas bill):
    • Head: heating_expense = gas_expense = 0, so the household is ineligible: $0.
    • Rule: standard formula 1,550.85 × 0.45 = 697.88, less the 70 holdback = $627.88, limited by 13(b)(i) to the prorated heat share where that is known.
  • Precedent: wave consistency (households the state serves excluded: Add New Mexico LIHEAP regular heating assistance #10431 S1, Add Maine HEAP Fuel Assistance #10437 S3, Add Tennessee LIHEAP regular energy assistance #10430 S1).
  • Severity: should. The body documents the convention, but it excludes a group the rules expressly serve.
  • Fix:
    • Make the household responsible when heat_expense_included_in_rent is true, as well as when heating_expense > 0.
    • In wy_lieap, cap at heating_expense when one is supplied, and otherwise pay the standard formula for the known fuel. This is main's heat-in-rent convention, and it is the cap the 13(b)(i) prorated share would set if known. UNSPECIFIED fuel stays at $0, which the wave accepts.
    • Add a case with the flag and a known fuel and no bill, and update the body row and Axiom interpretation 12.

S3. Seven of the 20 income-source entries, and the Social Security floor, have no test that would fail if they were dropped

  • Where: P/income/earned_sources.yaml:4-8, P/income/unearned_sources.yaml:4-18 and V/wy_lieap_countable_income.py:55.
  • Untested entries (no case gives them a counted positive value):
    • Earned (4 of 5):
      • sstb_self_employment_income, farm_operations_income and partnership_s_corp_income never appear.
      • self_employment_income appears only for a 17-year-old, whose earnings are excluded (countable Case 2), and as −$5,000, which floors to 0 (countable Case 4). Dropping it fails nothing.
    • Unearned (3 of 15): workers_compensation, disability_benefits and estate_income never appear.
  • Social Security floor. max_(social_security - premium, 0) is never tested with a Part B premium above Social Security. Removing the floor would let the premium cut other income, and no case would fail.
  • Tested:
    • Sources: wages, plus the 11 unearned sources in countable Case 17 (ssi, pension, retirement distributions, railroad, survivor, total_unemployment_compensation through unemployment_compensation, general assistance, alimony, rental, farm rent and dividends). military_retirement_income is tested by Cases 152-153.
    • Floors: the earned and unearned per-source floors (countable Case 4) and the support floor (Case 5).
  • Severity: should, as in Add Nevada Energy Assistance Program Fixed Annual Credit #10432 S1, Add Wisconsin WHEAP regular heating benefit #10434 S1 and Add Tennessee LIHEAP regular energy assistance #10430 S3 (the mutation rule).
  • Fix:
    • Add one countable-income case that gives each of the seven sources a distinct positive amount for a member aged 18 or over.
    • Add a case at age 70 with social_security of $1,000 and wages of $10,000. The expected value is $10,000, since the $2,434.80 premium cannot reduce the wages.
    • Add both to the rulespec-us#1906 companion tests.

S4. Every rules reference links the Secretary of State's search form, which shows no rule text

  • Where: href: https://rules.wyo.gov/Search.aspx?mode=7. It is the only reference in four parameters:

    • P/income/gift_monthly_threshold.yaml:11;
    • P/income/interest_monthly_threshold.yaml:11;
    • P/income/veterans_fpg_rate.yaml:15;
    • P/payment/minimum_payment.yaml:12.

    It is also the second reference in earned_income_min_age, earned_sources, unearned_sources and fpg_year_lag, and it appears in every variable's reference.

  • The problem. The URL opens an empty search form, so the reader cannot see the $30, the $10 or the 100% values without re-running the search. The body cites "PDF pages 2 to 7, 10 to 13 and 15 to 16", so a PDF exists, but no reference links it.

  • Severity: should (anchors that do not show the value; brief and CLAUDE.md "Parameter and variable references").

  • Fix: link the Chapter 1 rule PDF itself with a file-page anchor (and a Wayback capture, since the site serves files through a session-based handler). Alternatively, use the stable LII section pages, for example § 1-8 for 8(a)(i)(A), (ii)(D), (S) and (U), and § 1-10 for 10(d).

S5. The 215% candidate misstates the statute's history, and its follows label contradicts the PR's own reading

  • Where:
    • source_conflicts/candidates.yaml (head lines 5891-5930) gives the reading as follows: conflicting-source and says "No amendment history for the clause was found".
    • The body ("no amendment history was found") and Axiom interpretation 4 repeat this.
    • P/smi_rate.yaml:2-4 (comment).
  • The history.
    • Until 2016, W.S. 42-2-501(c) read "do not exceed the greater of" 215% of poverty or 60% of "state median income" (2010 text; Justia 2016 is the same). The 2016 DFS memo quotes that text and asks to drop the 215% clause because "We use 60% of state median income".
    • The 2017 DFS bill, SF0063 (Enrolled Act 43), then struck "greater" and inserted "lesser". It also changed "state median income" to "state median household income" (enrolled act, p. 7: "which do not exceed the greater lesser of"). Justia shows "lesser" from 2017 on.
    • Rules 3(oo) and 7(a)(ii), effective 2012, were written under the "greater of" text.
  • Why it matters.
    • The history supports the PR. Under "greater of", a coverage-minimum statute would require coverage above 60% of SMI for large households (215% of the 2025 guideline exceeds 60% of SMI from size 4). That exceeds the federal maximum, which is why (d)(ii) existed. Changing to "lesser of" at DFS's request makes a 60%-of-SMI plan always satisfy the minimum, which was DFS's stated aim. DFS has used 60% of SMI for every size since then (FY2026 plan 2.1; FY2027 draft 2.1). So the history is the strongest support for the PR's coverage-minimum reading, and the PR says none exists.
    • The label says the opposite. The candidates.yaml header defines conflicting-source as "against the statute; the 2026-10-19 rule calls for a model change". By the PR's own reading, the code follows the statute and the plan meets it. As labelled, the backlog tells maintainers the code violates W.S. 42-2-501(c) and must change.
  • Severity: should (misleading documentation in a public register, and a missed authority on a disputed reading).
  • Fix:
    • Cite 2017 Wyo. Sess. Laws, SF0063 (Enrolled Act 43) in the candidate's sources and note.
    • Set follows to statute and restate the readings: the statute as a coverage minimum since 2017, against rules 3(oo)/7(a)(ii) adopted under the pre-2017 text.
    • Correct the body, the smi_rate.yaml comment and Axiom interpretation 4.

Suggestions

G1. Record the plan-versus-rule choices in the backlog.

  • The choices. The PR follows plan 1.9 over the rules in four places:
    • under-18 earnings (the rules exempt only under-14 earnings and full-time students under 18; 8(a)(ii)(A));
    • POWER and child support received (the rules count all non-exempt income; 3(nn));
    • categorical eligibility (rule 7(a)(i));
    • lump sums, where it follows the rules over the plan's check (8(a)(ii)(L)); the plan's lump-sum box names lottery winnings, which rule 9(g)(ii)(B) lists as income evidence.
  • Child support paid. It comes off only the payer's own earnings (countable Case 19). Rule 8(a)(iii) says only "deducted from earnings".
  • Fix: add us-wy: candidates or a body table that cites both sides. Precedent: Add Tennessee LIHEAP regular energy assistance #10430 G2, Add New Mexico LIHEAP regular heating assistance #10431 G2 and Add Maine HEAP Fuel Assistance #10437 G4.

G2. Item 17: wy_ssp is correctly left out, so say why.

  • Why it is out. Rule 8(a)(ii)(U) exempts "The optional State Medicaid Supplement Benefit". Wyoming's $20 State Supplemental Payment (wy_ssp, on main under gov/states/wy/health/ssp/) is the supplement that EOM M1804 says is "required in order to receive federal match for the Medicaid program". So omitting it from P/income/unearned_sources.yaml is right.
  • Fix: add a comment so that a later item-17 sweep does not add it. Also correct Axiom interpretation 13 ("has no input"), since wy_ssp now exists.

G3. SOLAR pays $0.

G4. FY2027 (unclaimed and documented).

  • The gap. The FY2027 draft plan (2.6, p. 9) estimates $50-$2,252, against FY2026's $48-$1,901, so model-year 2027 awards for oil run about 18% low. No FY2027 matrix is posted on the Clearinghouse yet (404).
  • Fix: none needed now (NJ S3). Add the FY2027 workbook when DFS posts it.

G5. Internal-process wording in public files.

  • Where. Comments and documentation say:
    • "Approved convention" and "the stated extension of the user's pattern" (P/payment/entitlement_fraction.yaml);
    • "Approved assumptions" (P/income/veterans_fpg_rate.yaml);
    • "Income conventions approved October 6, 2026" (T/wy_lieap_countable_income.yaml:1);
    • "approved income bands" and "approved modeling assumption" in the variable documentation.
  • Fix: restate each as a source-based modeling assumption.

G6. Merge housekeeping.

Verified correct

Hand-checked expectations (26; all match the head, except those flagged under C1 and C2):

Test Hand computation Expected
wy_lieap Case 1 (coal, ratio 0) 525 × .8 = 420 − ROUND(42) 378
wy_lieap Case 2 (coal, .25) 393.75 − ROUND(39.375) = 393.75 − 39 354.75
wy_lieap Case 15 (coal, .95) 52.5 − ROUND(5.25) 47.5
wy_lieap Case 17 (oil, 0) 2,112 − 211 1,901
wy_lieap Case 25 (oil, .60) 1,056 − ROUND(105.6) = 1,056 − 106 950
wy_lieap Cases 33-47 (electricity) 1,712.997 × f − ROUND(0.1 × base), all 15 recomputed (e.g. .80: 1,370.3976 − 137) 1,233.3976 ... 154.2997
wy_lieap Cases 49-63 (gas) 1,550.85 × f − ROUND(0.1 × base), all 15 recomputed (e.g. .15: 232.6275 − 23) 1,116.68 ... 139.085
wy_lieap Case 66 (propane, .75) 975 − ROUND(97.5) = 975 − 98 877
wy_lieap Case 82 (wood, .75) 918.75 − ROUND(91.875) = 918.75 − 92 826.75
wy_lieap Case 97 (oil, exactly .21) head band .80; Table 1 row .21-.25 gives 1,782 (C1) 1,901
wy_lieap Case 125 (oil, exactly 1.00) head band .10; Table 1 "1.00 +" gives 0 (C1) 238
wy_lieap Case 129 adjusted 1,901 ≥ 10, then min(1,901, 9) 9
wy_lieap Case 143 12,000 − 2,400 = 9,600 (minor, POWER and support received excluded); 9,600 / 46,853 = .2049, .80 1,901
wy_lieap Case 144 60,000 − 21,150 = 38,850; .8292, .15; 232.6275 − 23 209.6275
wy_lieap Case 145 size 1 (citizen child); 20,000 / 35,829 = .5582, .45; 236.25 − 24 212.25
wy_lieap Case 146 372 (> 360) + 200 + 0 (gifts at 360) = 572; electricity 1,233.3976 capped at the bill 1,000
wy_lieap Case 147 [209.6275; size 0; propane 936 passes the cutoff, capped at 9; CO] [209.6275, 0, 9, 0]
wy_lieap Case 151 guideline 15,650 + 16 × 5,500 = 103,650; floor 114,015; limit 68,902 × 1.65 = 113,688; 113,900 / 114,015 = .999, .10 [238, 0]
wy_lieap Case 152 36,000 > 35,829 and > 17,215 0
wy_lieap Case 154 37,000 − 202.90 × 12 = 34,565.20; .9647, .10; 155.085 − 16 139.085
income limit Cases 2-7 114,837 × {.312, .408, .504, .600, .696, .792}, floored 35,829 ... 90,950
income limit Case 8 68,902 × 1.35 = 93,017.7 (HHS $93,017) 93,017
income limit Case 9 HHS $95,084 (C2) 95,085
income limit Cases 10-14 (2027) floor(114,932 × .6) = 68,959 × {.52 ... 1.16} = handout 35,858 ... 79,992
countable Case 17 1,000 + 500 + 2,000 + 3,000 + 400 + 300 + 2,000 + 100 + 800 + 900 + 700 + 200 11,900
countable Cases 13 and 18 30,000 − 15,650; 60,000 − 21,150 14,350; 38,850

Batch checks:

  • 1. Plan and matrix.
    • Matrix. All 96 visible Table 1 cells reconcile with the workbook formulas.
    • Limits. The 60% of SMI table matches for sizes 1-6, and the handout matches for 2027 sizes 1-5. See C2 for sizes 8-11.
    • Timing. The component runs October 1, 2025 to September 30, 2026 (plan 1.1 and SF-424 p. 2), and the parameters start on 2025-10-01.
    • Registry. verified_years: "2026" is backed by the FY2026 matrix and SMI table.
  • 2. Income.
    • Gross. The plan checks gross income (1.8). The rules define earned income as "total before deductions" (3(w)), so Document disjoint health premium inputs and correct consumer treatment #10046 premiums are rightly not deducted.
    • Social Security. It is counted net of the computed Part B premium, which matches "Medicare deducted from SSA" (8(a)(ii)(U)) and plan 1.9 "Excluding MediCare deduction".
      • Part A. Premium Part A is rarely withheld from Social Security, because beneficiaries usually have premium-free Part A. Leaving it out matches the Iowa precedent for check-withheld rules.
      • RRB. For railroad annuitants the Part B premium comes out of the RRB check, which the rule ("from SSA") does not exempt.
    • Losses. They are floored per source and per person, and support paid is floored against the payer's earnings.
    • Period. Annual amounts stand in for monthly amounts, as documented.
  • 3. Backdating. Only 2026 is claimed. 2027 and earlier years are documented as estimates (G4).
  • 4. Arrangements.
    • Eligibility rules. There is no categorical eligibility (plan 1.4 "No") and no asset test (2.3 "No").
    • Renters. Subsidized renters are unaffected (10(e)), which Case 140 pins. Heat in rent is covered in S2.
    • NONE and UNSPECIFIED. NONE is not vulnerable. UNSPECIFIED pays $0, which the wave accepts.
    • The $10 cutoff. It is applied before the cost cap (Cases 129-131 pin the order). It cannot bind in FY2026, because the smallest scheduled award is $47.50.
  • 5. Tests. Periods are plain. The exact limit (eligibility Cases 1-2), the floor on both sides, sizes 0-8, mixed states (Cases 142 and 147) and cent-level ceilings are covered.
  • 6. Descriptions. All 12 follow the house template with the state's program name, as South Dakota's LIEAP does.
  • 7. References. Plan anchors p. 2 (funding period), p. 5 (1.9), p. 6 (SSA/Medicare and minor boxes), p. 8 (2.1) and p. 38 (17.3) show their values. The statute's #page 34-35 title is well formed. See S4 for the rules links.
  • 8. Wiring.
    • Registry. The programs.yaml block is complete.
    • Aggregate. No merged LIHEAP state feeds a household aggregate, so none is needed.
    • Gating. All variables are gated by StateCode.WY or wy_lieap_eligible.
  • 11, Integrate modeled state unemployment insurance into income flows #9558. The list reads total_unemployment_compensation, and no Python reads the raw input.
  • 12. IIJA. There is no supplement.
  • 13. Mutation. See S3 and C1. Every other branch is pinned: the floor denominator (Case 151 would pay $0 with the SMI denominator), the age cut, the thresholds and the veterans exclusion.
  • 14. Health premiums. None are deducted, which is right for the gross rule.
  • 15, NH Add New Hampshire state supplementation for 2026 #10156. Nothing state-gated is used as a key:
    • wy_lieap_household_size is used only arithmetically (fpg(max_(size, 1)), smi(size)).
    • p.fuel_cost[heating_type] has all 11 HeatingType keys.
    • Case 147 runs Wyoming and Colorado units together.
  • 16, Wire military retirement pay and survivors into federal and state tax (#10181) #10182 / Count military SBP annuities in state benefit income lists #10317. military_retirement_income is used (Cases 152-153).
  • 17. State SSP. wy_ssp is exempt under 8(a)(ii)(U), so omitting it is right (G2).
  • Count each Social Security benefit once in Pennsylvania CCW countable income #10408 pattern. social_security is read once, in Python, and no list names a component. survivor_benefits ("other than Social Security") and disability_benefits are non-SSA inputs.
  • Federal floor. 42 U.S.C. 8624(b)(2)(B) is applied with the 2025 guideline and a strict "less than".
  • Changelog. changelog.d/wy-liheap-wave2b.added.md is a top-level fragment.
  • Local runs. None. CI ran all five Wyoming YAML files green in the baseline state shards at this head, and the findings above rest on hand traces and source arithmetic.

Axiom line assessment

axiom: TheAxiomFoundation/rulespec-us#1906 queued is valid.

  • The issue. It is OPEN and labelled pe-parity. It is dispatch-ready: module paths, corpus citations and status, verbatim rule, plan, statute and matrix text, required outputs, and companion tests derived from the workbook and sources.
  • The blocker. The rules, workbook, SMI tables, handout and memo are missing from the corpus; the signed release has not been checked; there is no reviewed oracle revision; and billed runs need approval.
  • The match. It describes head 5c968f998b and the 198 cases (154/22/14/5/3), with total_unemployment_compensation and military_retirement_income in the lists.
  • After the fixes, refresh:
    • interpretation 1, companion test 4 and the benefit row (C1);
    • interpretation 5 and the limit row (C2);
    • interpretation 9 (S1);
    • interpretation 12 (S2);
    • the new companion tests (S3);
    • interpretation 4 (S5);
    • interpretation 13 (G2);
    • the head SHA and case counts.

CI status

gh pr checks 10346 at head 5c968f998b, re-checked at the end of this review: 33 pass, 3 skipping (the superseded run 40055719714) and 1 failure.

  • The failure. "Contrib tests / Full Suite - Contrib (states-shard-1)" failed after 50m1s (run 40056568351, job 120765973202).
    • The job's annotation reads: "The hosted runner lost communication with the server". The test step has no conclusion, and the log was never uploaded.
    • The job timeout is 60 minutes, so this was not a timeout. It is an infrastructure failure (a lost runner, possibly starved).
    • The PR adds no contrib tests or reforms. The same shard passed on sibling runs, for example Add Tennessee LIHEAP regular energy assistance #10430's run 40032551559.
    • This is not a finding. Re-run the job.
  • Coverage. All other baseline and contrib shards, the guard tests, the partner suite, microsimulation, Python shards and Codecov pass.

Branch status

Verdict: REQUEST_CHANGES

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Requesting changes: 2 critical (benefit-band edges contradict Table 1 at every printed band start; FY2026 income limits for sizes 8-11 are $1 above HHS's figures), 5 should. Full report in the comment above.

hua7450 and others added 2 commits October 27, 2026 15:41
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	policyengine_us/programs.yaml
#	source_conflicts/candidates.yaml
@hua7450

hua7450 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the review, David. The fixes are in 5403e87, and 459fa26 merges current main.

  • C1 (band edges). Fixed. wy_lieap.py line 61 now selects with income < ceiling, so each printed Table 1 start begins its row and income at the limit takes the "1.00 +" zero; the cent-precision ceilings stay. The entitlement_fraction.yaml comment and the wy_lieap documentation state the lower-inclusive reading, and the parameter cites rule 10(c). Cases 97 to 125 (odd) are re-pinned to the table rows, from $1,782 at .21 to $238 at .86 and $0 at 1.00, and Case 149 now reads $1,782, $1,663, ..., $238, $0. Even Cases 98 to 126, 148 and 150 keep their values under reworded names, and Case 151 is unchanged ($238 and $0).
  • C2 (limits for sizes 8 to 11). Fixed. wy_lieap_income_limit.py line 23 calls liheap_smi_limit inside where(size > 0, ...), the inference comment is gone, and the variable cites IM 2025-02 Attachment 4 (pages 3 and 6). Income-limit Case 9 is now $95,084, and new Case 15 pins size 10 at $99,218.
  • S1 (kerosene and other fuels). Fixed. In fuel_cost.yaml, KEROSENE takes the $2,640 oil standard (rule 3(hh), the "Diesel Heating Oil" sheet and heating_expense reading fuel_oil_expense), and OTHER takes the $1,225 wood standard as the closest worksheet, with a comment citing plan 2.3 and the DFS page. Cases 135 and 137 now pay $1,901 and $882, and new Case 155 is your kerosene example ($1,069). The body says DFS publishes no amount for other fuels.
  • S2 (heat in rent). Fixed. wy_lieap_eligible.py lines 43 to 46 accept heat_expense_included_in_rent as heating responsibility alongside a positive heating_expense, and wy_lieap.py lines 76 to 77 cap the award only when a bill is reported. UNSPECIFIED and NONE stay at $0. New Case 156 is your gas example: eligible, $627.8825. Case 139, with a reported $500 share, still pays $500.
  • S3 (untested entries). Fixed. New countable Case 23 gives the seven sources distinct amounts (1,000 + 2,000 + 3,000 + 4,000 + 500 + 600 + 700 = $11,800). New Case 24 pins the Social Security floor: age 70, wages $10,000, Social Security $1,000 and a $2,434.80 premium give $10,000. It enters the premium directly, because at that income the model's Medicare Savings Program pays it; Case 154 still covers the computed premium.
  • S4 (rules links). Fixed. Every Search.aspx?mode=7 reference in the parameters, variables and candidates now links the Cornell LII section page (sections 1-3, 1-7, 1-8, 1-9, 1-10 and 1-13), with the cited paragraph in the title or comment.
  • S5 (215% candidate). Fixed. us-wy:lieap-income-limit-statute-lesser-of now cites SF0063 (Enrolled Act 43, page 7), has follows: statute, states the two readings (the statute as a coverage minimum since 2017, against rules 3(oo) and 7(a)(ii) adopted under the "greater of" text) and drops "No amendment history". The smi_rate.yaml comment and the body give the same history, and smi_rate.yaml adds SF0063 as a reference.
  • G1 (plan-versus-rule choices). Adopted. New candidate us-wy:lieap-plan-vs-rules-income-items (state: open) cites both sides for under-18 earnings, POWER and child support received, categorical eligibility, lump sums and child support paid off the payer's own earnings.
  • G2 (wy_ssp). Adopted. unearned_sources.yaml lines 32 to 34 say that rule 8(a)(ii)(U) exempts the State Supplemental Payment (EOM M1804), and the body's "Not counted" row and Axiom interpretation 13 say the same.
  • G3 (SOLAR). Adopted. SOLAR takes the $1,712.997 electricity standard, and Case 136 now pays $1,233.3976.
  • G4 (FY2027). Documented. The body's Years covered section says FY2027 benefits are not modeled, gives the draft plan's $50 to $2,252 range and notes that no FY2027 matrix is posted.
  • G5 (internal wording). Fixed. The "approved" and "user's pattern" wording is gone from the parameters, variables and tests; each passage now states a source reading or a modeling assumption.
  • G6 (housekeeping). Done. Both earlier WY LIEAP candidates list their code paths and no longer say "Code not yet on main", and the merge keeps main's WY CCAP note. The Wayback CDX API has no capture of the FY2026 workbook, so none is linked; the Clearinghouse serves the file again.

The PR body and TheAxiomFoundation/rulespec-us#1906 are updated for 459fa26. I did not run the tests locally, so CI will check them.

@hua7450
hua7450 requested a review from DTrim99 October 27, 2026 19:43
@DTrim99

DTrim99 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

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

PR #10346 (author: hua7450), head 459fa26aa0. Round 1 reviewed 5c968f998b and requested changes (2 critical, 5 should, 6 suggestions). Since then the author has pushed:

  • 5403e873fd, the review fixes;
  • 459fa26aa0, a merge of main with two hand-resolved blocks.

The author's reply addresses every item. The PR now has 203 YAML cases (wy_lieap 156, countable income 24, income limit 15, eligible 5, household size 3), and it still touches no partner test file.

Path prefixes:

  • P/ = policyengine_us/parameters/gov/states/wy/dfs/lieap/
  • V/ = policyengine_us/variables/gov/states/wy/dfs/lieap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/wy/dfs/lieap/

Summary

All 13 prior findings are resolved. Every critical and should fix is pinned by a test that fails without it:

  • C1, band edges. Each printed Table 1 start now begins its row, and income at the limit takes the "1.00 +" zero.
  • C2, limits. The limit now uses main's liheap_smi_limit, which reproduces HHS IM 2025-02 Attachment 4 for sizes 8 and 10.
  • S1, fuels. Kerosene takes the oil standard and other fuels the wood standard.
  • S2, heat in rent. It now establishes heating responsibility, and the award is capped only at a reported bill.
  • S3, untested entries. The seven sources and the Social Security floor are each pinned.
  • S4, rules links. Every rules link now opens the Cornell LII section that holds the cited paragraph.
  • S5, the 215% candidate. It cites 2017 SF0063 and reads follows: statute.
  • G1-G6. All six suggestions are adopted or documented.

No new critical or should findings. I hand-checked every new or changed expectation (32 values), and all of them match. The fix commit opens no unpinned branch and adds no comment that trips the #10287 ratchet.

Merge resolutions. Both hand-resolved blocks are correct:

  • programs.yaml. It keeps main's AZ, IA and VA, and adds WY to the coverage line and after the VA block.
  • candidates.yaml. It keeps main's rewritten WY CCAP note, with no duplicate, and keeps all three WY LIEAP candidates intact.

Two suggestions remain:

  • N1: the new candidate's state: open names no request.
  • N2: stale "not run" lines in the body and the Axiom issue.

Status.

  • CI: all 35 checks pass at 459fa26aa0, including the contrib states-shard-1 that lost its runner in round 1. All 203 Wyoming cases passed in Baseline states-shard-1.
  • Branch: 11 commits ahead and 2 behind main. It merges cleanly.

Prior findings

Finding Status Evidence
C1 Band edges <= contradict Table 1's printed row starts; 30 expectations pinned wrong amounts Fixed V/wy_lieap.py:61 now selects with income < ceiling, and the cent-precision ceilings are kept (lines 56-59). T/wy_lieap.yaml Cases 97-123 (odd) re-pin to $1,782 ... $238, Case 125 (exactly 1.00) to $0, and Case 149 to [1782, ..., 238, 0]. Reverting to <= fails all 15 of those cases and every entry of Case 149. Cases 98-126 (even), 148 and 150 keep their values, and Case 151 is unchanged ($238 and $0). The P/payment/entitlement_fraction.yaml:2-9 comment now states the lower-inclusive reading and cites rule 10(c).
C2 A single floor puts sizes 8-11 $1 above HHS Fixed V/wy_lieap_income_limit.py:23 calls liheap_smi_limit (floor(114,837 x .6) = 68,902, then the size factor, floored). T/wy_lieap_income_limit.yaml Case 9 is $95,084, and new Case 15 is $99,218 (HHS Att. 4 p. 6). The old method gives $95,085 and $99,219 (114,837 x .6 x 1.44 = 99,219.17), so both cases fail on revert. The 2027 Cases 10-14 are unchanged.
S1 KEROSENE and OTHER households with a bill get $0 Fixed P/payment/fuel_cost.yaml:19-20 sets KEROSENE to $2,640, the oil standard (rule 3(hh) "diesel, oil"; the "Diesel Heating Oil" worksheet; heating_expense reads fuel_oil_expense for KEROSENE on main). :29-30 sets OTHER to $1,225, the wood standard as the closest worksheet, with a comment citing plan 2.3 (p. 9) and the DFS page. Case 135 now pays $1,901, Case 137 $882, and new Case 155 (my round-1 example, with a real fuel_oil_expense) $1,069. Reverting fails all three. The body states that DFS publishes no amount for other fuels.
S2 Heat-in-rent households in main's convention get $0 Fixed V/wy_lieap_eligible.py:43-46 accepts heat_expense_included_in_rent alongside heating_expense > 0. V/wy_lieap.py:75-77 caps the award only when a bill is reported. New Case 156 (gas, wages $20,000, flag set, no bill) asserts heating_expense 0, eligible, and $627.8825. It fails if either the flag or the conditional cap is reverted. Case 139 ($500 share) and Cases 129-132, 146 and 147 still pin the cap, and Cases 127-128 still pin that a unit with no bill and no flag is ineligible. The body and Axiom interpretation 12 note the overstatement when the prorated share is smaller.
S3 Seven untested source entries and the Social Security floor Fixed T/wy_lieap_countable_income.yaml:267 (Case 23) gives self_employment_income, sstb_self_employment_income, farm_operations_income, partnership_s_corp_income, workers_compensation, disability_benefits and estate_income distinct amounts, totalling $11,800, so dropping any one fails. These are separate inputs on main, so there is no double count. :290 (Case 24): age 70, wages $10,000, Social Security $1,000 and a $2,434.80 premium give $10,000; without the floor the result is $8,565.20.
S4 Rules references link only the rules.wyo.gov search form Fixed No rules.wyo.gov link remains in the PR's parameters, variables or candidates. Each now links the LII section page (§§ 1-3, 1-7, 1-8, 1-9, 1-10, 1-13) with the paragraph in the title or a comment. I confirmed that each page shows the cited text, for example § 1-10(c) "Payment is based on an entitlement as specified in the LIEAP State Plan", (d) the $10 minimum and (e) renters. The four parameters that had only the search form now show their values: § 1-8(a)(i)(A) and (a)(ii)(D) ($30), (a)(ii)(S) (100%) and § 1-10(d) ($10).
S5 The 215% candidate omits the SF0063 history and is labelled conflicting-source Fixed us-wy:lieap-income-limit-statute-lesser-of now cites SF0063 (Enrolled Act 43) and sets follows: statute. It restates both readings, notes that rules 3(oo)/7(a)(ii) were adopted under the "greater of" text, and drops "No amendment history". I checked the enrolled act: p. 7 has "which do not exceed the greater lesser of", p. 8 underlines "household", and p. 9 reads "This act is effective July 1, 2017". P/smi_rate.yaml adds the act (#page 7-8, well formed), and the body and Axiom interpretation 4 match.
G1 Record the plan-versus-rule choices Adopted The new candidate us-wy:lieap-plan-vs-rules-income-items (follows: conflicting-source, state: open) cites both sides for all five items. Its example checks out: 40,000 / 46,853 = .8537 gives .15, and 232.6275 − 23 = $209.63; counting the $8,000 of support gives $48,000, above the limit. See N1.
G2 Say why wy_ssp is left out Adopted P/income/unearned_sources.yaml:32-34; the body's "Not counted" row; Axiom interpretation 13.
G3 SOLAR pays $0 Adopted SOLAR takes the $1,712.997 electricity standard. Case 136 pays $1,233.3976.
G4 FY2027 Documented The body's Years covered section gives the draft plan's $50-$2,252 range and notes that no FY2027 matrix is posted.
G5 Internal-process wording Fixed No "approved" or "user's pattern" wording remains in the WY LIEAP parameters, variables or tests.
G6 Merge housekeeping Done Both earlier candidates list their code paths, with no "Code not yet on main". main's CCAP note is kept. The author reports no Wayback capture of the workbook; the Axiom issue records the Clearinghouse copy's SHA-256 from 2026-10-23.

New findings

Critical

None.

Should address

None.

Suggestions

N1. The new plan-versus-rules candidate is state: open but names no request.

N2. Stale "not run" lines.

  • The lines. The body's test plan says CI passed the Wyoming files at 5c968f998b and that the fixes "were not run locally". rulespec-us#1906 says round 2 "was not run locally".
  • The current state. CI has now passed all 203 cases at 459fa26aa0.
  • Fix: update both lines.

Verified

Hand-checked new and changed expectations (all match the head):

Test Hand computation Expected
wy_lieap Case 97 (oil, exactly .21) 2,640 x .75 = 1,980; 1,980 − ROUND(198) 1,782
Case 99 (.26) 1,848 − ROUND(184.8) = 1,848 − 185 1,663
Case 101 (.31) 1,716 − ROUND(171.6) = 1,716 − 172 1,544
Case 103 (.36) 1,584 − ROUND(158.4) = 1,584 − 158 1,426
Case 105 (.41) 1,452 − ROUND(145.2) = 1,452 − 145 1,307
Case 107 (.46) 1,320 − 132 1,188
Case 109 (.51) 1,188 − ROUND(118.8) = 1,188 − 119 1,069
Case 111 (.56) 1,056 − ROUND(105.6) = 1,056 − 106 950
Case 113 (.61) 924 − ROUND(92.4) = 924 − 92 832
Case 115 (.66) 792 − ROUND(79.2) = 792 − 79 713
Case 117 (.71) 660 − 66 594
Case 119 (.76) 528 − ROUND(52.8) = 528 − 53 475
Case 121 (.81) 396 − ROUND(39.6) = 396 − 40 356
Case 123 (.86) 264 − ROUND(26.4) = 264 − 26 238
Case 125 (exactly 1.00) 100,000 ≤ limit, so eligible; not < the 1.00 ceiling, so "1.00 +" pays 0 0
Case 135 (KEROSENE, ratio 0) 2,112 − ROUND(211.2) = 2,112 − 211, below the $5,000 cost 1,901
Case 136 (SOLAR, ratio 0) 1,370.3976 − ROUND(137.03976) = 1,370.3976 − 137 1,233.3976
Case 137 (OTHER, ratio 0) 980 − 98 882
Case 149 (one person, limit $35,829) Starts are 35,829 x .21 = 7,524.09, ..., x .86 = 30,812.94, x 1.00 = 35,829; each start takes its own row: .75 → 1,782 ... .10 → 238; at 35,829, "1.00 +" → 0 [1782, 1663, 1544, 1426, 1307, 1188, 1069, 950, 832, 713, 594, 475, 356, 238, 0]
Case 155 (KEROSENE bill $1,500, wages $20,000) heating_expense = fuel_oil_expense 1,500; income 20,000; limit 35,829; 20,000 < 20,064.24 (.56 start), so .45; 1,188 − 119 = 1,069, below the bill; the 110% floor ($17,215) does not bind 1,500; 20,000; 35,829; true; 1,069
Case 156 (gas, heat in rent, no bill) gas_expense 0, so heating_expense 0; the flag makes the unit eligible; .45: 1,550.85 x .45 = 697.8825 − ROUND(69.78825) = 697.8825 − 70, uncapped 0; 20,000; true; 627.8825
countable Case 23 1,000 + 2,000 + 3,000 + 4,000 (adult earnings) + 500 + 600 + 700 11,800
countable Case 24 max(1,000 − 2,434.80, 0) = 0; 10,000 + 0 10,000
income limit Case 9 (size 8) 68,902 x (0.52 + 5 x 0.16 + 2 x 0.03 = 1.38) = 95,084.76, floored (HHS $95,084) 95,084
income limit Case 15 (size 10) 68,902 x 1.44 = 99,218.88, floored (HHS $99,218) 99,218

The renamed cases (98-126 even, 148 and 150) keep their round-1 values, and those values are right under the new rule: a cent below a start stays in the preceding row, and a cent above stays in the row. The candidate examples ($238 at size 17; $34,000 within $35,829) and the body's opening example ($9,600 / $46,853 = .205, so .80 and $1,901) are consistent with the head.

Regression and new-branch checks:

  • Cap and eligibility. The cap moved from min_(adjusted, max_(expense, 0)) to where(expense > 0, min_(adjusted, expense), adjusted). A negative or zero bill without the flag is still ineligible (Cases 127 and 128). A heat-in-rent unit with UNSPECIFIED or NONE fuel is eligible but pays $0 through the zero standard and the $10 minimum, as the body and Axiom interpretation 12 state.
  • main's conventions. heat_expense_included_in_rent is an SPM-unit boolean on main, used the same way by the AL, AR, FL, IL, KS, KY, MA and MD LIHEAP formulas. heating_expense reads other_heating_fuel_expense for OTHER and the pre-subsidy electricity bill for SOLAR, which matches the new mappings.
  • NH Add New Hampshire state supplementation for 2026 #10156 pattern. fuel_cost still has all 11 HeatingType keys, and household size is used only arithmetically.
  • Ratchet. No added or edited comment in the PR's parameter or variable files matches the Tie source-conflict markers to the register shared with Axiom #10287 pattern. The only matches in changed files are main's own candidates.yaml header lines, which the scan does not cover (it covers variables, parameters and reforms). KNOWN_UNMARKED has no Wyoming entry.
  • References. Every new anchor shows its content:
    • plan 2.3 on p. 8 (renters with utilities in rent) and p. 9 (unregulated fuel types);
    • plan 1.4 on p. 5;
    • IM 2025-02 Att. 4 on pp. 3 and 6;
    • SF0063 on pp. 7-9;
    • LII §§ 1-3, 1-7, 1-8, 1-9, 1-10 and 1-13.

Batch checks (unchanged from round 1 unless noted):

Axiom

axiom: TheAxiomFoundation/rulespec-us#1906 queued is valid.

  • The issue. It is OPEN, labelled pe-parity, and was updated 2026-10-27 19:43 UTC. It is still dispatch-ready: module paths, corpus status, verbatim sources, required outputs and companion tests.
  • The match. It describes head 459fa26aa0 and the 203 cases (156/24/15/5/3).
  • Each fix is reflected:
    • C1 → interpretation 1, companion test 4 and the benefit row (each start begins its row; $0 at the limit);
    • C2 → interpretation 5, companion test 5 and the limit row (liheap_smi_limit, sizes 8 and 10);
    • S1 and G3 → interpretation 9 and companion test 8 (kerosene, solar and other fuels, with Case 155);
    • S2 → interpretation 12, companion test 9(c) and the eligibility and benefit rows;
    • S3 → companion test 14 (Cases 23 and 24);
    • S5 → interpretation 4, plus SF0063 among the sources;
    • G1 → interpretation 15;
    • G2 → interpretation 13 (wy_ssp).
  • The blocker. It is unchanged: sources missing from the corpus, signed release unchecked, no reviewed oracle revision, and billed runs need approval.
  • One stale line. "Round 2 was not run locally" (N2).

CI status

gh pr checks 10346 at head 459fa26aa0 (run 40571557709), re-checked at the end of this review: all 35 checks pass, with none pending or failing.

  • Contrib shards. All 9 pass. The last three (states-shard-1, states-shard-2 and other-shard-1) finished between 20:52 and 21:07 UTC.
  • Baseline shards. All 11 pass. Baseline states-shard-1 ran the five Wyoming files (203 cases) green.
  • Other checks. The guard tests and lint, the partner suite, Package and compatibility, Microsimulation, all six Rest Python shards, Quick Feedback and Codecov pass.
  • Rest (Python shard 3). It passes. main's Give the Social Security state backend the names Core 3.33.13 needs #10504 (Core 3.33.13 names for the Social Security state backend) is in this merge, so the test_social_security_input_state_machine NameError does not occur.
  • Round 1's contrib states-shard-1 failure. It was a lost hosted runner. The shard passed in this run (41 minutes), which confirms that the failure was infrastructure.

Branch

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. Both criticals and all five shoulds are fixed and pinned. Full report in the comment above.

# Conflicts:
#	policyengine_us/programs.yaml
@hua7450
hua7450 merged commit 54e5d3a into main Oct 27, 2026
35 checks passed
@hua7450
hua7450 deleted the wy-liheap-wave2b branch October 27, 2026 23:03
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 Wyoming LIHEAP regular heating assistance

2 participants