Skip to content

Add Maine HEAP Fuel Assistance - #10437

Open
hua7450 wants to merge 2 commits into
mainfrom
me-liheap-wave1d
Open

hua7450 wants to merge 2 commits into
mainfrom
me-liheap-wave1d

Conversation

@hua7450

@hua7450 hua7450 commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Adds Maine HEAP Fuel Assistance, the state's LIHEAP regular heating benefit administered by the Maine State Housing Authority (MaineHousing) under 99-346 CMR ch. 24, for the 2025-26 and 2026-27 heating seasons (model years 2026 and 2027). The model counts citizens, nationals and qualified aliens in household size (all members' income still counts), tests income against the greater of 150% of the poverty guideline and 60% of state median income (or SNAP or TANF receipt), requires a heating bill or heat included in the rent, and scores points for dwelling type, county, fuel, at-risk members and subsidized housing. It adjusts the points by the household's poverty-level multiplier, prorates them for ineligible members, rounds up and multiplies by the dollar value per point. Subsidized tenants with heat included in rent receive $21.

Fixes #10427

The two seasons use different rule editions: the 2025 edition (SOS filing 2025-135, the same matrix as the 2024 edition) for 2025-26, and the replacement rule effective June 29, 2026 (SOS filing 2026-134) for 2026-27, which adds 8 base points and changes every points table and the multipliers.

The dollar value per point is an estimate. MaineHousing announces it after each federal award and has published none for FFY2025-FFY2027. $22 is inferred from the FFY2025 and FFY2026 plans' $1,012 maximum (the 2025-edition maximum of 35 points x 130% = 45.5, rounded up to 46, x $22), which also fits their $88 minimum (4 x $22). It is reused for 2026-27 until MaineHousing announces a value.

Regulatory authority

Eligibility

Requirement Source How modeled
Maine residence Rule 3(A)(4) defined_for = StateCode.ME
Citizens, nationals and qualified aliens Rule 3(A)(1) me_heap_household_size sums is_citizen_or_legal_immigrant; size 0 is ineligible
Income at most the greater of 150% FPG and 60% SMI Rule 3(C); Plan 2.1; MaineHousing charts me_heap_income_limit, prior-year guideline; reproduces the 2025-26 chart for sizes 1-10 and the 2026-27 chart
Categorical income eligibility (TANF or SNAP) Rule 3(C)(2); Plan 1.4 SNAP or TANF receipt passes the income test; the multiplier uses actual countable income
Energy cost for heat and a listed fuel Rule 1(M), 1(HH), 3(A)(4), 4(A) A Direct Energy Cost (a heating bill the household pays, has_heating_expense) or an Indirect Determinable Energy Cost (heat included in rent, heat_expense_included_in_rent); a listed fuel with no bill and heat outside the rent is ineligible. Listed fuels: electricity, propane, kerosene, oil, coal, natural gas and wood; SOLAR uses the electricity row (grid-tied home with electric heat), and an off-grid solar-only home has no electricity bill, so it has no energy cost and is ineligible; NONE is ineligible; OTHER and UNSPECIFIED are ineligible unless subsidized with heat in rent

Countable income

Item Source How modeled
Members counted Rule 3(C)(1) Members 18 and older ("over the age of 18"), of every immigration status
Earned income Rule 3(C)(1)(a)-(b) Wages and net self-employment, including partnership and S corporation income, each floored at zero; a full-time high-school student's earnings are excluded unless the student is the applicant (tax-unit head)
Unearned income Rule 3(C)(1)(c)-(n) Social Security and SSI including Medicare deductions, unemployment, workers' compensation, strike benefits, alimony, child support, VA benefits, cash gifts (financial_assistance), pensions and annuities, military retirement, long-term disability, interest, dividends, estate and trust income, rental income
Not counted Rule 3(C)(1) exclusions; Plan 1.9 TANF and General Assistance (not listed; plan boxes unchecked), retirement-account and other asset drawdowns, tax refunds, lump sums, SNAP
Medical-expense adjustment Rule 3(C)(1), last paragraph An over-income household deducts medical expenses (premiums and other medical costs) only up to the amount needed to reach the limit

Benefit

Points 2025 edition (2025-26) Replacement rule (2026-27)
Base 0 8
Dwelling: stick-built or modular / mobile or manufactured / condo, duplex or apartment 9 / 8 / 6 3 / 2 / 1
County 2 (Kennebec, Sagadahoc, Washington) to 7 (Aroostook) 1 (Cumberland, Kennebec) to 6 (Aroostook)
Fuel: electricity / propane / kerosene / oil / coal / natural gas / wood 14 / 10 / 8 / 7 / 5 / 5 / 4 8 / 5 / 5 / 4 / 4 / 3 / 3
Member 60+, disabled or 6 and under / else child 7-17 5 / 3 5 / none
Subsidized household paying for heat -9 -3
Poverty-level multiplier 130% (0-25%) to 70% (above 150%), whole-percent rounding 1.8 (0-10.99%) to 0.7 (176% and above), two-decimal rounding
  • Points x multiplier x eligible share of members, rounded up, x $22 (estimate). Subsidized tenants with heat in rent: $21 (rule 4(B); plan 1.7).
  • New input me_heap_dwelling_type, defaulting to stick-built or modular.

Not modeled

Item Source Treatment
TANF Fuel Supplemental Benefit ($300 per the PY2025 notice; removed by the 2026 rule) 2025 edition 3(A), 4(B) TANF-funded supplement, excluded
Wood pellet, corn, bio-fuel and bio-brick rows Rule 4(A) No heating_type value; WOOD uses the cordwood row
Roomers as separate households, live-in attendants, optional exclusion of college students Rule 3(A) No inputs
Residency and dwelling-unit tests, HEAP Guide procedures Rule 3(A)-(B) Not represented; the HEAP Guide is not public
ECIP crisis, weatherization, CHIP, heat pumps Ch. 24 (other components) Out of scope

Shared parameter

Adds gov.hhs.liheap.fpg_limit (150%, 42 U.S.C. 8624(b)(2)(B)(i)) next to smi_limit, starting October 1, 1981: Pub. L. 97-35, section 2605(b)(2)(B)(i), set this ceiling from fiscal year 1982. The Vermont branch adds a byte-identical copy.

Test plan

43 YAML cases in 9 files cover the income limit against both published charts and a size where 150% FPG exceeds 60% SMI; counted members, sources, the per-source floor, the high-school student rule and both sides of the medical-expense adjustment; categorical SNAP and TANF receipt; fuel and housing eligibility; the multiplier band edges and rounding in both editions; every dwelling type and fuel, high, low and unlisted counties, priority points, the subsidized adjustment, base points, proration and the round-up guard; the plan maximum ($1,012), the $21 benefit, and four end-to-end households, one of which heats with oil, has no bill and no heat in the rent, and is ineligible. Each paying case with heat outside the rent carries a heating bill for its fuel, taken from EIA's October 2026 Short-Term Energy Outlook winter fuels table and the Maine Department of Energy Resources price survey of January 5, 2026 (cordwood and pellets); the coal entry uses the heating-oil amount because neither source publishes a residential coal price. Expected values are hand-computed from the rule tables. The cases were not re-run locally after the 2026-10-22 review fixes; CI runs them.

  • YAML tests with hand-computed expected values
  • CI passes
  • Changelog fragment in changelog.d/

axiom: TheAxiomFoundation/rulespec-us#1898 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
@DTrim99

DTrim99 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Add Maine HEAP Fuel Assistance

PR #10437 (author: hua7450), head bbdb9b5f78. This is a first review. The PR adds HEAP Fuel Assistance, Maine's LIHEAP regular heating benefit administered by MaineHousing under 99-346 CMR ch. 24, for the 2025-26 and 2026-27 seasons (model years 2026 and 2027). It includes:

  • 20 parameters (19 Maine files plus the shared gov.hhs.liheap.fpg_limit) and 9 variables (8 computed, plus the new input me_heap_dwelling_type);
  • 9 test files (43 cases);
  • a programs.yaml entry (coverage line and state list);
  • a changelog fragment.

The PR has no comments or reviews yet, and it touches no partner test file.

Path prefixes:

  • P/ = policyengine_us/parameters/gov/states/me/msha/heap/
  • V/ = policyengine_us/variables/gov/states/me/msha/heap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/me/msha/heap/

Sources read for this review:

  • Rule, June 29, 2026 replacement (SOS filing 2026-134): 99-346 CMR ch. 24, file pages 1-4 (definitions), 6, 10-17 (eligibility, income, benefit matrix, payment) and 33 (effective date).
  • Rule, 2025 edition (SOS filing 2025-135): the Secretary of State's Word copy, definitions, sections 3-5 and the filing history, plus its matrix in the FY2026 Benefit Matrix, pages 1-2.
  • State plans: the FY2026 Detailed Model Plan, pages 4-10 (I rendered pages 5-7 to read the boxes), and the FY2025 plan, page 8 (rendered; the file is a scan). No FY2027 plan is on the Clearinghouse.
  • MaineHousing:
  • Federal: 42 U.S.C. 8624(b)(2)(B) and IRS Publication 502 ("Employer-Sponsored Health Insurance Plan"; "Medicare Part B").
  • Not obtainable: MaineHousing's PY2026 HEAP Guide (search indexes list "PY2026 HEAP Guide, Effective 8/29/2025" in its partner library, but the file now returns 404 and has no Wayback capture).

Summary

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

  • Points matrices. Every cell matches its edition: the 2025 edition (dwelling 9/8/6, 16 counties from Aroostook 7 to Kennebec, Sagadahoc and Washington 2, fuels 14 to 4, priority 5 or 3, subsidized -9, seven multiplier bands with whole-percent rounding) and the June 29, 2026 rule (base 8, dwelling 3/2/1, 16 counties from Aroostook 6 to Cumberland and Kennebec 1, fuels 8 to 3, at-risk 5 "for the first in the house", heating subsidized -3, eight bands from 1.8 to 0.7). The PR uses the adopted county table, not the April 2026 proposal (which had Franklin 4, Cumberland 2 and Washington 1).
  • Income limit. max(150% of the lagged guideline, 60% of state median income) reproduces all 20 published chart rows: 36,836 to 102,008 for 2025-26 and 38,070 to 105,426 for 2026-27.
  • Dollar values. $22 a point for 2025-26 is a sound inference: the 2025 edition's largest total, 35 × 1.30 = 45.5, rounds up to 46, and 46 × $22 = $1,012, the FY2025 and FY2026 plans' maximum. The $21 subsidized heat-in-rent amount matches plan 1.7b.
  • Countable income. Gross receipts; Social Security and SSI "including Medicare deductions" (rule 3(C)(1)(c) and plan 1.9's checked "Including MediCare deduction" box, so the wave's Medicare-netting precedent does not apply here); a per-source floor on every source, rental and farm rent included; the high-school-student exclusion and its applicant exception; assets drawn down excluded; ineligible members' income counted; and the medical adjustment that stops at the limit.
  • Heat in rent. Unsubsidized tenants with heat in the rent score full points (the rule has no reduction), and subsidized tenants receive $21.
  • Tests. I hand-checked 24 expectations below, and CI passed all 43 cases.
  • Batch checks. The guards all pass: Integrate modeled state unemployment insurance into income flows #9558, Count military SBP annuities in state benefit income lists #10317, the Count each Social Security benefit once in Pennsylvania CCW countable income #10408 pattern and the Tie source-conflict markers to the register shared with Axiom #10287 ratchet (on the merged tree too). Item 17 is a suggestion: me_ssp is on main but not counted.

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

  • S1. Railroad and survivor annuities are not counted. Rule 3(C)(1)(i) counts "regular annuity payments", but railroad_benefits and survivor_benefits are missing from the unearned list. A railroad retiree with $20,000 gets $748 instead of $462; with $40,000, $748 instead of $0.
  • S2. TANF follows the plan over the rule, while long-term disability follows the rule over the plan. The rule counts "total combined income ... from all sources" unless excluded, and TANF is not excluded. The PR leaves TANF out because plan 1.9 leaves its box unchecked, yet it counts long-term disability in 2025-26 on the rule's "includes, but is not limited to", against the plan's unchecked insurance box. The choice is not recorded. A TANF family of three gets $748 instead of $704.
  • S3. Households heating with an unlisted fuel are denied. Eligibility requires a fuel listed in the points matrix, which the rule does not require. The rule pays corn and bio-fuel heaters directly. An OTHER-fuel household with a bill gets $0 instead of $176-$264, and the PR's own test labels that household a pellet stove.
  • S4. Untested sources. 3 of the 5 earned sources, 15 of the 17 unearned sources and other_medical_expenses never take a positive value in any test. The public-housing branch of the $21 benefit is also unpinned.

There are also six suggestions:

  • G1: unsubsidized heat-in-rent renters with an UNSPECIFIED fuel get $0.
  • G2: the 2026-27 dollar value per point is an uncorroborated carry-forward.
  • G3: count me_ssp (item 17) and Maine paid family and medical leave benefits.
  • G4: record the plan-versus-rule and plan-versus-chart readings in the body and the backlog.
  • G5: add Wayback captures for the three overwritten URLs.
  • G6: reconsider the stick-built default for me_heap_dwelling_type.

Status.

  • CI: 27 pass and 3 skipping. All 43 Maine HEAP cases passed in states-shard-3.
  • Branch: 2 commits ahead of main and 41 behind. It merges cleanly.
  • Siblings: this PR adds ME to the LIHEAP coverage line, so it conflicts with 17 open LIHEAP siblings in programs.yaml only (branch note).

Critical (must fix)

None.

Should address

S1. Railroad retirement and non-Social Security survivor annuities are not counted, although rule 3(C)(1)(i) counts regular annuity payments

  • Where: P/income/sources/unearned.yaml:13-32 lists pension_income and military_retirement_income but neither railroad_benefits nor survivor_benefits. V/me_heap_income.py:28-30 sums only that list.
  • Sources:
    • Rule 3(C)(1), both editions (2026 p. 12): "Household Income means the total combined income of all Household Members over the age of 18, unless otherwise excluded from all sources before taxes and deductions ... Household Income includes, but is not limited to, the following: ... i. Government employee pensions, private pensions, and regular annuity payments". Neither exclusion list (pp. 12-15) mentions railroad or survivor annuities.
    • Plan 1.9 (p. 6, rendered) checks "Retirement / pension benefits".
    • On main, railroad_benefits is the Railroad Retirement Board annuity input, and survivor_benefits is documented as "Survivor benefits other than Social Security survivor benefits" (for example, a pension survivor annuity). Neither is part of pension_income, social_security or military_retirement_income, so adding them double counts nothing.
  • Effect (hand-traced, 2026; a single retiree aged 70, no medical expenses, oil with a $1,745 bill, stick-built, Penobscot, so 9 + 5 + 7 + 5 = 26 points):
    • (a) railroad_benefits $20,000.
      • Head: income 0, so 0% gives 1.30; 26 × 1.30 = 33.8, rounded up to 34; $748.
      • Counted: 20,000 / 15,650 = 127.80%, rounded to 128%, gives 0.80; 26 × 0.80 = 20.8, rounded up to 21; $462.
    • (b) railroad_benefits $40,000. Head $748. Counted: 40,000 > 36,836, and even after a standard 2026 Part B premium of $2,434.80 as a medical expense, 37,565.20 > 36,836, so $0.
    • The same figures hold for survivor_benefits.
  • Severity: should. This is an omitted countable source with a wrong result in a claimed year (the wave's unpinned-or-omitted source precedent; Add Minnesota EAP Primary Heat benefit #10433 S1 for railroad annuities).
  • Fix:
    • Add railroad_benefits and survivor_benefits to P/income/sources/unearned.yaml. Both count gross, like Social Security.
    • Add a railroad-only case like (a).
    • Update the body's unearned row and Axiom interpretation 8 and its countable-income output.

S2. TANF is left out on the plan's authority, although the rule's all-sources definition reaches it, while long-term disability is counted in 2025-26 on the rule's authority against the plan; neither choice is recorded

  • Where:
    • P/income/sources/unearned.yaml:4-12: "disability_benefits stands for long-term disability payments, item (n) of the June 29, 2026 replacement; the 2025 edition's list 'includes, but is not limited to' the items it names", and "Not counted: TANF and General Assistance, which the rule does not list and the FY2026 plan's Section 1.9 leaves unchecked".
    • The body's "Not counted" row cites "Rule 3(C)(1) exclusions; Plan 1.9" for TANF, but neither exclusion list names TANF.
    • source_conflicts/candidates.yaml gets no entry.
  • The rule.
    • Definition 1(EE) (2026 p. 3; 2025 edition the same): "'Household Income' means the total income from all sources before taxes and deductions as further defined in this Rule."
    • 3(C)(1) (p. 12): income of members over 18 "unless otherwise excluded from all sources before taxes and deductions", and the list "includes, but is not limited to" its items.
    • The exclusions (pp. 12-15, 2026 items a-t; the 2025 list is the same apart from items g and k) name SNAP, foster care, adoption assistance and "Non-cash income such as General Assistance voucher payments", but not TANF.
  • The plan. Plan 1.9 (pp. 6-7, rendered) leaves "Temporary Assistance for Needy Families (TANF) benefits" unchecked. It also leaves "Insurance payments made directly to the insured" unchecked, and the 2025 edition's list does not name long-term disability (item (n) arrives only with the 2026 rule).
  • What the PR does. It applies "includes, but is not limited to" to count long-term disability in 2025-26 against the plan box, and "the rule does not list" to drop TANF in line with the plan box. So the hierarchy runs one way for one source and the other way for the other.
  • The project rule. CONTRIBUTING "Source conflicts": "Regulations are law"; "The agency breaks true ties" only where the text does not settle a reading. The rules file rates a plan-versus-regulation conflict should, with a clear recommendation (Add Missouri LIHEAP Energy Assistance #10438 S1).
  • Effect (hand-traced, 2026; oil with a $1,745 bill, stick-built, Penobscot):
    • (a) TANF. Take T/me_heap_income.yaml Case 6 (head 27 with $2,400 of child support, tanf $10,740, children 5 and 2; categorically eligible), so 9 + 5 + 7 + 5 = 26 points.
      • Head: 2,400 / 26,650 = 9.01%, so 9% gives 1.30; 26 × 1.30 = 33.8, rounded up to 34; $748.
      • Rule: 13,140 / 26,650 = 49.31%, so 49% gives 1.20; 26 × 1.20 = 31.2, rounded up to 32; $704.
    • (b) Long-term disability, the other direction. A single adult aged 50 with is_disabled and disability_benefits $24,000: head 153.35%, so 153% gives 0.70 and 19 points, $418. Following the plan's box in 2025-26 gives 0%, 1.30 and 34 points, $748.
  • Severity: should. Authoritative sources conflict, the PR applies the hierarchy inconsistently, and nothing records the choice.
  • Fix: I recommend (a).
    • (a) Follow the rule for both. Count the SPM unit's tanf in me_heap_income (the rule's definition reaches it, and its exclusion list omits it), keep long-term disability, and add a us-me:heap-... candidate for the plan's unchecked TANF box with follows: rule and prs: [#10437].
    • (b) Follow the plan for both, pending a ruling from the project lead: keep TANF out, drop disability_benefits before June 29, 2026, and record the candidate with follows: plan.
    • Either way, correct the body's citation, and leave General Assistance out only on the voucher exclusion (j), saying so.

S3. Eligibility requires a fuel listed in the points matrix, which the rule does not, so OTHER-fuel households with their own bill get $0

  • Where:
    • V/eligibility/me_heap_eligible.py:39-54 requires listed_fuel (eight heating_type values) unless the household is a subsidized heat-in-rent tenant.
    • V/payment/me_heap_points.py:33, 55 gives OTHER no fuel row.
    • T/eligibility/me_heap_eligible.yaml:54, 67-69 (Case 2) gives the OTHER household a $357 other_heating_fuel_expense, describes it as "a pellet stove", and pins it ineligible ("OTHER fails even with its pellet bill").
  • Sources:
    • Eligibility. Rule 3(A)(4) (2026 p. 10) requires "a Direct Energy Cost or Indirect Determinable Energy Cost", and 3(B)(1)(a) (p. 11) requires "a Functioning Heating System". "Energy Cost" means "cost of energy used for heating" (1(Q), p. 2). Neither edition requires a fuel in the matrix.
    • Payment. Rule 5(A)(5) (2026 p. 17; the 2025 edition the same): "For payment for Primary Applicants that heat with Wood, Wood Pellets, Coal, Corn, or Bio-Fuel ... will make payment for a Benefit by direct check". The 2026 matrix has no corn or bio-fuel row, so the rule pays fuels its own table does not score.
    • MaineHousing's 2025-26 page lists the fuel types it accepts: "natural gas, heating oil, kerosene, propane, wood, wood pellets, biobricks, coal, corn, or electricity".
  • Why this is not the UNSPECIFIED precedent. On Add Virginia EAP Fuel Assistance (LIHEAP regular heating) #10303, Add Arizona LIHEAP Standard benefit #10293, Add Minnesota EAP Primary Heat benefit #10433 (G1) and Add Missouri LIHEAP Energy Assistance #10438 (G4), UNSPECIFIED $0 was accepted because heating_type is a required input. Here the caller supplies the input and a positive bill. heating_expense reads other_heating_fuel_expense for OTHER, which is how main represents a pellet, corn or bio-fuel household. The gate is the PR's inference from "the points matrix lists the fuels", not a rule requirement.
  • Effect (hand-traced; a single adult aged 40, stick-built, Kennebec, OTHER with a $357 bill):
    • (a) 2026 (wages $30,472; 194.71%, rounded to 195%, gives 0.70). Head: $0.
      • Eligible with no fuel points: 9 + 2 = 11; 11 × 0.70 = 7.7, rounded up to 8; $176.
      • Scored on the wood-pellet row (5, also the corn row): 16 × 0.70 = 11.2, rounded up to 12; $264.
    • (b) 2027 (a corn stove; wages $31,408; 196.79% gives 0.70). Head: $0.
      • No fuel points: 8 + 3 + 1 = 12; 8.4 rounds up to 9; $198.
      • Wood-pellet row (4): 16 × 0.70 = 11.2, rounded up to 12; $264.
  • Severity: should. This is a wrong result in a claimed year that contradicts the rule's eligibility test, with existing inputs, and a test pins it.
  • Fix:
    • Drop listed_fuel from me_heap_eligible and keep the NONE exclusion (3(B)(1)(a)).
    • Score OTHER on the wood-pellet row (5 in the 2025 edition, matching corn; 4 in the 2026 rule), the listed fuel heating_type cannot name, or at 0 fuel points as a floor. Document the choice.
    • Re-pin eligibility Case 2 (OTHER becomes true) and add a points case for OTHER in each year. G1 covers UNSPECIFIED.
    • Update the body's eligibility row and Axiom interpretation 11.

S4. Nineteen income and expense entries, and one benefit branch, have no test that would fail if they were dropped

  • Where: P/income/sources/earned.yaml (5 entries), P/income/sources/unearned.yaml (17), P/income/medical_expense_sources.yaml (2) and V/me_heap.py:43-48.
  • Untested. No case gives these a positive value:
    • Earned (3 of 5): sstb_self_employment_income, farm_operations_income and self_employment_income. The last is set only to -$4,200 in income Case 4: that pins the floor, but dropping the source changes nothing.
    • Unearned (15 of 17): ssi (0 in every case), total_unemployment_compensation, workers_compensation, strike_benefits, alimony_income, veterans_benefits, financial_assistance, pension_income, military_retirement_income, disability_benefits, interest_income, ordinary_dividend_income, estate_income, rental_income and farm_rent_income.
      • Example: a single adult aged 66 whose only income is $20,000 of pension_income (oil, stick-built, Penobscot) gets $462. Dropping pension_income gives $748, and no case fails.
    • Medical (1 of 2): other_medical_expenses (0 in every case).
    • The public-housing branch of the $21 benefit. me_heap.py computes subsidized separately from me_heap_eligible. Eligibility Case 3 pins public housing only for eligibility, and me_heap.yaml Case 3 uses a voucher. If is_in_public_housing were dropped from me_heap.py, a public-housing tenant with heat in the rent (UNSPECIFIED, wages $30,472, Kennebec) would get 9 + 2 = 11 × 0.70 = 7.7, rounded up to 8, so $176 instead of $21, and no case would fail.
  • Tested:
    • Income: wages, partnership and S corporation income, Social Security (retirement and disability), child support, IRA withdrawals (excluded), TANF (excluded) and health premiums.
    • Branches: every dwelling type, fuel and multiplier band in both years; base points; subsidized points; the priority edges at 6/7, 17/18 and 59/60; at-risk once; proration with the floating-point guard; the unlisted county; size 0; the limit edge; both sides of the medical adjustment; the student exclusion and its applicant exception; SNAP and TANF categorical eligibility; NONE; and no bill.
  • Severity: should, as in Add Minnesota EAP Primary Heat benefit #10433 S2, Add Missouri LIHEAP Energy Assistance #10438 S5 and Add Washington LIHEAP regular heating assistance #10345 S4 (the mutation rule).
  • Fix:
    • Add one me_heap_income case that gives every untested source a distinct positive amount for an adult. S1's railroad case covers railroad_benefits.
    • Give one medical-adjustment case a positive other_medical_expenses.
    • Add a me_heap.yaml case for a public-housing tenant with heat in the rent that expects $21.

Suggestions

G1. Unsubsidized heat-in-rent renters with an UNSPECIFIED fuel get $0.

  • The model. me_heap_eligible denies an unsubsidized heat-in-rent tenant whose fuel is UNSPECIFIED (eligibility Case 3, household 3). main's HeatingType comment calls UNSPECIFIED "the right value when heat is included in rent and the tenant does not know the building's fuel".
  • Example. Take T/integration.yaml Case 2 (2027, a family of four renting an apartment in Cumberland with heat in the rent, 0.9). With NATURAL_GAS it gets $374. With UNSPECIFIED it gets $0. Scored with no fuel points (8 + 1 + 1 + 5 = 15 × 0.9 = 13.5, rounded up to 14), it would get $308.
  • The precedent. Add Virginia EAP Fuel Assistance (LIHEAP regular heating) #10303, Add Arizona LIHEAP Standard benefit #10293, Add Minnesota EAP Primary Heat benefit #10433 G1 and Add Missouri LIHEAP Energy Assistance #10438 G4 settled UNSPECIFIED as an input rule, which is why this is a suggestion. S3's fix removes the gate for OTHER, so decide UNSPECIFIED explicitly: keep the gate and say so in the body, or score it at 0 fuel points or the lowest row (3 in 2027).

G2. The 2026-27 dollar value per point is an uncorroborated carry-forward.

  • 2025-26 is well supported. Beyond the $1,012 = 46 × $22 identity, MaineHousing's 2025-26 notice reports "approximately 4,000 households have received assistance, totaling $2.2 million" (about $550, roughly 25 points at $22 for priority households). The August 2026 board packet reports $20,625,130 paid for PY2026 (p. 67).
  • 2026-27 is not. The new matrix runs from 10 × 0.7 = 7 points ($154) to 30 × 1.8 = 54 points ($1,188) at $22. The only FY2027 figures MaineHousing has printed, item 2.6 of the draft FFY2027 plan (April 2026 board packet, p. 110, rendered), are $88 and $1,012, both flagged with the comment "Get this information". The adopted plan went to HHS by August 21, 2026 (August packet, p. 67) and is not yet on the Clearinghouse.
  • Fix:
    • Note the draft's placeholders, and the fact that the model's 2027 maximum exceeds them, in P/payment/value_per_point.yaml and the body (Axiom interpretation 1 already does).
    • Re-derive the value when the adopted FFY2027 plan or an announcement appears. Until then, consider saying in programs.yaml that 2027 benefit amounts are estimates while 2027 eligibility is verified.

G3. Count me_ssp (checklist item 17) and Maine paid family and medical leave benefits.

  • me_ssp. It is on main (in this PR's base), and the rule's "total income from all sources" reaches it: the State Supplement is cash income, and no exclusion names it.
    • Example: an SSI recipient living alone receives $10 a month ($120 a year). For a 2026 household whose countable income sits at $11,700 (74.76%, rounded to 75%, so 1.10), adding $120 gives 75.53%, rounded to 76%, so 1.00. On 26 points that is 29 points, $638, against 26 points, $572.
  • pfml_benefits. Maine's paid family and medical leave benefits became payable on May 1, 2026, and main has the pfml_benefits input. The rule counts unemployment insurance and long-term disability and does not exclude leave benefits.
  • Fix: add both to the unearned list, with a case each. Otherwise, explain in the body why they are left out.

G4. Record the plan-versus-rule and plan-versus-chart readings in the body and the backlog.

  • The readings. Axiom interpretations 3, 4, 6 and 13 record these choices, but the body and source_conflicts/candidates.yaml do not:
    • Categorical households. Plan 1.4a and 1.6 (p. 5, rendered) say these households "will have their benefit calculated based on the highest FPL allowable for each benefit type above", unless they choose to document actual income. The PR uses actual income, which rule 3(C)(2) also allows.
    • Size 10. Plan 2.1 (p. 9) assigns size 10 to "HHS Poverty Guidelines 150.00%" ($97,725). The 2025-26 chart prints $102,008 (60% of SMI), and the PR follows the chart.
    • At-risk points. The April 2026 proposed-rule memo says the new matrix "will add points for additional at-risk household members" (p. 66). The adopted table prints only "Points for the first in the house", and the PR follows the table.
    • Members over 18. The PR counts members aged 18 and older under "over the age of 18". Plan 1.9's unchecked "Earned income of a child under the age of 18" box supports that reading; say so in the body.
  • Fix:
    • Add a us-me:heap-... candidate for the categorical and size-10 readings with prs: [#10437], as us-al:liheap-lump-sums-and-refunds and us-sd:liheap-cash-gifts do (Add Minnesota EAP Primary Heat benefit #10433 G3, Add Missouri LIHEAP Energy Assistance #10438 G2).
    • Note the at-risk memo in the body.
    • Change the body's "the HEAP Guide is not public" to say that it was posted and is no longer available. Asking MaineHousing for the PY2026 or PY2027 Guide could settle the income period, the categorical percentages and unlisted fuels.

G5. Add Wayback captures for three URLs that MaineHousing or the Secretary of State overwrite.

  • The rule PDF. .../msha-rules/ch24-home-energy-assistance-program-rule.pdf held the 2025 edition until the June 29, 2026 rule replaced it, and it will be replaced again. Every 2026-rule anchor (pages 10-17) would then drift.
  • The Word copy. The Secretary of State's 346c024.docx still holds the 2025 edition (filing history ends "2025-135"). It should soon be replaced by filing 2026-134, leaving every 2025-edition reference pointing at the wrong edition.
  • The chart. mainehousing.org/charts/ shows the 2026-27 chart (modified 2026-07-22) and is replaced each season.
  • Fix: add a dated capture beside each, as Add Minnesota EAP Primary Heat benefit #10433 G6 and Add Missouri LIHEAP Energy Assistance #10438 G5 asked. The 2025-26 chart already uses one.

G6. Reconsider the stick-built default for me_heap_dwelling_type.

  • The default. V/me_heap_dwelling_type.py:14 defaults to STICK_BUILT_OR_MODULAR, the highest dwelling row in both editions. In microsimulation every household, renters and heat-in-rent tenants included, gets it.
  • Example. A 2026 unsubsidized heat-in-rent renter (natural gas, Cumberland, wages $30,472, 0.70) gets 9 + 3 + 5 = 17 × 0.70 = 11.9, rounded up to 12, so $264 with the default, against 14 × 0.70 = 9.8, rounded up to 10, so $220 as an apartment.
  • Fix: derive the default from tenure (renters and heat-in-rent tenants as CONDO_DUPLEX_OR_APARTMENT), as Add Minnesota EAP Primary Heat benefit #10433 G4 suggested for Minnesota's HOUSE default. Otherwise, state the effect in the variable documentation and the body.

Verified correct

Values against sources:

  • Points, 2025 edition (FY2026 matrix pp. 1-2; the SOS Word copy is identical):
    • stick-built/modular 9, mobile/manufactured 8, condo/duplex and apartment 6;
    • all 16 counties (Aroostook 7; Somerset, Franklin and Piscataquis 6; Oxford and Penobscot 5; Androscoggin and Hancock 4; Waldo, Cumberland, Lincoln, Knox and York 3; Washington, Kennebec and Sagadahoc 2);
    • electricity 14, LP gas 10, kerosene 8, oil 7, coal 5, natural gas 5, wood 4;
    • "Responsible for Heating" -9;
    • "60+, Disabled or child 6 and under" 5, "or" child 7-17 3;
    • the seven bands (130% down to 70% "not exceeding the maximum of the greater of 150% FPIG or 60% state median income");
    • the rounding examples ("75.1% will be rounded to 75%; income at 100.6% will be rounded to 101%") and "All final point results that are fractional will be rounded up".
  • Points, June 29, 2026 rule (pp. 16-17; effective date p. 33):
    • base 8; dwelling 3/2/1/1;
    • counties (Aroostook 6; Franklin 5; Somerset, Piscataquis, Oxford, Hancock and Washington 4; Sagadahoc, Penobscot and Waldo 3; Androscoggin, York, Knox and Lincoln 2; Cumberland and Kennebec 1);
    • electric 8, LP gas 5, kerosene 5, oil 4, coal 4, natural gas 3, wood 3;
    • at-risk 5 "for the first in the house" and no older-child row; heating subsidized -3;
    • bands 0-10.99% 1.8, 11-33.99% 1.6, 34-75.99% 1.4, 76-100.99% 1.2, 101-125.99% 1, 126-150.99% 0.9, 151-175.99% 0.8 and >176% 0.7.
    • Rounding half up to hundredths, and 0.7 at exactly 176.00%, are documented readings of a rule with no rounding sentence.
  • Income limit (rule 3(C), p. 11; 2025-edition 70% row; 42 U.S.C. 8624(b)(2)(B)):
    • SMI. $118,065 (FFY2026) and $122,022 (FFY2027) on main give 70,839 and 73,213 at 60%.
    • 2025-26 chart, all 10 rows: 36,836, 48,170, 59,504, 70,839, 82,173, 93,507, 95,632, 97,757, 99,882 and 102,008.
    • 2026-27 chart, all 10 rows: 38,070, 49,784, 61,498, 73,213, 84,927, 96,641, 98,837, 101,033, 103,230 and 105,426.
    • 150% of the lagged guideline binds from size 11 in 2026 (105,975 against 104,133), as plan 2.1 assigns sizes 11-12. The 110% floor never binds.
  • Dollar amounts:
    • $22 a point for 2025-26 (plans 2.6, FY2025 p. 8 and FY2026 p. 10: $88 and $1,012);
    • $21 subsidized heat-in-rent (plan 1.7b, p. 5, rendered: "$21.00", "Once Per Year"; rule 4(C) of the 2025 edition and 4(B) of the 2026 rule; the draft FFY2027 plan repeats $21.00).
  • Countable income (plan 1.8 "Gross Income"; rule 3(C)(1), pp. 11-15):
    • Social Security and SSI gross "including Medicare deductions", with plan 1.9's "Including MediCare deduction" box checked. The Part B premium enters only through the over-income medical adjustment.
    • Medical adjustment. It uses medical_expense_health_insurance_premiums (modeled Part B for enrollees plus other premiums) and other_medical_expenses. Excluding pre_tax_health_insurance_premiums matches Publication 502 ("Don't include in your medical and dental expenses any insurance premiums paid by an employer-sponsored health insurance plan unless the premiums are included on your Form W-2"), and "Premiums you pay for Medicare Part B are a medical expense". It stops at the limit, as "equal to only the amount necessary to make the Household eligible" requires.
    • Loss floors. A per-source floor on all 22 sources, so neither business nor rental losses offset wages (the wave's losses precedent passes).
    • Exclusions: retirement drawdowns ("Assets drawn down from financial institutions"); a full-time high-school student who is not the Primary Applicant (tax-unit head proxy); capital gains, refunds and SNAP.
    • Members: under 18 excluded; the income of members outside the counted size included (p. 15).
  • Eligibility:
    • size counts is_citizen_or_legal_immigrant (3(A)(1), p. 6), and size 0 is ineligible;
    • categorical SNAP or TANF (3(C)(2); plan 1.4: TANF and SNAP "Yes", SSI "No", rendered);
    • a Direct or Indirect Determinable Energy Cost (3(A)(4)) through has_heating_expense or heat_expense_included_in_rent;
    • NONE fails the functioning-heating-system test (3(B)(1)(a));
    • subsidized heat-in-rent tenants qualify (3(B)(3));
    • Subsidized Housing is receives_housing_assistance or is_in_public_housing, a documented subset of 1(VV).
  • Benefit formula (4(A)): points × multiplier × counted share of members, rounded up, × value. FLOAT_GUARD_DECIMALS is a numerical tolerance, documented as such, and Case 10 pins 22.000000000000004 to 22.
  • Years:
    • 2026 and 2027 are verified, apart from G2.
    • Earlier years. Parameters start 2024-07-03 or 2024-10-01, so period 2025 and earlier take the 2025-edition values. That is right for the 2024-25 season (same matrix, same $1,012 plan maximum) and an unclaimed, documented backfill before it (verified_years: "2026-2027"; NJ S3 pattern).

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

  • Income limit Case 1: floor(0.6 × 118,065) = 70,839; 70,839 × 0.52 = 36,836.28, giving 36,836 (150% is 23,475).
  • Income limit Case 2: size 10, factor 1.44, 102,008.16 gives 102,008 (150% = 97,725); size 11, 1.47 gives 104,133 against 150% × 70,650 = 105,975.
  • Income limit Case 3 (2027): floor(0.6 × 122,022) = 73,213; × 0.52 = 38,070.76, giving 38,070; size 4 73,213.
  • Eligibility Case 1: 36,836 is eligible, 36,837 is not, and 36,837 with SNAP is eligible.
  • Eligibility Case 3: voucher and public housing with heat in the rent are true; unsubsidized UNSPECIFIED is false (G1); unsubsidized natural gas is true; NONE is false.
  • Eligibility Case 4: TPS and undocumented give size 0, limit 0, false.
  • Income Case 1: 30,472 (the 18-year-old student and the 17-year-old excluded).
  • Income Case 2: 15,236 + 22,854 = 38,090.
  • Income Case 4: 19,045 + max(-4,200, 0) + 8,000 = 27,045.
  • Income Case 7: 30,472 + 11,427 = 41,899, with size 2.
  • Income Case 8: 38,948 > 36,836; 38,948 - 2,220 = 36,728, so the result is 36,836 and eligible.
  • Income Case 9: 42,757 - 2,220 = 40,537, ineligible.
  • Multiplier Case 1: 3,975.10 / 15,650 = 25.40%, rounded to 25%, gives 1.3; 3,990.75 / 15,650 = 25.50%, rounded to 26%, gives 1.2.
  • Multiplier Case 2: 74.15%, 97.35%, 121.15%, 146.03% and 194.71% give 1.1, 1.0, 0.9, 0.8, 0.7.
  • Multiplier Case 3 (2027, guideline 33,000): 10.99% / 11.00% give 1.8 / 1.6; 75.99% / 76.00% give 1.4 / 1.2; 175.99% / 176.00% give 0.8 / 0.7.
  • Points Case 3: 11 plus each fuel gives 25, 25, 21, 19, 18, 16, 16, 15. Case 4 (2027): 12 plus each fuel gives 20, 20, 17, 17, 16, 16, 15, 15.
  • Points Case 6: 18 plus 5 / 3 / 3 / 0 gives 23, 21, 21, 18. Case 7 (2027): 16, 21, 21.
  • Points Cases 8-9: 22 - 9 = 13 (voucher and public housing), 22; 2027: 18 - 3 = 15, 18.
  • Points Case 10: 22,854 / 32,150 = 71.09%, rounded to 71%, gives 1.1; 25 × 1.1 × 4/5 = 22, so $484.
  • Points Case 11 (2027): 31,408 / 21,640 = 145.14% gives 0.9; 21 × 0.9 × 2/3 = 12.6, so 13 and $286.
  • me_heap Case 1: IRA excluded, income 0, 1.3; 35 × 1.3 = 45.5, so 46 and $1,012.
  • me_heap Case 2 (2027): 24,852 / 15,960 = 155.71% gives 0.8; 18 × 0.8 = 14.4, so 15 and $330.
  • Integration Cases 1-3:
    • Case 1: 23,712 / 15,650 = 151.51%, rounded to 152%, gives 0.7; 26 × 0.7 = 18.2, so 19 and $418.
    • Case 2 (2027): 47,112 / 33,000 = 142.76% gives 0.9; 18 × 0.9 = 16.2, so 17 and $374.
    • Case 3: 25,254 / 26,650 = 94.76%, rounded to 95%, gives 1.0; 6 + 7 + 10 + 5 - 9 = 19, so $418.
  • Case count: 2 + 4 + 3 + 4 + 4 + 1 + 9 + 4 + 12 = 43, as the body says.

Batch checks:

Wiring and housekeeping:

  • Registry. The ME entry sits between MD and MS with verified_years: "2026-2027", and ME is added to the coverage line. test_programs_registry passed.
  • Aggregates. There is no aggregate wiring, which matches every merged LIHEAP state.
  • Gating. defined_for = StateCode.ME is on 7 variables, and me_heap is gated by me_heap_eligible. test_members_are_state_gated passed.
  • Changelog. changelog.d/me-liheap-wave1d.added.md is top level and typed added.
  • Shared parameter. gov.hhs.liheap.fpg_limit (1.5 from 1981-10-01) matches 42 U.S.C. 8624(b)(2)(B)(i). The Vermont branch's copy is byte-identical, so the two merge cleanly.
  • Descriptions (item 6): all 20 end "under the Low Income Home Energy Assistance Program." with nothing after it.
  • References (item 7):
    • Every anchor I opened shows its value: rule pp. 10, 11, 11-12, 11-13, 15, 16 and 17; matrix pp. 1, 2 and 1-2; plan pp. 5, 6-7, 9 and 10; FY2025 plan p. 8.
    • Multi-page titles use the quoted #page 11-12 form, and variables use # PDF pages comments.
    • Wayback captures are G5.
  • Tests. The files are variable-named, every period is plain, and every eligibility or benefit case sends heating_type.

Checklist results (LIHEAP batch):

  1. State plan and rule: every matrix cell, limit row and dollar amount matches. The 2026-27 point value is G2.
  2. Income definition: gross income, Social Security gross (Maine's rule), per-source floors and the medical adjustment are right. Omitted annuities are S1; TANF and long-term disability are S2.
  3. Backdating: pass for 2026-2027. Earlier years are a documented, unclaimed backfill.
  4. Household and arrangement rules: heat in rent (subsidized and unsubsidized), subsidized points and categorical eligibility are right. The listed-fuel gate is S3, UNSPECIFIED is G1 and the dwelling default is G6.
  5. Tests: 43 cases, 24 hand-checked, all periods plain. Source coverage is S4.
  6. Descriptions: pass.
  7. References: pass (Wayback captures are G5).
  8. Wiring: pass.
  9. Axiom: valid (Add DC TANF maximum income #1898).
  10. Branch and CI: a clean merge with main; 27 pass and 3 skipping.
  11. Integrate modeled state unemployment insurance into income flows #9558: pass.
  12. IIJA / FY2027: not applicable / FY2027 from the June 29, 2026 rule and chart.
  13. Mutation check: 19 entries and one branch are unpinned (S4).
  14. Document disjoint health premium inputs and correct consumer treatment #10046: pass.
  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: me_ssp not counted (G3).

Axiom line assessment

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

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

  • It matches the head. It names head bbdb9b5f78 and merge base 6a92d6a983. It lists the 43 cases by file. Its required outputs (size, limit, countable income with the same 5 earned and 17 unearned sources, categorical eligibility, multiplier, points, eligibility and benefit) describe the head's code.

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

    • proposed us-me/ module paths, with corpus status per source;
    • verbatim text of both rule editions, the plans and both charts;
    • companion tests derived from the sources, not from PE output;
    • 16 interpretations;
    • its blockers: sources missing from the corpus, no published point value, an unchecked signed release, billed-run approval and no reviewed oracle revision.
  • Note. The fixes change these interpretations and outputs:

    • S1 and S2 change interpretation 8 and the countable-income output;
    • S3 and G1 change interpretation 11 and the eligibility and points outputs;
    • S4 adds cases;
    • G2 changes interpretation 1;
    • G3 changes interpretation 8;
    • G6 changes interpretation 14.

    Update the issue with the head that resolves them.

CI status

27 pass, 0 failed, 3 skipping, none pending. I re-checked gh pr checks 10437 at the end of this review.

  • The runs. Run 40032620248 tested head bbdb9b5f78 (pull_request, created 2026-10-23 22:17 UTC, after Tie source-conflict markers to the register shared with Axiom #10287, the 2026-10-21 cutoff and Count military SBP annuities in state benefit income lists #10317, which is in the base). The three skipped checks belong to an earlier trigger on the same head (run 40032382104, 22:15 UTC).
  • Maine tests. States-shard-3, batch 6/13 (states/me, 80 files, exit 0), ran all 9 files: 2 + 4 + 3 + 4 + 4 + 1 + 9 + 4 + 12 = 43 passed.
  • Guards (Rest shard-1):
    • the four test_unemployment_compensation_readers.py tests;
    • the four test_military_retirement_readers.py tests;
    • the test_source_conflicts.py tests, including test_conflict_sounding_comments_do_not_grow;
    • 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 and G1-G6 examples are hand traces of the code at the head. The only local scripts were text extraction and page renders of the sources and the static comment-pattern scan.

Branch status

0 critical, 4 should and 6 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.

Every points-matrix cell matches its edition, the income limit reproduces all 20 published chart rows, $22 a point and the $21 subsidized amount check out, Social Security correctly counts including Medicare deductions (rule 3(C)(1)(c)), and 24 expectations hand-check. Four should-address items: (1) railroad and survivor annuities aren't counted, though rule 3(C)(1)(i) counts regular annuities ($748 vs $462 for a $20k railroad retiree); (2) TANF follows the plan over the rule while long-term disability follows the rule over the plan, unrecorded; (3) eligibility requires a listed fuel, which the rule doesn't, so OTHER-fuel households get $0; (4) 19 income and expense entries and the public-housing branch are untested. Six 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 Maine HEAP regular heating assistance

2 participants