Skip to content

Add Missouri LIHEAP Energy Assistance - #10438

Open
hua7450 wants to merge 3 commits into
mainfrom
mo-liheap-wave1d
Open

hua7450 wants to merge 3 commits into
mainfrom
mo-liheap-wave1d

Conversation

@hua7450

@hua7450 hua7450 commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Adds Missouri LIHEAP Energy Assistance (EA), the one-time regular heating payment the Department of Social Services, Family Support Division pays for FY2026 and FY2027. The model:

Fixes #10428

  • counts citizens and qualified noncitizens in household size; other members are left out of the count, but their income still counts;
  • computes countable income from the October 2025 LIHEAP Policy and Procedure Manual (FFY2026 edition), with a 20% earned income deduction, children's earnings and disability payments excluded, Social Security net of the Part B premium, child support paid deducted and a $100 monthly medical deduction for an elderly or disabled applicant or spouse;
  • tests that income against Missouri's published 60% state median income limits, with the federal 110% poverty floor;
  • applies the $3,000 resource limit;
  • pays the published amount for the household's heating fuel ($153 to $495). A renter whose heat is included in the rent receives 8% of annual rent, up to that fuel's amount.

The Energy Crisis Intervention Program (ECIP), cooling, weatherization and emergency services are out of scope.

Regulatory authority

Eligibility

Requirement Source How modeled
Missouri residence 13 CSR (6)(A), (7)(A) defined_for = StateCode.MO
Citizens and legal permanent residents 13 CSR (6)(A), (8)(A); manual p.42-43 mo_liheap_household_size sums is_citizen_or_legal_immigrant; other members are left out of size, but their income counts (manual p.42-43); size 0 is ineligible
Income at or below 60% of SMI Plan 2.1; Appendix K; application p.1 mo_liheap_income_limit: liheap_smi_limit / 12, rounded to the nearest dollar, x 12. Reproduces all 20 FFY2026 rows and all 10 FFY2027 rows. The 2017 income ranges in 13 CSR (6)(D) and (14) are not applied (see the source notes below)
Federal 110% poverty floor 42 U.S.C. 8624(b)(2)(B) 2025 guidelines in FY2026, 2026 in FY2027; binds from household size 16 in both years. source_conflicts/candidates.yaml entry us-mo:liheap-110-percent-poverty-floor
Resources at most $3,000 13 CSR (2)(N), (6)(B); plan 2.3; manual p.40 spm_unit_cash_assets (bank, stock and bond assets)
Responsibility for heating costs 13 CSR (2)(M), (6)(C) has_heating_expense, or heat_expense_included_in_rent without subsidized housing
Subsidized housing 13 CSR (7)(D); plan 2.3; manual p.43 Ineligible when heat is included in the rent and the household receives_housing_assistance or is_in_public_housing; eligible with its own fuel bill
Coal Manual Appendix E (p.122), denial code O Coal-heated households are ineligible

Countable income

Item Source How modeled
Earned income Plan 1.9; manual p.32, 36 Wages and net self-employment, farm and partnership income, each floored at zero, less the 20% earned income deduction
Children's income Plan 1.9; manual p.38 (Earnings of Children); application p.4 Members under 18: earned income and short- and long-term disability payments (disability_benefits) are excluded; their Social Security and SSI count as SSA income. Members 18 or older have earnings counted whether or not they attend high school, GED classes or home school
Unearned income Plan 1.9; application p.5; manual p.32-34 Unemployment, strike benefits, SSI, Missouri SSP/SAB/Blind Pension (mo_ssp), pensions, military retirement (with survivor annuities), railroad retirement, rental and farm rent, alimony, child support received, VA benefits, workers' compensation, contributions from friends or family (financial_assistance); private short- and long-term disability for members 18 or older
Income of members left out as non-citizens Manual p.42-43 Counted like any member's income
Social Security Plan 1.9 ("Excluding MediCare deduction") Net of medicare_part_b_premium, floored at zero per person
TANF Plan 1.9 mo_tanf
Child support paid Manual p.36, 42; application Part 6; 13 CSR (9)(B)7 child_support_expense of every member is deducted. The manual deducts child support "paid by any household member" and calls members left out as non-citizens "ineligible household members", so their payments are deducted with their income counted
Medical deduction 13 CSR (2)(C), (2)(D), (6)(D)1; manual p.36, 48 $100 a month, once per household, when the applicant or spouse (tax-unit head or spouse) is 65 or older, or is disabled or blind and receives SSI, Social Security disability, Medicaid, a state supplementary payment (mo_ssp), veterans_benefits, railroad_benefits, social_security_dependents or social_security_survivors. With the disabled-or-blind requirement, the last four inputs stand in for VA and Railroad Retirement disability benefits and for disabled-adult-child and disabled-widow(er) benefits. They also include benefits a disabled member receives for other reasons (Social Security spousal, aged-survivor or child-in-care benefits, a railroad age-and-service annuity), which no input separates, so the deduction can reach some disabled members whose benefit is not paid for disability. The manual is silent on a spouse left out as a non-citizen; such a spouse does not qualify the household
Not counted Manual p.37-40; plan 1.9; 13 CSR 40-19.020(2)(N) Interest and dividends, capital gains and other lump sums, tax refunds, general assistance, student aid, loans, EITC, SNAP; retirement-account (IRA, Keogh, 401(k)) withdrawals, since those balances count as resources

Benefit

Primary heating fuel Payment
Natural gas $326
Propane (tank) $495
Electricity, solar $318
Fuel oil $326
Wood $219
Kerosene $153
Other fuel, unspecified $0

The same amounts appear in the October 2025 manual (Appendix K, p.129), the FFY26 Appendix K and the FFY2027 application. A renter whose heat is included in the rent receives 8% of annual rent (pre_subsidy_rent), up to the amount for the household's fuel (13 CSR 40-19.020(13); manual p.63).

Not modeled and source notes

Item Source Model treatment
Renter rate 13 CSR (13) sets "no more than eight percent"; the October 2025 manual, the FFY2024-FFY2026 plans and the draft FFY2027 plan describe 16% The regulation's 8% is applied (rule above manual and plan)
Rule income ranges and payment table 13 CSR (6)(D) and (14) (effective May 30, 2017) set monthly income ranges from 0 to 135% of the poverty level and payments that fall by range (natural gas $296 in range A to $203 in range F); the FFY2026 plan, Appendix K, the October 2025 manual and the 8-2026 application set 60% of SMI and one amount per fuel The FFY2026-FFY2027 agency values are applied. In FFY2026, a family of four with $39,936 of countable income (124% of the 2025 guideline) that heats with natural gas receives $326; the rule's range E pays $221. The renter share above follows the rule. source_conflicts/candidates.yaml entry us-mo:liheap-rule-income-ranges-and-payments
FFY2027 "+$170 per member above 10" Application p.1 The plan's 60% SMI amount is kept; at sizes 12-15 it is $1-2 a month below the shorthand (the federal floor governs from size 16). To be rechecked against the FFY2027 Appendix K once posted
Cylinder propane ($177) Appendix K Not reachable: heating_type has one propane value, paid at the tank amount
13 CSR (7)(B), (C), (E)-(H) exclusions; one EA per household per year; roomers, boarders and live-in attendants 13 CSR (7), (8) No inputs; not modeled
IRAs, Keoghs, deferred compensation and annuities in resources 13 CSR (2)(N) No asset inputs
Foster care payments, royalties, armed forces allotments, installment income Plan 1.9; manual No inputs
Part B premium paid without Social Security (e.g. Railroad Retirement); Part D premiums Manual p.36, 59 Not deducted. The October 2025 manual lists only the SMI (Part B) premium among deductions; page 59 mentions a Part D field on a screen
Civil Service Disability and Black Lung benefits for the medical deduction 13 CSR (2)(C); manual p.48 No separate inputs
Prior-month income 13 CSR (9)(B)5; manual p.30 Annual income stands in for 12 times the prior month
ECIP, cooling, weatherization, emergency services, supplemental EA Plan 1.1 Out of scope
Earlier years Parameter backfilling; unverified historical estimates

The October 2025 manual replaces the FFY2024 manual (updated 10/2023), which left out the income of members excluded as non-citizens and also excluded the earnings of a child in high school, GED classes or home school; the model follows the October 2025 edition.

Both Missouri entries in source_conflicts/candidates.yaml, us-mo:liheap-110-percent-poverty-floor and us-mo:liheap-rule-income-ranges-and-payments, are unregistered candidates, so the code carries no # Source conflict marker yet.

Test plan

52 YAML cases in 8 files cover:

  • every heating fuel, plus the renter share below and above the fuel cap, and a renter with an unknown fuel;
  • subsidized housing through either input;
  • income limit rows for FFY2026 sizes 1, 4, 16 and 20 and FFY2027 sizes 1 and 10;
  • income and asset boundaries, and the federal floor at size 16 in both years;
  • the 20% deduction; a 17-year-old's wages excluded and an 18-year-old high school student's wages counted; a minor's disability payments excluded while the minor's Social Security counts; a 25-year-old parent in GED classes whose $58,240 of earnings count ($46,592 after the deduction, over the $44,568 limit); per-source loss floors, Social Security net of Part B, child support paid and the medical deduction, including Medicaid as the only qualifying benefit;
  • mixed-status households, where an undocumented member is left out of household size but that member's earnings count and child support paid is deducted, and three end-to-end integration cases.

Expected values are hand-computed from the sources above. All 52 pass locally (policyengine-core test on the program folder, 2026-10-23, after the move to the October 2025 manual), as do the registry and source-conflict checks.

  • YAML tests whose expected values come from external sources
  • make format (ruff on changed Python)
  • Changelog fragment in changelog.d/
  • 52 YAML tests pass locally
  • CI passes

axiom: TheAxiomFoundation/rulespec-us#1899 queued

🤖 Generated with Claude Code

hua7450 and others added 2 commits October 23, 2026 18:11
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	policyengine_us/programs.yaml
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DTrim99

DTrim99 commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Add Missouri LIHEAP Energy Assistance

PR #10438 (author: hua7450), head 566343d074. This is a first review. The PR adds Missouri's LIHEAP Energy Assistance (EA), the one-time regular heating payment from DSS / Family Support Division, for FFY2026 and FFY2027. It includes:

  • 13 parameters and 7 variables;
  • 8 test files (52 cases);
  • a programs.yaml entry (coverage line and state list);
  • two source_conflicts/candidates.yaml entries;
  • a changelog fragment.

The PR has no comments yet and touches no partner test file.

Path prefixes:

  • P/ = policyengine_us/parameters/gov/states/mo/dss/liheap/
  • V/ = policyengine_us/variables/gov/states/mo/dss/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/

Sources read for this review:

Summary

What is right. The published FFY2026 and FFY2027 values are encoded correctly:

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

  • S1. Source hierarchy. The income test and payment table follow the agency documents over 13 CSR 40-19.020(6)(D) and (14), while the renter rate follows the rule over those same documents. The candidate entries leave out RSMo 660.100.2, mark follows: unknown and list no PR, and the renter-rate conflict has no entry of its own.
    • Example: a family of four with $50,000 (155% of the guideline) gets $326 at the head and $0 under the rule.
  • S2. Missouri pays the fuel the household selects. Missouri lets a household with more than one energy account choose which fuel EA pays, electric included, but the model pays only the primary heating fuel. It also bars a subsidized tenant with heat in the rent who pays an electric supplier.
    • Kerosene households with an electric bill get $153 instead of $318.
    • Such tenants get $0 instead of $318.
  • S3. The SMI premium is not deducted for railroad beneficiaries, although the manual allows it "to persons receiving SS and RRB". A railroad retiree with $37,000 gets $0 instead of $326.
  • S4. Rental and farm-rent losses offset wages. The unearned sum has no per-source floor. A worker with $45,000 of wages and a $5,000 rental loss gets $326 instead of $0.
  • S5. Untested sources. 10 of the 20 income-source entries and 5 of the 8 medical-deduction benefit entries never take a positive value in any test.

There are also five suggestions:

  • G1: cite the manual's page 44 for the citizenship proxy.
  • G2: fix the plan citation for interest and dividends, and record the plan-vs-manual choices.
  • G3: read the take-up-gated tanf.
  • G4: decide what an UNSPECIFIED heat-in-rent renter receives.
  • G5: add Wayback captures for the overwritten application URL.

Status.

  • CI: 27 of 27 pass. All 52 Missouri cases passed in states-shard-2.
  • Branch: 3 commits ahead of main and 41 behind; main moved during this review with the Iowa merge, Add Iowa LIHEAP regular heating assistance #10292. It merges cleanly.
  • Siblings: this PR adds MO 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. The income test and payment table follow the agency documents over 13 CSR 40-19.020(6)(D) and (14), while the renter rate follows the rule, and the backlog entries do not record the conflicts fully

  • Where:
    • P/eligibility/smi_rate.yaml sets 0.6, and P/amount.yaml sets one amount per fuel.
    • P/rent_share.yaml sets 0.08.
    • source_conflicts/candidates.yaml:3421-3490 holds us-mo:liheap-110-percent-poverty-floor and us-mo:liheap-rule-income-ranges-and-payments.
  • The rule.
    • (6)(D): "Each household must meet the specified income guidelines based on their household size, as established in section (14) of this rule."
    • (14): "EA payments are determined by household size, income range, and fuel source, using metrics established by the division. Monthly Income Federal Poverty ranges are A: 0-25% of the Federal Poverty Level ... E: 101-125% and F: 126-135%." The table follows: natural gas pays $296 in range A down to $203 in range F (PDF page 4).
    • (13): "no more than eight percent (8%) of their annual rental charge not to exceed the maximum EA benefit payment" (page 4).
  • The agency documents.
    • Plan 2.1 sets "State Median Income 60.00%" for all sizes, and 2.3 sets "16% of their annual rent, not to exceed the maximum allowed EA benefit" (p. 8; the same in FFY2024, FFY2025 and the FFY2027 draft).
    • Appendix K FFY26 and the 8-2026 application print 60% SMI limits and flat fuel amounts.
    • Manual page 63 gives "16% of their annual rent not to exceed the maximum EA benefit payment for their household size, income, and energy source" (p. 63).
  • The statute the candidate omits. RSMo 660.100.2 defines a "qualified individual household" as one "(1) ... whose combined household income is less than or equal to one hundred and fifty percent of the current federal poverty level or sixty percent of the state median income for the relevant household; and (2) ... also determined to be eligible for assistance under such program and related state programs of the Missouri department of social services." So the statute permits either limit and defers to the program's rules. It does not settle the rule-vs-agency question, but it is the statute, and the candidate says "No statute is supplied".
  • The project rule. CONTRIBUTING "Source conflicts" sets three principles:
    • "Statute first. When a statute conflicts with a form, instructions, a manual or stated agency practice, follow the statute";
    • "Regulations are law";
    • "The agency breaks true ties" only "where the text and the canons don't settle a reading".
  • What the PR does:
    • follows the agency documents over the rule for the income test and the payment table;
    • follows the rule over the same documents for the renter rate;
    • follows the manual's fuel-specific reading of the rule's renter cap, which is a reasonable agency tie-break.
    • The body and Axiom interpretation 2 say "Unlike interpretation 1, the rule governs here" but give no reason for the difference.
  • The backlog entries:
    • The rule-ranges entry has follows: unknown, although its note says "PE-US follows the plan, Appendix K, manual and application". It also has prs: [].
    • The renter-rate conflict appears only in that entry's note, with no entry of its own.
    • The floor entry says "no PR is open yet" and also has prs: [].
  • Effect (hand-traced, FFY2026, natural gas; the 2025 guideline for four is $32,150, so 135% is $43,402.50):
    • (a) Family of four with $50,000 of countable income (155%). Head: $50,000 ≤ $65,532, so $326. Rule: above range F, so $0.
    • (b) The PR's own example, $39,936 (124%). Head $326; the rule's range E pays $221.
    • (c) Renter rate, T/mo_liheap.yaml Case 2 (rent $6,000, propane). Head: 0.08 × 6,000 = $480. Agency: min(960, 495) = $495.
  • Severity: should. Authoritative sources conflict (the wave rates the state plan against the regulation should), and the PR applies the hierarchy one way for (14) and the other way for (13). It matches Add New Mexico LIHEAP regular heating assistance #10431 S2, where guidance was followed over the rule.
  • Fix: I recommend (b).
    • (a) Follow the rule: the (14) ranges, the range-based table, and the 8% rate with the manual's cap.
    • (b) Keep the agency values pending a ruling.
      • Add RSMo 660.100.2 to the candidate as the statute.
      • Mark the entry as following the agency documents against the rule, set state: open and list this PR.
      • Take the question to the project lead. The argument for the agency is (14)'s "using metrics established by the division".
      • Give the renter rate its own candidate: the rule's 8%, which is followed; the agency's 16%; and RSMo 660.115.2's 8%-or-$100 cap on state-fund payments.
      • In the body, either state why (14) delegates to the division and (13) does not, or apply the same source to both.
    • Either way, fix the floor entry's note and prs, and update Axiom interpretations 1–3.

S2. Missouri pays the fuel the household selects, electric included, but the model pays only the primary heating fuel and bars subsidized tenants who pay an electric supplier

  • Where:
    • V/mo_liheap.py:24-25 pays p.amount[heating_type].
    • V/eligibility/mo_liheap_eligible.py:36-42 accepts a subsidized household only through has_heating_expense. That is the primary fuel's bill, and it is always false with heat in the rent.
  • Sources:
    • Manual, EA (file p. 51): "DSS will only pay EA as a one-time payment towards one (1) fuel type per program year. ... If the household has multiple fuel types, they can choose the fuel type to pay when they apply. The EA payment will go towards the heating or cooling source that the applicant indicates on the LIHEAP Application under 'Fuel Source For My Home'." Electric is among the seven EA fuel types.
    • Application (p. 3): "DSS will only pay EA benefits for the fuel type selected under this section." Page 4 then asks for an "Additional Fuel Source For My Home".
    • Plan 2.5, Other (p. 9): "Households receiving LIHEAP assistance are able to select the fuel type for which they need assistance, including electric. While this is considered a heating program, payments made toward electric accounts may be utilized for cooling costs October through May."
    • Rule. (2)(E) defines the fuel source as "the fuel consumed in the operation of an appliance manufactured and used for the purpose of heating or cooling a household". (7)(D) bars subsidized housing "unless they are paying a home energy supplier or are billed by the landlord/housing authority for any out-of-pocket heating/cooling costs".
    • Plan 2.3 (p. 8): subsidized renters are "Only eligible if the client is paying an energy supplier out-of-pocket."
  • Effect (hand-traced from the code):
    • (a) Kerosene with an electric bill. Take T/mo_liheap.yaml Case 6 (FFY2027, kerosene with fuel_oil_expense $1,500) and add a $1,200 pre_subsidy_electricity_expense. Head: $153. Selecting Electric: $318.
    • (b) Purchased wood with an electric bill. $219 against $318.
    • (c) Subsidized tenant (2026, age 33, countable $14,000, receives_housing_assistance, gas heat in the rent, $1,080 electric bill). Head: has_heating_expense is false and the unit is subsidized, so $0. Rule and plan: the tenant pays an energy supplier, so it is eligible and selects Electric, $318.
    • (d) Unsubsidized renter with heat in the rent, rent $3,000 a year, who pays an electric bill. Head: min(240, 326) = $240. The renter can choose Electric instead, $318.
  • Tests: eligibility Cases 8–9 have no electric bill, so they stay correct after a fix.
  • 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:
    • Pay the largest amount among the fuels for which the household has its own positive bill: at least the primary fuel, plus Electric when pre_subsidy_electricity_expense is positive.
    • Treat a positive own electric bill as paying a home energy supplier for (7)(D).
    • For heat-in-rent renters with an electric bill, take the larger of the renter amount and the electric amount.
    • Decide and document whether a home with no heating but an electric bill qualifies. The manual's "heating or cooling source" and (2)(E) point to yes; (3)(A)'s "home heating" points to no.
    • Add cases (a)–(c), and update Axiom interpretations 14 and 16.

S3. The SMI (Part B) premium is deducted only from Social Security, although the manual allows it for railroad beneficiaries and for the full premium paid

  • Where:
    • V/income/mo_liheap_countable_income_person.py:36-42 nets medicare_part_b_premium from social_security alone, floored at zero per person.
    • railroad_benefits counts gross (P/income/unearned_sources.yaml:27).
    • The variable documentation, the body ("Part B premium paid without Social Security (e.g. Railroad Retirement) ... Not deducted") and Axiom interpretation 10 accept this.
  • Source: manual, "Income Deductions", SMI Premium (p. 36): "SMI is an additional health cost that is available to persons receiving SS and RRB. ... Allowable for all household members of a B or C case who are paying this premium." It sits beside the 20% deduction and child support as a deduction, not as a netting of the SSA check. Plan 1.9 ("Excluding MediCare deduction", p. 6) agrees for Social Security.
  • Effect (hand-traced, 2026):
    • (a) Single railroad retiree aged 70. railroad_benefits $37,000, Part B $2,434.80, natural gas.
      • Head: 37,000 − 1,200 (medical deduction) = 35,800, above $34,080, so $0.
      • Manual: 37,000 − 2,434.80 − 1,200 = 33,365.20, so eligible and $326.
    • (b) A premium larger than the check. T/income/mo_liheap_countable_income_person.yaml Case 5, person 2 (Social Security $1,800, pension $6,000, Part B $2,434.80). Head: max(1,800 − 2,434.80, 0) + 6,000 = $6,000. Manual: the member pays the full premium, so 7,800 − 2,434.80 = $5,365.20.
  • Severity: should, as in the wave's Medicare precedent (Add Virginia EAP Fuel Assistance (LIHEAP regular heating) #10303, Add Arizona LIHEAP Standard benefit #10293, Add Iowa LIHEAP regular heating assistance #10292): income counted gross where the state deducts the premium. The input exists and is enrollee-only and net of MSP.
  • Fix:
    • Deduct medicare_part_b_premium for members with social_security or railroad_benefits, from that member's countable income, floored at zero per member.
    • Re-pin Case 5 and add a railroad case.
    • Update the documentation, the body row and Axiom interpretation 10.

S4. Rental and farm-rent losses offset wages, because the unearned sum has no per-source floor

  • Where:
    • V/income/mo_liheap_countable_income_person.py:35 sums p.unearned_sources, including rental_income and farm_rent_income (P/income/unearned_sources.yaml:30-31), as reported.
    • The earned loop floors each source (line 28), and P/income/earned_sources.yaml:2-3 says "business and farm losses do not offset other income".
  • Sources:
    • Manual (p. 32): "Schedule 1, Line 3 – Business income (don't include if a loss)" and "Schedule 1, Line 6 – Farm income (don't include if a loss)". For "Roomer-Boarder / Rent Income", the documents are "Rent receipts. Contracts. Signed and dated statement from the tenant or cancelled checks", and the manual says "Prorate income from the rent of land and/or buildings not received monthly to a monthly amount". Page 34 adds that CRP payments count "as rental income".
    • Application (p. 5): it asks for "Rent Received from Land or Buildings".
    • Rule. (2)(H) defines income as "monthly revenue obtained".
    • Rent received cannot be negative.
  • Effect (2026, single adult aged 40, wages $45,000, so $36,000 after the 20% deduction, a rental_income of −$5,000 and natural gas):
    • Head: 36,000 − 5,000 = 31,000 ≤ 34,080, so $326.
    • With the floor: 36,000 > 34,080, so $0.
  • Severity: should, as in the wave's losses precedent (rental, farm-rent or self-employment losses offsetting wages).
  • Fix: floor rental_income and farm_rent_income (or every unearned source) per person, as the earned loop does. Add a case with wages and a rental loss that expects the wages alone.

S5. 10 of the 20 income-source entries and 5 of the 8 medical-deduction benefit entries have no test that would fail if they were dropped

  • Where: P/income/earned_sources.yaml (5 entries), P/income/unearned_sources.yaml (14), P/income/adult_unearned_sources.yaml (1) and P/income/disability_benefit_sources.yaml (8).
  • Untested. No case gives these a positive value:
    • Earned: sstb_self_employment_income and partnership_s_corp_income. farm_operations_income is set only to −$3,000 in person Case 4, which floors to 0, so dropping it changes nothing.
    • Unearned:
      • strike_benefits, railroad_benefits, rental_income, farm_rent_income, alimony_income and workers_compensation;
      • mo_ssp, which is set only to 0 in medical-deduction Cases 4 and 9.
    • Medical-deduction benefits: social_security_dependents, social_security_survivors, veterans_benefits, railroad_benefits and mo_ssp. No medical-deduction case uses them. The deduction tests > 0 over the list, so each entry needs its own case.
  • Tested:
    • Income: wages, self-employment, reported unemployment (through total_unemployment_compensation), SSI, pensions, military retirement pay, child support received, VA benefits and financial_assistance, plus Social Security, adult-only disability_benefits and mo_tanf.
    • Medical deduction: ssi, social_security_disability and medicaid.
    • Branches: every eligibility and benefit branch is pinned, including the floor, resources, size 0, coal, both subsidy inputs, the renter cap on both sides and the earned floor.
  • Severity: should, as in Add New Mexico LIHEAP regular heating assistance #10431 S3, Add Louisiana LIHEAP regular heating assistance #10429 S1, Add Virginia EAP Fuel Assistance (LIHEAP regular heating) #10303 S4 and Add Alabama LIHEAP regular heating assistance #9967 S3 (the mutation rule).
  • Fix:
    • Add one countable-income case that gives every untested source a distinct positive amount for an adult, including mo_ssp, reported unemployment and military_retirement_pay_survivors. Re-pin farm_operations_income with a profit.
    • Add one medical-deduction case per untested benefit with is_disabled.
    • S4's rental-loss case pins the new floor.

Suggestions

G1. Cite manual page 44 for the citizenship proxy.

  • The proxy. mo_liheap_household_size counts is_citizen_or_legal_immigrant. The rule ((6)(A), (8)(A)) and manual pages 42–43 say "citizen of the United States or a Legal Permanent Resident".
  • Page 44 supports it. Page 44 accepts as documents of "legal permanent residence status" an I-94 annotated "refugee", "parolee", "paroled", "asylum" or 204, 207, 208, 212(d)(5), 243(h) or 244. It also says COFA citizens "are included in the definition of qualified non-citizens". So the proxy matches practice, as Axiom interpretation 6 says.
  • What omits it. The body row ("Citizens and legal permanent residents") and the variable's reference (pages 40–43) omit page 44. Household-size Case 2 counts a refugee on page 44's authority.
  • Fix: cite page 44 in the variable and the body, and record the rule-vs-manual reading as a candidate.

G2. Fix the plan citation for interest and dividends, and record the plan-vs-manual income choices.

  • The conflict. Plan 1.9 checks "Interest, dividends, or royalties" and leaves "Cash gifts" unchecked (p. 6, rendered; the same in the FFY2027 draft). The manual excludes "Interest-Dividend Income" (p. 38) and counts contributions (p. 33).
  • The PR's choice. It follows the manual, which is the operative document (Axiom interpretation 9).
  • The citation. The body's "Not counted" row cites "plan 1.9" for interest and dividends, but the plan counts them.
  • Fix:

G3. Read the take-up-gated tanf, as every merged LIHEAP state does.

  • The difference. V/income/mo_liheap_countable_income.py:23 adds mo_tanf. AL, AR, FL, GA, KY, NJ, OK, OR, RI and SD read tanf, which is gated by takes_up_tanf_if_eligible. In microsimulation, mo_tanf counts TANF for eligible households that do not take it up.
  • Effect. mo_liheap does not change, since no TANF-eligible unit is near the 60% SMI limit, but mo_liheap_countable_income does.
  • Fix: read tanf and re-pin countable Case 1 with a tanf input.

G4. Decide what a heat-in-rent renter with an UNSPECIFIED fuel receives.

  • The model. T/mo_liheap.yaml Case 4 pins eligible and $0.
  • Main's contract. heating_type documents UNSPECIFIED as "the right value when heat is included in rent and the tenant does not know the building's fuel".
  • The rule. (13) caps the renter payment at "the maximum EA benefit payment" without naming a fuel. That supports the schedule maximum ($495) for an unknown fuel, which with 8% of a $9,000 rent gives $495 rather than $0.
  • Tracking. Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754 tracks the default.
  • Fix: cap at the schedule maximum when the fuel is UNSPECIFIED, or keep $0 and say in the body that such an eligible renter receives nothing.

G5. Add Wayback captures for anchors at risk of revision drift.

  • The application. It sits at a wp-content/uploads/2022/02/ path that DSS overwrites; it now holds the 8-2026 edition, the only printed FFY2027 source. Once the 8-2027 edition replaces it, the FFY2027 anchors in amount, smi_rate, adult_age and unearned_sources will drift.
  • The rule. Its URL is the "current" copy.
  • Fix: add a Wayback capture beside each.

Verified correct

Values against sources:

  • Income limit (plan 2.1, 60% SMI for all sizes, p. 8; also FFY2024, FFY2025 and the FFY2027 draft):
    • FFY2026. From SMI 109,229: floor(0.6 × 109,229) = 65,537. Times 0.52, 0.68, 0.84, 1.00, 1.16, 1.32 and +0.03 a member from 7, floored, then / 12 rounded half up, gives 2,840, 3,714, 4,588, 5,461, 6,335, 7,209, 7,373, 7,537, 7,701, 7,864, 8,028, 8,192, 8,356, 8,520, 8,684, 8,847, 9,011, 9,175, 9,339 and 9,503. All 20 match Appendix K FFY26.
    • FFY2027. From 113,137 (67,882): 2,942, 3,847, 4,752, 5,657, 6,562, 7,467, 7,637, 7,806, 7,976 and 8,146. All 10 match application page 1.
    • Sizes 12–15 in FFY2027. These run $1–2 a month below the application's "+$170" shorthand (8,485 / 8,655 / 8,825 / 8,994 against 8,486 / 8,656 / 8,826 / 8,996). The choice is documented (interpretation 4).
    • The comparison. "Maximum" is <=.
  • Federal 110% floor (42 U.S.C. 8624(b)(2)(B); gov.hhs.liheap.fpg_floor; fpg_year_lag 1, per IM 2025-02 Attachment 2 "mandatory use in FY26"):
    • FFY2026: size 15 has a limit of 104,208 against a floor of 101,915; size 16 has a floor of 107,965 against a limit of 106,164.
    • FFY2027: size 16 has a floor of 111,276 against a limit of 109,968.
    • So the floor binds from size 16 in both years, as the body says.
  • Fuel amounts. Natural gas 326, tank propane 495, electric 318, fuel oil 326, wood 219, kerosene 153 and cylinder propane 177 match:
    • Appendix K FFY26 (parsed);
    • manual page 129 (labelled "FFY 24", with the same amounts);
    • application page 1;
    • plan 2.6's $153–$495 (p. 9), which is the same in FFY2024, FFY2025 and the FFY2027 draft.
    • SOLAR at the electric amount is a documented inference. COAL is denied (Appendix E code O, "Heats with Coal", p. 122).
  • Eligibility:
    • resources "may not exceed $3,000" (rule (6)(B); plan 2.3; manual p. 40) on spm_unit_cash_assets;
    • subsidized housing with heat in the rent is barred (rule (7)(D); code M), apart from S2;
    • unsubsidized heat in the rent is eligible (rule (2)(M), (13));
    • a size of 0 is ineligible;
    • no categorical eligibility (plan 1.4 "No", p. 5, rendered).
  • Countable income (plan 1.8 gross, p. 5; manual pp. 30–38; application pp. 4–5):
    • the 20% deduction for wages and self-employment (p. 36);
    • per-source floors on business and farm income ("don't include if a loss", p. 32);
    • minors' earned and disability income excluded while their "SSA income" counts (p. 38);
    • income of members left out as non-citizens counted (pp. 42–43);
    • child support paid "by any household member to someone not included in the LIHEAP household" deducted (p. 36);
    • interest, dividends, lump sums, capital gains, refunds, student income and loans excluded (pp. 37–38; G2 covers the plan citation);
    • Social Security net of Part B, per plan 1.9 "Excluding MediCare deduction" (rendered) and manual page 36. That is right for Social Security; S3 covers railroad benefits.
  • Medical deduction (rule (2)(C), (2)(D), (6)(D)1; manual pp. 36, 48):
    • $100 a month, once per household;
    • the applicant or spouse 65 or older, or "totally and permanently disabled or blind" and receiving a listed benefit;
    • the disability list matches the rule's nine benefits through documented stand-ins, and RSMo 660.100.2's "disabled" definition agrees.
  • Renter base. pre_subsidy_rent × 12 is "the regular monthly rental charge" (rule (13); manual p. 63).
  • Years:
    • 2026 and 2027 are verified.
    • Earlier years. The parameter start dates (2017-05-30, 2023-10-01, 2025-10-01) are documented, unclaimed backfills. The FFY2024 manual's different non-citizen and student rules are not reproduced for 2024–2025, and the body says earlier years are unverified estimates (NJ S3 pattern).

Hand-checked expectations (20). All are 2026 unless noted, with a size-1 limit of 34,080:

  • Eligibility Cases 1–2: 34,080 = 12 × 2,840 is eligible. 34,081 is ineligible (the floor is 17,215).
  • Eligibility Case 3 (size 16): limit 106,164; floor 1.1 × 98,150 = 107,965. 107,000 is eligible; 107,965 is not below the floor, so ineligible.
  • Eligibility Case 4 (2027, size 16): limit 109,968; floor 1.1 × 101,160 = 111,276. 110,500 is eligible.
  • Eligibility Cases 5–7: assets of 3,000 are eligible and 3,001 are not. An undocumented single adult has size 0, so ineligible.
  • Income-limit Case 1: 2,840, 5,461, 8,847 and 9,503 × 12 give 34,080, 65,532, 106,164 and 114,036.
  • Income-limit Case 2 (2027): 2,942 and 8,146 × 12 give 35,304 and 97,752.
  • Countable Case 2: 31,200 × 0.8 − 4,800 = 20,160.
  • Countable Case 3: 23,400 − 2,434.80 − 1,200 = 19,765.20.
  • Countable Case 4: max(4,992 − 6,000, 0) = 0.
  • Countable Case 5: 2 × 24,960 − 3,600 = 46,320, with size 1.
  • Person Case 4: max(24,000, 0) + max(−3,000, 0), times 0.8, = 19,200.
  • Person Case 5: 20,965.20 and 6,000 (head reading; S3 changes the second).
  • Person Case 6: 6,000 + 4,800 + 1,200 = 12,000; 24,000 + 6,000 = 30,000.
  • Person Case 9: 58,240 × 0.8 = 46,592, above 3,714 × 12 = 44,568, and the floor (23,265) does not reach it, so $0.
  • Person Case 10: 18,000, and for the minor, 9,600 (the minor's $1,440 is excluded).
  • Medical-deduction Cases 1, 2 and 7: 65 gives 1,200; 64 gives 0; a couple of 70 and 67 gives 1,200, not 2,400.
  • Integration Case 1: 24,960 + 14,976 = 39,936, at most 65,532, so natural gas $326.
  • Integration Case 2: 27,565.20 + 10,765.20 − 1,200 = 37,130.40, at most 44,568, so tank propane $495.
  • Integration Case 3 (2027): size 2; 24,960 + 20,800 = 45,760, at most 46,164; min(0.08 × 10,200 = 816, 326) = $326.
  • mo_liheap.yaml Cases 1–3 and 6:
    • The fuel vector is 326 / 495 / 318 / 326 / 219 / 153 / 318 / 0 / 0 / 0 / 0.
    • 0.08 × 6,000 = 480, below 495.
    • 0.08 × 9,000 = 720, capped at 326.
    • 2027: 41,600 × 0.8 = 33,280, at most 46,164, so kerosene $153.
  • Case count: 13 + 2 + 5 + 10 + 9 + 3 + 6 + 4 = 52, as the body says.

Batch checks:

Wiring and housekeeping:

  • Registry. The MO entry sits between MD and MS with verified_years: "2026-2027", and MO is added to the coverage line. test_programs_registry passed.
  • Aggregates. There is no aggregate wiring, which matches every merged LIHEAP state. Take-up is G3.
  • Gating. defined_for = StateCode.MO is on 6 variables, and mo_liheap is gated by mo_liheap_eligible.
  • Changelog. changelog.d/mo-liheap-wave1d.added.md is top level and typed added.
  • Descriptions (item 6): all 13 end "under the Low Income Home Energy Assistance Program." with nothing after it.
  • References (item 7):
    • Every anchor I opened shows its value: rule PDF pp. 2–4; plan pp. 5–9; draft FFY2027 plan pp. 5–9; FFY2024 and FFY2025 plans p. 8; manual pp. 32–34, 36, 38, 40, 48, 63, 122 and 129; application pp. 1, 4 and 5.
    • Multi-page titles use the quoted #page 32-34,38,40 form, and variables use # PDF pages comments.
  • Tests. The files are variable-named, every period is plain, and every case sends heating_type.

Checklist results (LIHEAP batch):

  1. State plan and manual: every published limit row and fuel amount matches. The rule's ranges and table are S1.
  2. Income definition: gross income and the 20% deduction are right. Railroad SMI is S3 and rental losses are S4.
  3. Backdating: pass for 2026–2027. Earlier years are documented, unclaimed backfills.
  4. Household and arrangement rules: fuel choice and subsidized tenants who pay electric are S2. Every other branch is tested.
  5. Tests: 52 cases, 20 hand-checked, all periods plain. Source coverage is S5.
  6. Descriptions: pass.
  7. References: pass (Wayback captures are G5).
  8. Wiring: pass (TANF take-up is G3).
  9. Axiom: valid (#1899).
  10. Branch and CI: a clean merge with main; 27 of 27 pass.
  11. Integrate modeled state unemployment insurance into income flows #9558: pass.
  12. IIJA / FY2027: not applicable / FY2027 encoded from the application.
  13. Mutation check: 10 income-source entries and 5 benefit entries are unpinned (S5).
  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: pass (mo_ssp is counted).

Axiom line assessment

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

  • State: OPEN, labelled pe-parity, created 2026-10-23 22:16 UTC.

  • It matches the head. It names head 2b62923ca0 and merge base 6a92d6a983. The current head 566343d074 adds one commit, which replaces sum() with a loop in mo_liheap_countable_income_person and changes no behavior. The issue lists the 13 parameters, the 7 output variables and the 52 cases by file. Its required outputs describe the head's code.

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

    • proposed us-mo/ module paths, with corpus status per source;
    • verbatim text of the rule, the manual, the plans, Appendix K and the application;
    • 13 companion tests derived from the sources, not from PE output;
    • 19 interpretations;
    • its blockers: sources missing from the corpus, an unchecked signed release, billed-run approval and no reviewed oracle revision.
  • Note. The fixes change these interpretations and outputs:

    • S1 changes interpretations 1–3;
    • S2 changes 14 and 16, plus the eligibility and benefit outputs;
    • S3 changes 10 and the per-person income output;
    • S4 changes 12–13;
    • S5 adds cases.

    Update the issue with the head that resolves them, and add RSMo 660.100 to its sources.

CI status

27 pass, 0 failed, none pending. Run 40047545306 tested head 566343d074 (pull_request, created 2026-10-24 00:57 UTC, after #10287 and the 2026-10-21 cutoff). I re-checked gh pr checks 10438 at the end of this review.

  • Missouri tests. States-shard-2, batch 7/14 (states/mo), ran all 8 files: 13 + 2 + 5 + 10 + 9 + 3 + 6 + 4 = 52 passed.
  • Guards (Rest jobs):
    • the four test_unemployment_compensation_readers.py tests;
    • the four test_military_retirement_readers.py tests;
    • the test_source_conflicts.py tests, including the ratchet and the four candidate checks;
    • test_members_are_state_gated;
    • test_programs_registry.
  • Also passing: Microsimulation, Household API Partners, PR validation, Package and compatibility, Quick Feedback, and every baseline and contrib shard.
  • Known main-caused failure: not applicable.
  • Locally: I ran no tests or model probes. The S1–S4 examples are hand traces of the code at the head. The only local scripts were the static comment-pattern scan, the Appendix K parse and the limit and floor arithmetic.

Branch status

0 critical, 5 should and 5 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 tables check out (all FFY26 and FFY27 limit rows, the 7 fuel amounts, the 110% floor, the 20% and medical deductions, mo_ssp counted), the guards pass, and 20 expectations hand-check. Five should-address items: (1) the income test and table follow the agency (60% SMI, flat amounts) over 13 CSR's 135% FPG ranges, but the renter rate follows the rule (8% vs 16%), and the candidate omits RSMo 660.100.2 and the rent rate; (2) Missouri pays the fuel the household selects, electric included (kerosene plus electric: $153 vs $318); (3) the SMI premium isn't deducted from railroad benefits ($0 vs $326); (4) a rental loss offsets wages; (5) 10 of 20 income sources and 5 of 8 medical-deduction entries are unpinned. Five suggestions. Full report in the comment above.

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 Missouri LIHEAP Energy Assistance regular heating assistance

2 participants