Skip to content

Add Rhode Island LIHEAP regular heating assistance - #9972

Merged
hua7450 merged 16 commits into
mainfrom
ri-liheap-wave2a
Oct 20, 2026
Merged

hua7450 merged 16 commits into
mainfrom
ri-liheap-wave2a

Conversation

@hua7450

@hua7450 hua7450 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Adds Rhode Island's LIHEAP regular heating assistance. The model counts citizens and qualified noncitizens for household size and the income of adult members, tests income against 60% of state median income, and places the household in one of five bands by the prior year's poverty guideline. It pays the FY2026 primary heating grant for the household's fuel, plus the $350 utility enhancement on natural gas and electric grants, and the FY2026 heat-in-rent grants. In FY2026, a one-person household with $10,000 of wages and its own heating bill receives $861 for fuel oil, $582 for natural gas ($232 plus $350) and $743 for electricity ($393 plus $350). If heat is included in its unsubsidized rent, it receives $400, or $430 ($80 plus $350) when it pays a separate electric bill. With electric heat included in that rent and no electric bill, it receives $0, because matrix row G leaves the Electric cell blank. Earlier years and FY2027 reuse the FY2026 payment schedule as unverified estimates. Income below 110% of the prior-year poverty guideline also passes the income test under the federal floor, which first exceeds the 60% SMI limit at 23 qualified members in FY2026 and FY2027.

Fixes #9963

Regulatory authority

The model follows the DHS manual published June 11, 2019 and filed with the Public Utilities Commission in Docket 4290. Later editions exist: the Appendix H footers read "RI LIHEAP Policy Manual Appendix H May 2025" and "RI LIHEAP Policy Manual Appendix H July 2026", and the footer of the FFY2026 notice to applicants reads "RI LIHEAP Policy Manual July 2025". A search found none of these editions online.

Eligibility

Requirement Source How modeled
Rhode Island residence — defined_for = StateCode.RI
Household size counts citizens, permanent residents and qualified noncitizens Manual section III, page 12 Counts members with is_citizen_or_legal_immigrant, with no SNAP-specific waiting periods or bars. A household with no qualified member is ineligible. The income of nonqualified adults counts.
Income at or below 60% of state median income FY2026 plan section 2.1, page 8; FY2026 and FY2027 income tables Calls the shared liheap_smi_limit helper (#10019): floors 60% of the four-person state median income, applies the federal size share and floors again. This order reproduces all 14 published limits in FY2026 and FY2027; the sources do not state the order. One person: $42,252 in FY2026 and $43,410 in FY2027. The limit is inclusive.
Federal 110% poverty floor 42 U.S.C. 8624(b)(2)(B); FY2026 plan assurances, page 45 Income below the floor, 110% of the poverty guideline for the qualified size rounded to the cent, also passes the income test. The rate comes from gov.hhs.liheap.fpg_floor (1.1), a file byte-identical to the copy in #10279. The guideline uses the bands' one-year lag (gov.states.ri.dhs.liheap.fpg_year_lag): the 2025 guideline in FY2026 and the 2026 guideline in FY2027. The 60% SMI limit falls below the floor from size 23 in FY2026 and FY2027 (23 people: limit $148,694 and floor $150,315 in FY2026; $152,770 and $155,012 in FY2027), from size 21 in the 2025 backfill and from size 19 in the 2024 backfill. ri_liheap_income_limit keeps the published limit.
Energy burden Manual sections II.B and III.A, pages 5–6 and 12 Without heat in rent, a reported obligation (has_heating_expense) or a positive heating bill qualifies. Heat included in unsubsidized rent qualifies. A household with housing assistance or in public housing whose rent includes heat needs a positive electric bill (pre_subsidy_electricity_expense), whatever heating obligation it reports. heating_type NONE is ineligible.
No categorical eligibility and no asset test FY2026 plan question 1.4, page 5, and section 2.3, page 8 SSI or TANF receipt does not waive the income limit; assets are not tested.

Countable income

Item Source How modeled
Members whose income counts Manual section III.G, page 20; FY2026 and FY2027 application instructions, page 2 Counts income of members 18 or older, except a full-time student aged 18–23, whether or not the student heads the household. All income of members under 18 and of excluded students, including SSI and interest, is excluded.
Earned income Manual section III.E, pages 14–17; FY2026 plan sections 1.8–1.9, pages 5–7 Counts wages and net self-employment, SSTB, farm operations and partnership/S-corporation income, each floored at zero, with no further self-employment deduction (see the 40% row below).
Unearned income Manual section III.E, pages 14–17; FY2026 plan section 1.9, page 6 Counts unemployment (total_unemployment_compensation: the reported amount, or modeled state unemployment insurance when none is reported), strike benefits, Social Security (gross), SSI, pensions, military retirement pay, retirement account distributions, survivor benefits, railroad retirement, alimony, child support received, workers' compensation, disability benefits (standing in for Temporary Disability and Temporary Caregivers Insurance), cash support (financial_assistance), ordinary dividends, veterans benefits, estate income and gambling winnings. Floors each source at zero, so a loss in one source offsets nothing.
Rental income Manual sections III.E and III.G, pages 16 and 20; Appendix M Counts 50% of rental and farm rental income, each floored at zero.
Interest Manual section III.G, page 20; application instructions, page 2 Floors each counted member's interest at zero, so a negative entry offsets no other member's interest, then subtracts $500 a year once from the combined interest.
TANF (RI Works) FY2026 plan section 1.9, page 6 Counts the take-up-gated tanf aggregate, which includes ri_works, once per household.
Deductions Manual section III.H, pages 20–21 Subtracts child support and alimony paid and the Medicare Part B premium of every member, including members whose income is excluded or who are not counted in the size, plus child care expenses when the household receives no child care subsidy. Income after deductions is floored at zero.

Benefit

Income band (share of prior-year guideline) Matrix row Delivered fuels Natural gas Electricity
Up to 75% A $861 $232 $393
76–100% B $805 $211 $357
101–125% C $752 $192 $324
126–150% D $704 $175 $295
Above 150% E $657 $159 $268
Subsidized housing with a primary heating bill, any income F $657 $159 $268
  • Delivered fuels are fuel oil, kerosene, propane and wood. Natural gas and electricity grants add the $350 enhancement (R.I. Gen. Laws § 39-1-27.12; DHS response 1-1; PUC Order 25579), so a row A gas grant is $582 and a row F electric grant is $618.
  • Band thresholds are the guideline times 75%, 100%, 125% and 150%, rounded half up to the annual dollar and upper-inclusive: $11,738, $15,650, $19,563 and $23,475 for one person in FY2026. The printed size-two 125% cell repeats the 150% amount ($31,725); the model applies the labeled 125% rate ($26,438).
  • Row F applies at any income to a household with housing assistance or in public housing that has its own primary heating obligation, using the same obligation test as eligibility. The FY2026 matrix prints the same cells for rows E and F, so the model reads row E's amounts for row F.
  • Heat-in-rent households receive rows H–I for any fuel, including an unspecified one. A household with no separate electric bill receives row G directly, read from its fuel column (heat_in_rent.direct): Deliverables, Natural Gas and Other print $400, and the blank Electric cell is $0, so electric heat included in unsubsidized rent with no electric bill is eligible but receives $0. Coal and solar read the Other cell ($400) because Appendix B has no coal or solar box. As a modeling assumption, an unspecified fuel (heating_type UNSPECIFIED, the input for heat in rent with an unknown fuel) also reads the Other cell; when the building heats with electricity, the matrix pays $0 and the model overpays $400. A household with a separate electric bill receives $80 on that electric account (row H), or $50 in subsidized housing (row I), plus the $350 enhancement: $430 or $400. A subsidized heat-in-rent household with no electric bill is ineligible.
  • Outside heat in rent, coal, other and solar have no matrix amount: the Other column is blank in rows A–F, and Appendix B has no coal or solar box, so a household would mark those fuels Other. These households stay eligible when they have their own bill and receive $0. An unspecified fuel has no bill input, so outside heat in rent it meets the energy burden only when has_heating_expense is set; it then receives $0 because heating_type is a required input (Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754).
  • The reported bill does not cap the award.

Years covered

Model year Program year One-person income limit Payment
2025 and earlier FY2025 and earlier Computed; unverified FY2026 matrix and $350 enhancement backfilled; unverified
2026 FY2026, October 1, 2025 to September 30, 2026 $42,252 FY2026 matrix and $350 enhancement
2027 FY2027, from October 1, 2026 $43,410, matching the FY2027 table FY2026 amounts, including the $350 enhancement, carried forward; unverified

A calendar-year period reads the parameters in force on January 1. Formulas are undated and verified_years is "2026". Earlier years backfill the FY2026 grants and enhancement as unverified estimates. The FY2025 plan (section 2.6, page 9) gives a $64 minimum and $1,148 maximum benefit, compared with FY2026's $50 and $861, so 2025 and earlier results do not reproduce those years' awards.

A search for the FY2025 grant matrix and enhancement found neither. It covered the ACF clearinghouse (the FY2025 matrix links return 404 on both clearinghouse domains), Wayback captures of the clearinghouse benefit page and of DHS's FY2025 guidelines and LIHEAP pages (income limits only), the FY2025 state plan, and Docket 23-33-EL: the DHS filing of October 8, 2024, the Division memo of November 13, 2024 and PUC Order 25281, which set the charge but not the grant. Earlier years differ as well: the FY2024 matrix differs from FY2026 in every cell, and PUC Order 24925 sets the enhancement at $515 for 2024 and $450 for 2023. RI Energy's April 2025 reconciliation shows FY2025 credits in multiples of $360, but no document states that amount, so the model does not encode it.

No adopted FY2027 matrix was found. DHS's October 2, 2026 filing in Docket 26-34-GE (page 2) says "Accounts receiving a 2027 Primary benefit will receive one additional credit from the LIHEAP Enhancement Fund" and leaves the amount to DHS, so the model carries the $350 forward as an unverified estimate.

Not modeled and source conflicts

Item Source Model treatment
Heat-in-rent payment route (matrix rows G–I) FY2026 matrix; manual section II.B, page 5 A reported separate electric bill selects the secondary-electric grant; otherwise the household receives the row G grant for its fuel column ($400 for deliverables, natural gas, other, coal, solar and unspecified fuels; $0 for electricity, whose cell is blank). The manual allows payment to a secondary heating source or utility or directly to the applicant but does not say how the route is chosen.
Electric heat in unsubsidized rent with no electric bill FY2026 matrix row G (Electric cell blank) Eligible; pays $0, with no enhancement.
$20.01 nominal payment for SNAP households in subsidized housing with heat in rent FY2026 plan section 1.7, page 5 Not modeled.
Utility provider and grant account R.I. Gen. Laws § 39-1-27.12; DHS PUC response, page 2 The enhancement assumes a qualifying distribution-company account receives the federal grant, including a heat-in-rent grant to a secondary electric account. Customers of the Block Island Utility District and the Clear River Electric and Water District, which the statute excludes, cannot be identified.
Full-time students who head the household Manual section III.G, page 20; FY2026 (Appendix H) and FY2027 application instructions, page 2 The 2019 manual excludes only a full-time student child who is not the household head; the current instructions exclude every full-time student aged 18–23. The model follows the current instructions.
40% self-employment deduction on gross receipts Manual section III.H, page 20; DHS FY2026 plan summary, page 1 ("Self-employment income (60%)") Uses existing net business inputs in full with no further deduction, as Kansas LIHEAP does. This equals the manual's 60% of receipts only when expenses are 40% of receipts; it overstates income when expenses are lower and understates it when they are higher. No gross-receipts or expense input is added.
Nursing-home and adult day care payments; Medicare costs other than the Part B premium, including prescriptions Manual section III.H, pages 20–21 No sufficiently specific inputs; not deducted.
VA education and Aid and Attendance exclusions Manual section III.G, page 20 Cannot be separated from veterans_benefits, which counts in full.
Gross rents Manual section III.G, page 20 Existing rental inputs may hold net rather than gross rents.
Payments from mortgages or sales contracts, AmeriCorp living allowances, jury duty pay, royalties, foster care receipts and legal settlements; contract income FY2026 plan section 1.9, pages 5–7; DHS FY2026 plan summary, page 1 No specific existing input; not counted. Contract income counts only when reported as wages or self-employment income.
State SSI supplement — Not modeled; ssi is the federal benefit.
Coal, other, solar and unspecified fuels outside heat in rent FY2026 matrix; Appendix B Coal, other and solar households with their own bill are eligible and receive $0: the Other column has no amount in rows A–F, and Appendix B has no coal or solar box. An unspecified fuel has no bill input, so it is eligible only when has_heating_expense is set, and it receives $0 because heating_type is a required input (#9754).
Crisis, cooling and weatherization assistance — Out of scope.

Where the FY2026 plan and the manual differ, the model follows the manual:

Topic FY2026 plan Manual and model
Lottery winnings and cash prizes Section 1.9 (page 6) leaves "One-time lump-sum payments, such as rebates/credits, winnings from lotteries" unchecked. DHS's FY2026 and draft FFY2027 plan summaries and the application instructions do not list them either. Section III.E (page 17) lists "Cash Prizes and Lottery Winnings" as income; the model counts gambling_winnings.
Workers' compensation and temporary disability Section 1.9 (page 6) leaves "Insurance payments made directly to the insured" unchecked Section III.E counts "Temporary Disability Insurance (TDI), Temporary Caregivers Insurance (TCI)" (page 15) and "Workers' Compensation" (page 16); the model counts disability_benefits and workers_compensation.
Subsidized renters Section 2.3 (page 8) answers "No" to differing eligibility policies for "Renters Living in subsidized housing?" Section II.B (page 6): "Subsidized renters with no utility burden are ineligible for this program." The model requires a subsidized heat-in-rent household to have a separate electric bill.

Plan section 1.9 (page 6) counts Social Security "Including MediCare deduction". Only DHS's draft FFY2027 plan summary (page 3) glosses this, as "meaning the Medicare amount deducted is not counted"; read that way, the plan agrees with manual section III.H (page 21). deduction_sources.yaml cites the draft until DHS posts a final FFY2027 summary; a search found none online. The model counts Social Security gross and deducts medicare_part_b_premium.

Microsimulation: the microsimulation datasets carry no heating inputs, so population totals are about $0 until #9754 lands. Callers must send heating_type with the matching fuel bill.

Test plan

74 YAML cases in 8 files cover:

  • all 15 FY2026 primary amounts with the enhancement on gas and electricity, the shared delivered-fuel amount, row F for either subsidy flag and for an obligation flag with no bill, the enhancement following the primary fuel despite other utility bills, and $0 for unpriced fuels, no heat, zero qualified size and out of state;
  • band edges at the exact dollar and the next cent for one person, the size-two 125% anomaly and 2025 bands on the 2024 guideline;
  • all 14 FY2026 and all 14 FY2027 income limits and the inclusive ceiling;
  • the federal 110% floor: 23 members (forced) at $150,314.99 eligible and at $150,315 and $150,315.01 not, all above the $148,694 limit, and a 23-member household with $150,000 paid $542 (row C gas);
  • a mixed-status family whose qualified size is 2 of 3 members at the two-person limit ($55,252: eligible, $509) and one cent above (ineligible);
  • each energy-burden route, including subsidized heat in rent with and without an electric bill and a subsidized heat-in-rent household that reports a heating obligation but no electric bill (ineligible), and a household with no qualified member and no income, which only the size check makes ineligible;
  • heat-in-rent grants: $400 direct for oil, gas and other fuel, $400 for an unspecified, solar or coal fuel (row G Other), $430 with a separate electric bill, $400 for subsidized housing or public housing with an electric bill, no direct grant for subsidized heat in rent without an electric bill under either subsidy flag, and electric heat in unsubsidized rent at $0 without an electric bill and $430 with one;
  • coal, solar and other heat with a direct bill: eligible, $0;
  • the age 17 and 18 boundary and the student exclusion at 23 and 24 and for a student living alone, the $500 interest exclusion, the exclusion of a minor's and a full-time student's interest ($12,000), 50% rental income, SSI and TANF counted once, TANF with and without take-up, child SSI excluded, nonqualified parent income, estate income, military retirement pay and retirement distributions, lottery winnings, reported unemployment compensation read through total_unemployment_compensation ($10,010), every listed unearned source at once ($17,300), the Part B deduction, support and unsubsidized child care deductions, the zero floor, business, estate and rental losses, a negative interest entry that cannot offset another member's interest ($12,200), and child support and alimony paid by an excluded student and a nonqualified member deducted ($46,920);
  • final awards set by retirement account distributions and by the Part B deduction;
  • five end-to-end integration scenarios: an SSI retiree with electric heat ($707), a working single parent with gas ($542), a family of four with a college student and fuel oil ($657), a public housing tenant with heat in rent and an electric bill ($400), and a working couple above the limit ($0);
  • the backfilled 2025 estimates ($861 for oil and $430 for heat in rent with an electric bill), which check the backfill only, since the FY2025 plan gives a $64 minimum and $1,148 maximum benefit.

Every eligibility and payment case specifies heating_type; the income, limit, band and household-size cases omit it because those variables do not read it. CI validates the cases.

  • YAML tests whose expected values come from an external source (statute, official form or worksheet, official calculator)
  • make format
  • Changelog fragment in changelog.d/

axiom: TheAxiomFoundation/rulespec-us#1537 queued

🤖 Generated with Claude Code

hua7450 and others added 5 commits October 3, 2026 19:49
- Start regular heating payments in FY2026 with a dated in_effect switch:
  no FY2025 benefit matrix is published, so 2025 and earlier pay $0.
- Use the eligibility primary-bill test for subsidized row F.
- Count military retirement pay, retirement distributions and gambling
  winnings; floor each unearned source at zero.
- Count TANF through the take-up-gated tanf variable instead of ri_works.
- Deduct the Medicare Part B premium per manual III.H (p21); rename the
  deduction list to deduction_sources.
- Put RI on the LIHEAP coverage line and shorten its note.
- Add tests for each change.

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

# Conflicts:
#	policyengine_us/programs.yaml
@codecov

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

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9972   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         7    +3     
  Lines           76       147   +71     
  Branches         2         3    +1     
=========================================
+ Hits            76       147   +71     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

hua7450 and others added 6 commits October 7, 2026 22:56
Follow the FY2026/FY2027 application instructions over the 2020 manual's household-head exception, drop the unused is_household_head test inputs, and note the plan-versus-manual conflict for workers' compensation and TDI/TCI.

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
One reference entry per source; single-page citations keep the page only in the href; multi-page titles end with a quoted #page list and the href opens the first cited page; variable references use '# PDF pages ...' comments above multi-page hrefs (CLAUDE.md, PolicyEngine/policyengine-us PR 10009). Reference lines only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Heat-in-rent households receive the FY2026 matrix rows G-I: a $400 direct
grant, or an $80 secondary-electric grant ($50 when subsidized) when a
separate electric bill is reported, with the $350 utility enhancement on
the secondary-electric grant. Subsidized heat-in-rent tenants without a
utility burden are ineligible. The research-date payment gate is removed,
so earlier years backfill the FY2026 schedule as unverified estimates.
Utility provider and grant receipt stay an assumption; no new input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Calls liheap_smi_limit from PR 10019 instead of repeating the HHS
floor-then-floor calculation. Limits are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hua7450
hua7450 marked this pull request as ready for review October 12, 2026 05:54
@DTrim99

DTrim99 commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Add Rhode Island LIHEAP regular heating assistance

PR #9972: Add Rhode Island LIHEAP regular heating assistance (author: hua7450, head c8b6cafa25)

Scope: Rhode Island's LIHEAP regular (primary) heating grant, run by DHS through seven Community Action Agencies, for FY2026. The PR covers:

  • household size, which counts citizens and qualified noncitizens, and countable income, which counts members 18 and over except full-time students aged 18-23, with the manual's interest, rental, support, child-care and Medicare rules;
  • the income limit at 60% of state median income, through the shared liheap_smi_limit helper;
  • five payment bands at 75%, 100%, 125% and 150% of the prior year's poverty guideline;
  • the FY2026 Grant Amounts matrix: rows A-E for Deliverables, Natural Gas and Electric, row F (subsidized housing with a primary heating bill) and heat-in-rent rows G-I;
  • the $350 LIHEAP Enhancement credited with a gas or electric primary grant (R.I. Gen. Laws § 39-1-27.12).

Crisis, cooling, weatherization and the $20.01 SNAP nominal payment are out of scope. The PR changes 31 files: 15 parameters, 7 variables, 7 test files (55 cases), programs.yaml and a changelog fragment. Every parameter has a single 2025-10-01 value, the tests use periods 2026, 2025 and 2027, and the registry lists verified_years: "2026".

Overall: the FY2026 policy values are right.

  • All 15 primary cells, the 3 row F cells, rows G-I ($400 / $80 / $50) and the $350 enhancement match the matrix and the PUC record.
  • All 28 published FY2026 and FY2027 income limits reproduce, and 41 of the 42 printed 75%, 125% and 150% band tops do. The 42nd is the matrix's size-2 "125%" cell, which repeats the 150% amount; the PR documents that it follows the labeled rate.
  • The income rules follow the manual and the current application instructions, and losses are floored per source.
  • Social Security is counted net of the Part B premium. That matches DHS's own reading of plan item 1.9: its draft FY2027 plan summary glosses "Including Medicare deduction" as "meaning the Medicare amount deducted is not counted".
  • The backfilled FY2024 and FY2025 limits reproduce. Earlier payments do not, which the PR documents (G1).

There are no critical findings. The five should-address items:

  • S1: a merge blocker from main's Integrate modeled state unemployment insurance into income flows #9558. The unearned list reads the raw unemployment_compensation input, so main's new code-health guard fails on the merged tree. Rhode Island has no modeled unemployment insurance yet, so no household value changes today.
  • S2: matrix row G prints no Electric amount, but the PR pays $400 to unsubsidized electric-heat households with heat in rent and no electric bill. The code and PR body do not say why, and no test covers it.
  • S3: no test would fail if the interest exclusion for minors and students or the eligibility size gate broke, and 8 of the 18 unearned sources are never nonzero in any test.
  • S4: six parameter descriptions fall outside the house template.
  • S5: one manual anchor opens the wrong page, Appendix H is linked without its page and from two hosts, and multi-page titles lack page lists.

All 55 cases pass locally at the head and on the merged tree. The model outputs quoted below were reproduced by running the head code, or the merged tree for S1. The values each proposed fix would produce are hand computations and are labelled as such. The untested-logic claims in S2 and S3 were confirmed by mutating the code and rerunning the PR's tests.

Path prefixes used below:

  • P/ = policyengine_us/parameters/gov/states/ri/dhs/liheap/
  • V/ = policyengine_us/variables/gov/states/ri/dhs/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/ri/dhs/liheap/
  • M = DHS LIHEAP Administration and Procedures Manual, cover dated "PUBLISHED: JUNE 11, 2019" (PDF page = printed page)

Line numbers refer to head c8b6cafa25.

Source Documents

# Document Link Use
1 FY2026 Rhode Island LIHEAP State Plan (49 pp, report period 10/01/2025-09/30/2026, "Submission Accepted by CO") RI_Plan_2026.pdf 1.1 dates (p4); 1.4 No, 1.7 $20.01, 1.8 Gross Income, 1.9 (p5-7); 2.1 60% SMI, 2.2-2.3 (p8); 2.5, 2.6 $50 / $861 (p9). The text layer lacks the checkbox states, so the rendered pages were read
2 FY2026 Grant Amounts and Income Eligibility (1 p) RI_BenefitMatrix_2026.pdf Rows A-I; sizes 1-14 for 75/100/125/150% FPG and 60% SMI
3 DHS FFY2027 LIHEAP Income Eligibility (1 p, "For mandatory use as of October 1, 2026") DHS copy All 14 FY2027 limits. The PR cites an EBCAP CDN copy
4 M, filed in PUC Docket 4290 (28 pp) M II.B (p5-6); III (p12); III.E (p14-17); III.G (p18-20); III.H (p20-21)
5 Appendix H, Application Instructions: May 2025 (FY2026) and July 2026 (FY2027) May 2025, July 2026 Gross income, $500 interest, students 18-23 (p2); the two editions match on these rules
6 Appendix M (Rental Income Reported Form) and Appendix B (Landlord Information Form), May 2025 App. M, App. B 50% of rental income (M p1); tenant heat "Oil Kerosene Propane Wood/Pellets / Gas Electricity Other" (B p1)
7 DHS Summary of the FFY2026 State Plan (10 pp) media/9371 p1 income list: "Self-employment income (60%)", "Social Security Administration (SSA) benefits (including the Medicare deduction)"
8 DHS draft Summary of the FFY2027 State Plan (11 pp) media/11711, p. 3 "(Including Medicare deduction)*" / "*meaning the Medicare amount deducted is not counted" (file p3); FY2027 limits (p4); no benefit amounts
9 PUC Docket 25-38-GE: DHS answer to DIV 1-1 (Oct 9, 2025); DHS answers to PUC set 1 (Nov 2025); Order 25579 DIV 1-1, PUC 1-5, Order 25579 $350 "issued to households being issued a LIHEAP Primary Grant" (DIV 1-1 p1); FFY2025 $64-$1,148 and FFY2026 $50-$861 (DIV 1-5 p2); credited after the utility receives the federal grant (PUC 1-5 p2); "$350 per recipient" (Order p3)
10 R.I. Gen. Laws § 39-1-27.12 statute (e) credit to "customers' accounts that are receiving federal LIHEAP assistance payments"; (f) excludes Block Island and Pascoag
11 PUC Docket 26-34-GE, DHS filing of Oct 2, 2026 FFY2027 filing, p. 2 "Accounts receiving a 2027 Primary benefit will receive one additional credit"; no amount yet (G5)
12 FY2023 and FY2024 Grant Amounts 2023, 2024 Rows G-I printed only in the Other column; row F below row E (S2, G1, G2)
13 FY2025: DHS press release (Sept 30, 2024) and FY2025 plan summary press release, media/7571 "grants ranging from $64 to $1,148"; FY2025 limits ($39,101 for one person)

Critical (Must Fix)

None.

Should Address

S1. Merge blocker: after merging main, the unearned list reads the reported-only unemployment_compensation, so main's guard fails

  • Where: P/income/sources/unearned.yaml:12 (- unemployment_compensation).
  • What changed on main: Integrate modeled state unemployment insurance into income flows #9558 (merged 2026-10-13, after this PR's last push) added total_unemployment_compensation, which uses the reported amount when present and otherwise the modeled state unemployment insurance programs. It moved every income-source list under parameters/ to the total, including the merged LIHEAP lists (for example ks/dcf/liheap/income/sources/unearned.yaml:4 and nj/dca/liheap/income/sources/unearned.yaml:4), and added policyengine_us/tests/code_health/test_unemployment_compensation_readers.py, which fails on any raw list entry.
  • Reproduced on the git merge-tree result of main 8ae01aa3cb and this head: test_parameter_source_lists_do_not_read_raw_unemployment_compensation fails with one violation, parameters/gov/states/ri/dhs/liheap/income/sources/unearned.yaml:12; the file's other three tests pass. The PR's 55 cases still pass on that tree.
  • Source: M III.E, p. 15 counts "Unemployment Benefits" and plan 1.9, p. 6 checks "Unemployment insurance". Neither separates reported from modeled amounts.
  • Impact: main models unemployment insurance for AL, NJ, NY, OK, PA and UT only, so for Rhode Island households total_unemployment_compensation equals the reported amount and no value changes today. The guard still blocks the merge, and the raw entry would silently drop Rhode Island UI once it is modeled.
  • Why should, not critical: the head is correct against its base and CI is green. git merge-tree shows a clean textual merge, but this has to change before merge (as Add Alabama LIHEAP regular heating assistance #9967 S1).
  • Fix: replace the entry with total_unemployment_compensation, add a case with reported unemployment compensation (see S3), and update rulespec-us#1537's input list, which names unemployment_compensation.

S2. Row G prints no Electric amount, but the PR pays $400 to unsubsidized electric-heat households with heat in rent and no electric bill

  • Where:
    • V/payment/ri_liheap_base_payment.py:72-77 pays hir.direct ($400) whenever heat is in rent, no electric bill is reported and the household is unsubsidized, whatever the fuel.
    • V/eligibility/ri_liheap_eligible.py:29-31 makes the same household eligible.
  • Source: the FY2026 Grant Amounts, row G "Heat in Rent Direct Pay to Household", prints "$ 400" under Deliverables, "$400" under Natural Gas and "$400" under Other, and leaves the Electric cell blank. Rows H ($80) and I ($50) print only in the Other column.
  • Why the blank looks deliberate: the FY2023 and FY2024 matrices printed a single "HIR (Direct payment to household)" amount, $400, in the Other column, with no split by fuel. FY2026 added $400 under Deliverables and Natural Gas and left Electric empty.
  • Reproduced at head: a one-person household with $10,000 of wages, ELECTRICITY heat included in unsubsidized rent and no electric bill is eligible and gets $400. The printed matrix has no amount for it. With an electric bill it gets row H, $80 + $350 = $430.
  • Documentation and tests:
    • The PR body says "Heat-in-rent households receive rows G–I for any reported fuel" and does not mention the blank. The author's own rulespec-us#1537 does (interpretation 3: "Row G prints no Electric cell, yet electric heat in unsubsidized rent with no electric bill gets $400 (untested)").
    • The only electric-heat heat-in-rent cases are subsidized with an electric bill (row I): T/ri_liheap.yaml Case 4 unit 3 and Case 10 unit 6. Paying $0 here instead passes all 55 cases.
  • Why should, not critical: the matrix leaves the cell blank rather than printing a conflicting amount, so this is an unstated reading of the source in the claimed year rather than a confirmed mismatch.
  • Fix:
    • Either pay $0 for row G when the fuel is ELECTRICITY, matching the printed matrix (and decide whether such households stay eligible; an eligible-but-$0 flag repeats Add New Jersey LIHEAP regular heating assistance #9745 G1), or keep $400 and say why in the variable, P/payment/heat_in_rent.yaml and the PR body.
    • Add the case either way: unsubsidized, ELECTRICITY, heat in rent, no electric bill, expecting ri_liheap: 0 (or 400). Add the unsubsidized electric-heat case with an electric bill, expecting 430 (row H).

S3. Three pieces of logic have no test that would fail if they broke

Each mutation below, applied to the head on its own, still passes all 55 cases.

  1. Interest of excluded members. V/income/ri_liheap_income.py:54-56 multiplies interest by counted_person, so a minor's or an 18-23 student's interest is excluded (M III.G, p. 20: "Child Income (under 18)"; Appendix H, p. 2: "Income will not be considered in eligibility determination for students ages 18-23"). The interest cases (T/income/ri_liheap_income.yaml Cases 8 and 9) use adults aged 39 and 40, so dropping * counted_person passes. Pin it: a parent aged 45 with $12,000 of wages and a 17-year-old with $800 of interest. Reproduced at head: 12,000. With the mask removed, the same case gives 12,300 (reproduced under the mutation).
  2. Eight unearned sources. unemployment_compensation (which S1 replaces), strike_benefits, pension_income, survivor_benefits, railroad_benefits, workers_compensation, disability_benefits and veterans_benefits are never nonzero in any test, so deleting all eight passes. Two of them, workers_compensation and disability_benefits, are choices the PR's conflict table defends against plan 1.9; Add OR income subtraction of taxable social security benefits #1537 interpretation 10 notes "No case tests either source". One case with every source nonzero would catch a dropped entry (Add New Jersey LIHEAP regular heating assistance #9745 G7).
  3. The size gate in eligibility. Without (size > 0) at V/eligibility/ri_liheap_eligible.py:34, a household with no qualified member and no income passes the income test (limit 0, income 0) and is eligible. The payment stays $0 because the base payment also gates on size, so only the flag changes. Every size-0 case that asserts eligibility or the award has income above $0 (T/eligibility/ri_liheap_eligible.yaml Case 2 unit 3, T/ri_liheap.yaml Case 3 unit 5). Add ri_liheap_eligible: false for a size-0 household with no income; reproduced at head: false.

The row G Electric cell (S2) is also unpinned. Consistency: #9967 S3 and #9745 S5 rated untested branches SHOULD.

S4. Six parameter descriptions fall outside the house template

File:line Current Suggested
P/income/sources/earned.yaml:1 "counts these earned income sources" "Rhode Island uses these sources as earned income under the Low Income Home Energy Assistance Program."
P/income/sources/unearned.yaml:1 "counts these unearned income sources" "Rhode Island uses these sources as unearned income under the ..."
P/income/minimum_income_age.yaml:1 "counts individual income beginning at this age" "Rhode Island excludes the income of members below this age under the ..."
P/income/rental_income_rate.yaml:1 "counts this share of rental receipts" "Rhode Island uses this share of rental income as countable income under the ..."
P/income/deduction_sources.yaml:1 "deducts these reported expenses from income" "Rhode Island uses these expenses as income deductions under the ..."
P/payment/utility_enhancement.yaml:1 "adds this enhancement to the primary federal Low Income Home Energy Assistance Program grant credited to a qualifying gas or electric distribution-company account" (verb, and a clause after the program name) "Rhode Island provides this enhancement with a primary heating grant credited to a gas or electric distribution-company account under the Low Income Home Energy Assistance Program."

The other nine fit: smi_rate (limits), interest_exclusion and student_age_limit (excludes), the three amount files and heat_in_rent (provides), fpg_rates (sets) and fpg_year_lag (uses). Consistency: #9967 S4 and #9745 S6.

S5. One anchor opens the wrong page, Appendix H is linked without its page and from two hosts, and multi-page titles lack page lists

File:line Problem Fix
P/income/rental_income_rate.yaml:13 (and the comment at line 2) M #page=17 opens the documentation list. The rule is at the foot of p. 16, "Fifty percent (50%) of rental income shall be included in the total income for eligibility determination.", and on p. 20, "50 percent of Gross Rental Income". The comment says "pages 17 and 20". Appendix M p1 does corroborate the 50% #page=16, a title ending #page 16,20, and correct the comment
P/income/interest_exclusion.yaml:13, P/income/sources/earned.yaml:23, P/income/sources/unearned.yaml:53, V/income/ri_liheap_income.py:18 Appendix H (media/9671) has no anchor, so it opens p1 (identity and residence documents). The interest rule and the income list are on p2 Add #page=2
V/income/ri_liheap_income.py:18,20; P/income/student_age_limit.yaml:15 The same May 2025 instructions are cited from DHS (media/9671, footed "Appendix H") and from westbaycap.org (footed "Appendix C", although the parameter title says Appendix H); the variable lists both One entry, on the DHS host, #page=2
P/income/sources/earned.yaml:18-21, P/income/sources/unearned.yaml:48-51 "Sections III.E-G" opens p14, but the cited sources and exclusions run to p20; "Sections 1.8 and 1.9" opens p5, but 1.9 runs to p7 Titles ending #page 14-20 and #page 5-7

Consistency: #9745 S7 rated wrong anchors SHOULD. The author's #1537 interpretation 20 already records the p17 error.

Suggestions

G1. Backfilled years pay FY2026 amounts that the earlier sources contradict

  • Every single-dated parameter carries back to every earlier period. Earlier years differ:
    • FY2025 grants ranged "$64 to $1,148" (the DHS press release of Sept 30, 2024; DIV 1-5 p2).
    • The FY2023 and FY2024 matrices are published and differ in every row A-F cell and in rows H and I ($125 / $75).
    • The enhancement was $515 for 2024 and $450 for 2023 (PUC Order 24925, p. 2: "raised the LIHEAP Enhancement Grant to $515.00 for 2024, where in 2023 it was $450.00").
  • Period 2025 pays $861 to T/ri_liheap.yaml Case 5's household; FY2025's top grant was $1,148. The limits do carry back correctly: FY2024 ($35,674 for one person) and FY2025 ($39,101) reproduce.
  • The branch gated the payment with payment/in_effect.yaml (false before 2025-10-01) until aa4ccc33b9 removed it. Merged NJ gates with eligibility/in_effect.yaml.
  • The PR documents the backfill and labels the 2025 cases unverified, so this is a suggestion (checklist item 3). Either restore the gate, or encode the published FY2023-FY2024 matrices and enhancements. In both cases, drop or reword the 2025 award assertions (T/ri_liheap.yaml Cases 5 and 11, T/payment/ri_liheap_base_payment.yaml Case 9), which pin values the FY2025 sources contradict.

G2. Give row F its own amounts

  • V/payment/ri_liheap_base_payment.py:42 maps row F to band len(p.fpg_rates) + 1, so it reuses row E's cells. That is right for FY2026, where row F equals row E ($657 / $159 / $268).
  • In FY2023 and FY2024, row F ("Sec. 8 w/ Primary Heating Bill", $696 / $205 / $310) was below row E ($981 / $355 / $533 and $932 / $256 / $426). A future matrix like those could not be encoded without a code change, and the comment's "lowest payment" holds only by coincidence.
  • Add a row-F amount per fuel (for example a sixth breakdown key), so the index no longer depends on the length of the band-rate list.

G3. Cite DHS's current summaries for three income rules

  • Part B deduction (correct as is). The draft FY2027 summary (file p. 3) reads "Social Security Administration (SSA) benefits (Including Medicare deduction)*" with "*meaning the Medicare amount deducted is not counted". So plan 1.9 and M III.H agree. Cite it in P/income/deduction_sources.yaml and drop the "conflict" row from the PR body.
  • Lottery winnings. Plan 1.9 leaves "winnings from lotteries" unchecked. The FY2026 summary, the draft FY2027 summary and both editions of Appendix H omit them; only M p17 lists "Cash Prizes and Lottery Winnings". The choice is documented, but the weight of current DHS documents points the other way. Consider dropping gambling_winnings, or say in the comment that the current summaries omit it.
  • Self-employment. The FY2026 summary (p1) still lists "Self-employment income (60%)", so M's 40% deduction is current. The deferral to net business income is reasonable; cite the summary in P/income/sources/earned.yaml.

G4. Sources and naming

  • M's cover reads "PUBLISHED: JUNE 11, 2019". The PR body and titles call it the 2020 manual.
  • The appendix footers ("RI LIHEAP Policy Manual Appendix H, May 2025"; July 2026) and the footer of the FFY2026 notice to applicants ("RI LIHEAP Policy Manual July 2025") show that later editions exist. None was found online. Say so in the PR body, as Add OR income subtraction of taxable social security benefits #1537 interpretation 18 does.
  • V/eligibility/ri_liheap_income_limit.py:16 cites a CDN copy of the FY2027 sheet. DHS hosts it at https://dhs.ri.gov/media/12266/download?language=en.
  • The PR describes the FY2027 instructions but links only the May 2025 edition. The July 2026 edition is media/12306.

G5. FY2027 enhancement

DHS's Oct 2, 2026 filing (Docket 26-34-GE) says "Accounts receiving a 2027 Primary benefit will receive one additional credit", with the amount still to be set. The $350 carry-forward is documented as unverified, which is fine. Record the filing in P/payment/utility_enhancement.yaml and the registry notes, and update the value when DHS answers the docket's data requests. Rhode Island pays no IIJA supplement; the enhancement is ratepayer-funded under § 39-1-27.12, so checklist item 12 does not apply.

G6. PR body and issue housekeeping

G7. Test hygiene

  • About twenty comment lines lost the spaces around their numbers. Examples:
    • T/income/ri_liheap_income.yaml:3 ("approximation:12000+2400+600+1200+1200=17400; no additional40% deduction"), line 394 ("arepositive"), line 456 ("underp20");
    • T/eligibility/ri_liheap_income_limit.yaml:3 ("annual60%SMI") and line 31 ("all14");
    • T/payment/ri_liheap_base_payment.yaml:6, 23, 58, 86 ("bills10", "bandB deliverables805", "ExplicitNONE", "Oil861 remains861");
    • T/ri_liheap.yaml:228 ("October2025 DIV1-1", "direct400").
  • Comments such as T/income/ri_liheap_income.yaml:3 and :34 call conventions "approved", which refers to internal decisions.
  • The income, limit, band and household-size tests set heating_type and fuel bills that those variables never read.
  • Five files open with "no final award is asserted", but T/income/ri_liheap_income.yaml Case 15 and the base-payment file assert payment amounts.
  • SOLAR and OTHER households with a bill are eligible but get $0 (the matrix's Other column is blank in rows A-F). That is consistent with the matrix; as in Add New Jersey LIHEAP regular heating assistance #9745 G1 and Add Alabama LIHEAP regular heating assistance #9967 G2, either make the flag match or note it.

Verified correct

  • Matrix (FY2026):
    • Rows A-E: Deliverables 861 / 805 / 752 / 704 / 657, Natural Gas 232 / 211 / 192 / 175 / 159, Electric 393 / 357 / 324 / 295 / 268.
    • Row F 657 / 159 / 268, at any income. Rows G $400, H $80, I $50.
    • Oil, kerosene, propane and wood pay from Deliverables (Appendix B: "Oil Kerosene Propane Wood/Pellets").
    • The plan 2.6 range of $50-$861 matches, with the state-funded enhancement outside it.
  • Enhancement: $350 per primary grant (DIV 1-1 p1; Order 25579 p3). It is added to gas and electric grants and to heat-in-rent grants paid to an electric account, never to Deliverables or the direct $400. That follows § 39-1-27.12(e) and PUC 1-5 ("credited to a customer's account by the utility once the federal grant to that household has been received").
  • Limits:
    • All 14 FY2026 limits (42,252 ... 126,756) and all 14 FY2027 limits (43,410 ... 130,230) reproduce from SMI $135,424 and $139,136: floor(0.6 x SMI) = 81,254 and 83,481, times the 45 CFR 96.85 shares, floored.
    • The limit is inclusive ("equal to or less than"; Case 3's 42,252 / 42,252.01 pair).
  • Bands:
    • Tops are the 2025 guideline x 0.75 / 1 / 1.25 / 1.5, rounded half up and upper-inclusive: 11,738 / 15,650 / 19,563 / 23,475 for one person. 41 of the 42 printed 75%, 125% and 150% tops for sizes 1-14 reproduce.
    • Following the labeled 125% rate for size 2 (26,438, not the printed 31,725) is a documented, reasonable reading of a typo.
    • The FPG lag gives the 2025 guideline for period 2026.
  • Timing: heating assistance runs 10/01/2025-04/15/2026 (plan 1.1, p4), and period 2026 reads January 1, 2026.
  • Income (plan 1.8 gross; M III.E-H):
    • Members 18 and over count; full-time students 18-23 are excluded, head or not, following the current Appendix H over M p20.
    • Each source is floored at zero. Rental and farm rent count at 50%. Interest is counted above $500 once per household, and dividends in full.
    • TANF is read through the take-up-gated tanf. A child's SSI is excluded. SNAP is excluded.
    • Child support and alimony paid are deducted, and child care only when unsubsidized. medicare_part_b_premium is deducted, and it is already net of Medicare Savings Program coverage.
  • Household: size counts citizens and 8 U.S.C. 1641 qualified statuses (DACA excluded), matching M p12-13. Nonqualified members' income counts (M p12).
  • Eligibility:
    • Rhode Island residence. No categorical eligibility (plan 1.4 No) and no asset test (plan 2.3 No).
    • A heating obligation, or heat in unsubsidized rent, qualifies. Subsidized heat in rent needs an electric bill (M p6). NONE is ineligible.
  • Code patterns:
    • No hard-coded values. defined_for = StateCode.RI on six variables, and ri_liheap is gated by ri_liheap_eligible.
    • Vectorized formulas. All 15 parameters are read. The shared fpg() and liheap_smi_limit() helpers are reused.
  • Tests:
    • 55 of 55 pass locally at head (policyengine-core 3.32.29) and on the merged tree. Periods are plain.
    • Hand-checked: T/ri_liheap.yaml Cases 1-4 and 9-10; income Cases 8, 10, 11, 12 and 15; all 15 base-payment cells; all 28 limits; the 9 one-person and 5 two-person band edges; the 2025 band tops (11,295 / 18,825).
  • Changelog: changelog.d/ri-liheap.added.md is top level and typed added.

Checklist results (LIHEAP wave 2a)

  1. State plan and manual first: pass, with S2. I read the accepted FY2026 plan (rendered checkboxes), the FY2026 matrix, the FY2027 income sheet, M, the May 2025 and July 2026 appendices, DHS's FY2026 and draft FY2027 summaries, the FY2023-FY2025 sources and the PUC enhancement record, and verified every encoded cell, limit and band. The one blank cell (row G Electric) is paid without a stated reason (S2).
  2. Income definition: pass at head. Gross income with M's deductions; Social Security net of Part B, matching DHS's own gloss; losses floored per source; annual income. After rebase the list must read total_unemployment_compensation (S1). Lottery and self-employment notes are in G3.
  3. Backdating: limits reproduce FY2024-FY2025. Payments and the enhancement do not, which the PR documents (G1). FY2027 limits are used; no FY2027 matrix is published.
  4. Household and arrangement rules: pass on subsidized and public housing, heat in rent (rows G-I), renters, no categorical eligibility and crisis-only priority. Row G Electric is S2; the SNAP nominal payment is documented as out of scope.
  5. Tests: 55 cases, more than 8 hand-checked. Limits for sizes 1-14 in both years, band edges, the limit edge and plain periods are covered. Gaps are in S2-S3.
  6. Parameter descriptions: six fall outside the template (S4).
  7. References: one wrong anchor, missing Appendix H anchors, a duplicate host and missing page lists (S5).
  8. Wiring: pass. The programs.yaml entry and coverage line are well formed. No aggregate wiring, which matches OR, NY, NJ and MD on main. defined_for gating is on every variable. No take-up beyond TANF's.
  9. Axiom: valid queued line. rulespec-us#1537 is open, labelled pe-parity, dispatch-ready and current to c8b6cafa25; it needs updates for S1-S2 (see below).
  10. Branch and CI: all checks are green at head. 11 ahead and 82 behind main. No textual conflicts, but main's UI guard fails on the merged tree (S1).
  11. Integrate modeled state unemployment insurance into income flows #9558: S1. No modeled RI UI exists, so the effect today is the guard failure only.
  12. IIJA and FY2027: no IIJA supplement. The $350 is ratepayer-funded, continues into FY2027 with the amount pending (G5), and the FY2027 limits are encoded.
  13. Mutation check: S3, plus the row G Electric cell in S2.

CI status

28 of 28 checks pass at c8b6cafa25 (gh pr checks 9972, run of 2026-10-12). The three "skipping" entries belong to a superseded run on the same SHA.

Branch status

Axiom line

axiom: TheAxiomFoundation/rulespec-us#1537 queued: valid format, and the issue meets the bar.

  • rulespec-us#1537 is open and labelled pe-parity (plus enhancement), with no comments, and was last updated 2026-10-12.
  • It is dispatch-ready under the Add AMT parameters for 2020-2023 #1467 standard. It has module paths with corpus status, verbatim manual, plan, matrix and instruction text, required outputs for all 7 variables, and companion tests derived from the matrix, manual, instructions, guidelines and PUC record ("None is taken from policyengine-us output").
  • It describes c8b6cafa25 correctly. It already records the row G Electric gap (interpretation 3), the p17 anchor (interpretation 20), the 2019 manual edition (interpretation 18) and the backfill (interpretation 12).
  • Updates needed when the fixes land:
    • the input list and a UI case (S1);
    • the row G Electric decision (S2);
    • the new branch cases (S3);
    • the draft FY2027 summary's Medicare gloss for interpretation 11 (G3);
    • the stale "open as a draft".

Next steps

  1. S1: rebase onto main, switch P/income/sources/unearned.yaml:12 to total_unemployment_compensation, and add a UI case.
  2. S2: decide the row G Electric cell ($0 or a documented $400) and add the two electric heat-in-rent cases.
  3. S3: add the minor-interest, all-sources and size-0 cases.
  4. S4-S5: align the six descriptions and fix the anchors and duplicate Appendix H entries.
  5. Optionally address G1-G7, then refresh the PR body and rulespec-us#1537 and re-request review.

0 critical and 5 should-address findings, plus 7 suggestions.

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 for 5 should items; details in the full report above. The FY2026 values check out: all 15 primary benefit cells, rows F–I, the $350 enhancement and all 28 FY2026/FY2027 income limits. The Part B treatment is correct, all 55 tests pass, and CI is green. (1) Merge blocker from main's #9558: unearned.yaml:12 lists the raw unemployment_compensation, so the guard fails on the merged tree. (2) Matrix row G prints no Electric amount, but the PR pays $400 to unsubsidized electric-heat households with heat in rent and no electric bill. This is undocumented and untested. (3) Logic that passes every test even when broken on purpose: the interest exclusion for minors and students, 8 of the 18 unearned sources, and the size check in eligibility. (4) Six parameter descriptions are off the house template. (5) Reference anchors: rental_income_rate cites page 17 (the rule is on pages 16 and 20); the Appendix H links lack #page=2 and come from two hosts.

hua7450 and others added 2 commits October 15, 2026 15:13
- S1: The unearned list reads the raw unemployment_compensation, so main's #9558 guard fails
- S2: Row G prints no Electric amount, but the PR pays $400 for electric heat in unsubsidized rent with no electric
- S3: Three pieces of logic have no test that fails when they break: excluded members' interest, 8 unearned sources
- S4: Six parameter descriptions fall outside the house template
- S5: Wrong rental anchor, Appendix H without page 2 and on two hosts, multi-page titles without page lists

Also applies the in-scope suggestions. Tests not run locally; CI validates.

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

hua7450 commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the review. Fixes pushed in 09fddd6.

The branch also merges upstream/main (PRs 9558 and 10046). Rhode Island deducts no health insurance premium other than Medicare Part B, so 10046 changes nothing here. The 60% SMI limit stays above the federal 110% poverty floor (42 U.S.C. 8624(b)(2)(B)) for sizes 1–20 in FY2025–FY2027; the smallest margin is $1,833, at size 20 in FY2025. So this PR does not add the shared gov.hhs.liheap.fpg_floor parameter.

  • S1: unearned.yaml now lists total_unemployment_compensation. Income Case 25 sends $10,010 of reported UI and expects $10,010 for both total_unemployment_compensation and ri_liheap_income. The $10,010 is the R.I. DLT formula for a worker earning $40,000 a year: $385 a week for 26 weeks.
  • S2: I followed the matrix as printed. Row G pays $0 for electric heat, so electric heat in unsubsidized rent with no electric bill stays eligible but gets $0, with no enhancement. ri_liheap_base_payment, heat_in_rent.yaml, ri_liheap_eligible and the body now document this. ri_liheap.yaml Case 12 covers both of your cases with minimum-wage income ($33,280): $0 without an electric bill and $430 (row H, $80 + $350) with one.
  • S3: All three are added. Income Case 27 has a parent with $12,000 of wages, a 17-year-old with $800 of interest and a 20-year-old full-time student with $600; it expects $12,000, and dropping the mask would give $12,900. Income Case 26 sets all 18 unearned sources to distinct amounts and expects $17,300. Eligibility Case 3 is an undocumented adult with no income and a gas bill, with size 0, limit 0 and ri_liheap_eligible: false.
  • S4: The six descriptions now use your suggested wording.
  • S5: rental_income_rate now opens page 16, its title ends #page 16,20 and the comment is fixed. Every Appendix H link now points to the DHS host at #page=2, and the westbaycap.org copy is gone. The manual and plan titles end #page 14-20 and #page 5-7. Appendices M and B open at #page=1.
  • G1: History is out of scope for this PR: LIHEAP states use undated formulas with parameter backfilling, so I added no gate and no FY2023–FY2024 matrices. I took your rewording option instead. The comments on ri_liheap.yaml Cases 5 and 11 and base-payment Case 9 now say they check only the backfill; Cases 5 and 9 cite FY2025's published $64–$1,148 range.
  • G2: Not split. FY2026 rows E and F print identical cells, so a separate row-F key would duplicate parameters, and the earlier matrices fall under history. The comment now says row F reads row E's band because the FY2026 cells match, and that a matrix with different row F cells would need its own amounts. Base-payment Case 3 is renamed.
  • G3: For Part B, deduction_sources.yaml now cites plan 1.9 and the draft FFY2027 summary's gloss, and the body no longer lists it as a conflict. For lottery winnings, gambling_winnings stays because where the plan and manual conflict, we follow the manual. The comment and the conflict row now note that the FY2026 and draft FFY2027 summaries and the application instructions omit lottery winnings. For self-employment, earned.yaml cites the FY2026 summary's "Self-employment income (60%)".
  • G4: The code now calls the manual the 2019 edition, and the body calls it the manual published June 11, 2019. The body notes that later editions exist (appendices dated May 2025 and July 2026, and an applicant notice citing a July 2025 manual) but that none was found online. ri_liheap_income_limit now cites the DHS copy of the FY2027 sheet (media/12266), and the July 2026 instructions (media/12306, page 2) are cited next to the May 2025 edition.
  • G5: utility_enhancement.yaml records the Docket 26-34-GE filing and labels the FY2027 $350 an unverified estimate, and the body's years section says the same. Registry notes stay at one or two sentences, so the filing details are in the parameter and the body; the programs.yaml note is now two sentences and says FY2027 payments reuse FY2026 amounts as unverified estimates.
  • G6: The plan 2.3 / manual II.B conflict is now a body row and a comment in ri_liheap_eligible. The code and body now say "no matrix amount", and the make format box is checked. The stale "open as a draft" wording is fixed in the rulespec-us refresh below.
  • G7:
    • The squashed comments are rewritten and the "approved" wording is gone.
    • heating_type and gas_expense are dropped from the income, limit, band and household-size cases. Income Case 15 keeps them because it asserts a payment.
    • The "no final award is asserted" headers are deleted.
    • SOLAR, OTHER, COAL and electric heat in unsubsidized rent with no electric bill stay eligible with a $0 award because the matrix prints no amount for them, the same treatment the other LIHEAP states give unpriced fuels. The eligibility variable and the body say so.
  • LIHEAP wave 2a: encode Rhode Island LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1537 is refreshed to this head.

@hua7450
hua7450 requested a review from DTrim99 October 15, 2026 21:08

@PavelMakarchuk PavelMakarchuk 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. All round-1 should-address items (S1-S5) are resolved, the row G Electric fix matches the FY2026 matrix, and CI is green. S6-S8 are non-blocking: the 110% floor first binds at 23 people, the row G Electric value is correct but belongs in a parameter, and the UNSPECIFIED heat-in-rent path needs a test. Please pick them up here or in a quick follow-up; for S6, reuse gov/hhs/liheap/fpg_floor.yaml once #9968 or #9969 merges.

Program Review

IDs: C = critical, S = should address, G = suggestion. S1-S5 and G1-G7 keep the prior review's numbers; S6-S8 and G8-G17 are new.

Source Documents

Paths: P/ = policyengine_us/parameters/gov/states/ri/dhs/liheap/, V/ = policyengine_us/variables/gov/states/ri/dhs/liheap/, T/ = policyengine_us/tests/policy/baseline/gov/states/ri/dhs/liheap/.

Branch Status

13 commits ahead of main and 38 behind; merges cleanly. Staleness did not affect any finding. Informational only.

Critical (Must Fix)

None.

Should Address

S6. The federal 110%-of-poverty floor is not encoded

  • Defect: V/eligibility/ri_liheap_eligible.py:42 tests only income <= limit; V/eligibility/ri_liheap_income_limit.py:24 has no floor.
  • Evidence: 42 U.S.C. 8624(b)(2)(B) bars excluding a household with income "less than 110 percent of the poverty level"; the plan assurances, #page=45 restate it.
  • Impact: the 60% SMI limit falls below the floor from size 21 in 2025 and size 23 in 2026-2027 (size 19 in the 2024 backfill). Period 2026, 23 people, $150,000: limit $148,694 < floor 1.1 × $136,650 = $150,315, so the model pays $0; with the floor, band 3 gas pays $542. The author's margins are correct, but the model does not cap household size at 20.
  • Severity: SHOULD, not CRITICAL as #9969 C1, because the first binding size in FY2026-FY2027 is 23 (FL: 15), which no realistic household reaches. The legal gap is the same.
  • Fix: in ri_liheap_eligible, use (income <= limit) | (income < p_hhs.fpg_floor * guideline) with fpg() and the RI year lag (generalize the P/payment/fpg_year_lag.yaml description or add an eligibility lag). Reuse gov/hhs/liheap/fpg_floor.yaml (1.1) from #9968/#9969 after one merges, or add the identical file. Round the product to cents (#9969 S4). Add the 23-person case and a $150,314.99 / $150,315.01 pair.

S7. The blank row G Electric cell is in the formula, not a parameter

  • Defect: V/payment/ri_liheap_base_payment.py:78 sets the row G grant to 0 for fuels.ELECTRICITY; P/payment/heat_in_rent.yaml:6-7 shows direct: 400 for every fuel. Every other matrix cell is a parameter.
  • Impact: the parameter tree and API show $400 for all fuels, and a later matrix with a row G Electric amount needs a code change.
  • Severity: SHOULD: the literal is 0, which the repo rule allows, and T/ri_liheap.yaml Case 12 pins the result.
  • Fix: split direct into deliverables / natural_gas / electricity (0) / other, selected with the existing fuel mapping and default=hir.direct.other. A list parameter of excluded fuels is a lighter option.

S8. Heat in rent with an UNSPECIFIED fuel gets the $400 row G grant, with no test and an unclear comment

  • Defect: an unsubsidized heat-in-rent household with no electric bill and heating_type UNSPECIFIED (the default), SOLAR or COAL is eligible and gets $400 (V/payment/ri_liheap_base_payment.py:78, 82). No test covers this; a mutation that pays row G only for the printed columns passes all 60 cases.
  • Comment: :61-64 sits in the rows A-F select, so "UNSPECIFIED receives none" is scoped to rows A-F and is not wrong. But it does not say that heat in rent then pays row G, so a reader can take it as the whole outcome.
  • Evidence: the matrix prints row G under Deliverables, Natural Gas and Other, and leaves Electric blank. The HeatingType docstring uses UNSPECIFIED for heat in rent with an unknown fuel, which can be electric. SOLAR and COAL read as "Other" (Appendix B has no box for them).
  • Severity: SHOULD under the untested-branch rule (as #9967 S5): it is the default heat-in-rent path, and it sets the award.
  • Fix: decide the UNSPECIFIED outcome (with S7, the default branch carries it), and extend the comment to say what row G pays. Add a T/ri_liheap.yaml case: unsubsidized, heat in rent, pre_subsidy_electricity_expense: 0, heating_type: [UNSPECIFIED, SOLAR, COAL], expecting ri_liheap_eligible: [true, true, true] and ri_liheap: [400, 400, 400] under the current code.

Suggestions

  • G8. Lottery winnings: the author took round 1's documentation option, which is acceptable. The reviewer still leans toward removing gambling_winnings (P/income/sources/unearned.yaml:42): the 600-dpi check confirms that plan 1.9 leaves "winnings from lotteries" (p6) and "Other" (p7) unchecked, and only M p17 counts them. If removed, income Case 22 expects 20,000 and Case 26 expects 17,200.
  • G9. Self-employment: round 1 accepted net business income. The comment at V/income/ri_liheap_income.py:38 ("approximate the gross-receipts rule") is inaccurate. With the M III.H, p20 40% allowance, the error is receipts × (0.4 − expense ratio), so net is exact only at a 40% expense ratio. Correct the comment (and P/income/sources/earned.yaml:2-5), citing ks_liheap_countable_earned_income.py:11. Optionally add a 0.4 deduction parameter for the self-employment sources. 0.6 × net is not a correct fix; it removes expenses twice.
  • G10. Pin the subsidized | term at V/payment/ri_liheap_base_payment.py:78 with a base-payment unit (subsidized, heat in rent, no bill, gas) expecting 0.
  • G11. Pin the documented eligible-but-$0 result for COAL, SOLAR and OTHER (V/eligibility/ri_liheap_eligible.py:36-38).
  • G12. Coverage: no integration.yaml; the end-to-end limit edge is tested for size 1 only; the negative-interest floor and deductions of excluded members are untested.
  • G13. Add the FY2026 summary (media/9371#page=1) to the unearned.yaml references, and name mortgage or sales-contract payments, contract income and AmeriCorp allowances as not represented.
  • G14. Titles: earned.yaml:26 "Countable Income" is not a summary heading; mark utility_enhancement.yaml:20 "(2027 credit amount not yet set)"; use one Appendix H title style.
  • G15. "So the sources agree" (P/income/deduction_sources.yaml:9-14) rests on the draft FFY2027 gloss; replace the draft link when DHS posts the final summary.
  • G16. T/income/ri_liheap_income.yaml:738: strike pay and VA benefits come from plan 1.9 (p6), not the manual; :706-712 cites DLT figures without a link.
  • G17. Nits: adds for ri_liheap_household_size and ri_liheap; the changelog name differs from the branch; optionally archive the DHS links.

Investigated and cleared: workers' compensation (REJECTED: plan 1.9 does not name it; M p16 governs, and Appendix H counts TDI); the size-2 125% band cell (REJECTED: $31,725 repeats the 150% cell, and 55 of 56 cells follow the rate; likely a matrix typo); the $350 enhancement (MATCH: DIV 1-1 p1, Order 25579 p3); the FY2027 limits (MATCH: all 14 reproduce from 60% of $139,136).

Prior Findings

ID Finding Status
S1 Raw unemployment_compensation RESOLVED (guard 4/4; Case 25)
S2 Row G Electric paid $400 RESOLVED ($0, Case 12); encoding in S7
S3 Untested mask, sources, size gate RESOLVED (each mutation fails)
S4 Six off-template descriptions RESOLVED
S5 Anchors, hosts, page lists RESOLVED
G1 Backfill contradicts FY2023-25 STILL OPEN, declined by author
G2 Row F own amounts STILL OPEN, declined by author
G3 Cite DHS summaries (Part B, lottery, self-employment) RESOLVED per the round-1 documentation option (author kept the entry with a documented note); see G8, G9
G4 Manual edition, DHS hosts RESOLVED
G5 FFY2027 enhancement filing RESOLVED
G6 PR body housekeeping RESOLVED (rulespec-us#1537 per author)
G7 Test hygiene RESOLVED

PDF Audit Summary

Category Count
Changed values confirmed on rendered pages 34
Source differences confirmed (code path + 600-dpi), documented in the PR 2 (G8, G9)
Investigated and cleared 2
External documents matched 2
Missing from repo (documented or no input) 6
Repo behavior without source support 6 (one is S8)
Page anchors: correct / wrong / unverifiable 45 / 0 / 7
Pages rendered 107 (98 at 300 dpi, 9 at 600 dpi)

Validation Summary

Check Result
CI 29/29 pass
Local tests 60/60 RI cases pass
Mutation checks Prior S2/S3 mutations fail; S8 and G10 mutations survive
Regulatory accuracy FY2026 values correct; S6; documented choices in G8, G9
References 0 missing, 0 wrong; 7 unverifiable
Code patterns S7
New test values 5 cases reproduce by hand

Review Severity: COMMENT

Next Steps

To auto-fix issues: run the fix-pr workflow for this PR.

@hua7450

hua7450 commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the review. Fixes pushed in 2376cb4.

  • S6: ri_liheap_eligible now applies the federal floor the way Apply the federal 110% poverty floor to state LIHEAP programs (DC, MA, MS, NJ, OR) #10279 does: (income <= limit) | (income < floor), with floor = np.round(guideline * fpg_floor, 2) and fpg() on the qualified size at the bands' one-year lag. That lag parameter now sits at the program root (fpg_year_lag.yaml, cited to IM 2025-02 Attachment 2 and IM 2026-01) and serves both the bands and the floor. The new gov/hhs/liheap/fpg_floor.yaml (anchored to 8624#b_2_B) is byte-identical to the copy in Apply the federal 110% poverty floor to state LIHEAP programs (DC, MA, MS, NJ, OR) #10279, Add Georgia LIHEAP regular heating assistance #9968 and Add Florida LIHEAP regular heating assistance #9969, so the PRs merge in any order. Threshold-edge eligibility Case 4 puts 23 members at $150,314.99 (eligible) and at $150,315 and $150,315.01 (ineligible), all above the $148,694 limit, and ri_liheap.yaml Case 13 pays your 23-member, $150,000 household $542 (row C gas).
  • S7: Split heat_in_rent.direct into deliverables 400, natural_gas 400, electricity 0 and other 400. Row G now reads the fuel column with the same mapping as rows A–F (default=hir.direct.other), and the formula no longer special-cases electricity; ri_liheap.yaml Case 12 still pins electric heat at $0. I chose one key per printed cell over the excluded-fuel list, which could express the Electric cell only as $0 or $400.
  • S8: Kept the outcome: an unsubsidized heat-in-rent household with no electric bill and an unspecified, solar or coal fuel reads row G's Other cell and gets $400. The comments in ri_liheap_base_payment (rows A–F select, row G and the documentation) and in heat_in_rent.yaml now say what row G pays, and ri_liheap.yaml Case 14 pins [400, 400, 400], so the printed-columns-only mutation now fails. The PR body records that a building actually heated by electricity gets $0 under the matrix, so the model overpays $400 there.
  • G8: Kept gambling_winnings: where the plan and the manual conflict, we follow the manual (III.E, page 17), and unearned.yaml and the PR body document the conflict. Income Cases 22 and 26 keep 21,500 and 17,300.
  • G9: Reworded the comments in ri_liheap_income.py and earned.yaml (and the PR body): counting net business income in full, as Kansas does, matches the manual's 60% of receipts only at a 40% expense ratio and is off by receipts × (0.4 − expense ratio) otherwise. No 0.4 parameter: it needs a gross-receipts input, which is out of scope here, and 0.6 × net would deduct expenses twice.
  • G10: Added base-payment Case 10: subsidized heat in rent with no electric bill gets $0 under either subsidy flag (housing assistance, public housing), and the same unsubsidized household gets $400.
  • G11: Added ri_liheap.yaml Case 15: coal, solar and other heat, each with its own bill, are eligible and paid $0.
  • G12: Added integration.yaml with 5 scenarios ($707, $542, $657, $400, $0); ri_liheap.yaml Cases 16–17 at the two-person limit through a mixed-status family whose qualified size is 2 of 3 ($55,252 eligible and paid $509, $55,252.01 ineligible); and income Cases 28 (a negative interest entry cannot offset another member's interest: $12,200) and 29 (support and alimony paid by an excluded student and an undocumented member are deducted: $46,920).
  • G13: unearned.yaml now cites the DHS FY2026 summary (page 1), and its comment and the PR body name mortgage or sales-contract payments, AmeriCorp allowances, jury duty pay, royalties, foster care receipts and legal settlements as not represented. Contract income counts only when reported as wages or self-employment income.
  • G14: Retitled the FY2026 summary entry after its actual heading, "Section 1 - Program Components", marked the FFY2027 filing "(2027 credit amount not yet set)", and put the Appendix H and M titles in one style ("Appendix H (May 2025)"). The "Countable Income" title in deduction_sources.yaml stays, because the draft FFY2027 summary has that heading.
  • G15: Reworded deduction_sources.yaml (and the PR body): the plan and manual agree only as read through the draft FFY2027 gloss, which stays cited until DHS posts the final summary; none was found online yet.
  • G16: Income Case 26 now attributes strike pay and VA benefits to plan section 1.9 (page 6), and Case 25 links the R.I. DLT Unemployment Insurance FAQ.
  • G17: ri_liheap and ri_liheap_household_size now use adds, and the changelog fragment is renamed to ri-liheap-wave2a.added.md to match the branch. The DHS links stay on the official host with one entry per source; three of them (media/12306, media/11711 and media/12266) have no archived copy to point to.
  • G1: Unchanged: history is out of scope for this PR, and the 2025 cases are labelled as checks of the backfill only.
  • G2: Unchanged: the FY2026 matrix prints the same row E and F cells, so a separate row F key would duplicate parameters, and earlier matrices are history, which is out of scope for this PR.
  • LIHEAP wave 2a: encode Rhode Island LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1537 is refreshed to match.

Thanks also for checking workers' compensation, the size-two 125% cell, the $350 enhancement and the FY2027 limits; those stay as they are.

@DTrim99

DTrim99 commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

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

PR #9972 (author: hua7450). This round reviews head d58c4a21f9; round 1 reviewed c8b6cafa25. Four commits and one outside review came in between:

  • 0897f8604a, a merge of main at 9560e7f183. It brought in Integrate modeled state unemployment insurance into income flows #9558 (total_unemployment_compensation and its guard) and Document disjoint health premium inputs and correct consumer treatment #10046 (pre_tax_health_insurance_premiums). Its only Rhode Island-relevant change is the programs.yaml coverage line.
  • 09fddd623b, "Address review round 1 on Rhode Island LIHEAP" (21 files, +298/−170). It answers S1–S5 and G1–G7 and brings the suite to 60 cases.
  • PavelMakarchuk approved 09fddd623b on 2026-10-19. He raised three should items (S6: the federal 110% floor; S7: the row G Electric cell sits in the formula; S8: the untested UNSPECIFIED heat-in-rent path) and suggestions G8–G17.
  • 2376cb4b4e, "Address Pavel's review on Rhode Island LIHEAP" (23 files, +694/−65). It:
    • adds the 110% floor to ri_liheap_eligible, moves fpg_year_lag to the program root and adds gov.hhs.liheap.fpg_floor;
    • splits heat_in_rent.direct by fuel column;
    • adds ri_liheap.yaml Cases 13–17, eligibility Case 4, base-payment Case 10, income Cases 28–29 and a new integration.yaml (5 cases), for 74 cases in 8 files;
    • switches ri_liheap and ri_liheap_household_size to adds, renames the changelog fragment and polishes comments and references.
  • d58c4a21f9, a merge of main at 1661d715bd (Apply the federal 110% poverty floor to state LIHEAP programs (DC, MA, MS, NJ, OR) #10279, the shared 110% floor).

Neither merge had a hand-resolved conflict. The PR's fpg_floor.yaml is the same blob as main's (aeb7f8c5b0), so the #10279 add/add merged cleanly and the file is no longer in the PR's diff.

Path prefixes, as in round 1:

  • P/ = policyengine_us/parameters/gov/states/ri/dhs/liheap/
  • V/ = policyengine_us/variables/gov/states/ri/dhs/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/ri/dhs/liheap/

Line numbers refer to d58c4a21f9.

Summary

Ziming fixed all five round-1 should items:

  • S1. The unearned list reads total_unemployment_compensation. Main's guard passes at the head, and income Case 25 pins a reported $10,010.
  • S2. The blank row G Electric cell is now $0, and ri_liheap.yaml Case 12 pins both of my cases ($0 without an electric bill, $430 with one).
  • S3. Each of the three mutations now fails a test: income Case 27 (excluded members' interest), income Case 26 (all 18 unearned sources at distinct amounts) and eligibility Case 3 (size 0, no income).
  • S4. All six descriptions use my wording, and all 15 Rhode Island descriptions follow the template.
  • S5. The rental anchor opens p. 16 with #page 16,20, Appendix H uses the DHS host at #page=2, and the multi-page titles end #page 14-20 and #page 5-7.

Of the seven suggestions, five are fixed (G3–G7). G1 (backfilled history) and G2 (separate row-F amounts) are declined with reasons I accept, as in #9967–#9970.

His second commit also fixes Pavel's three should items:

  • S6. ri_liheap_eligible treats income below round(1.1 × guideline, 2) as income-eligible, on the qualified size and the bands' one-year lag. It is the same line as Apply the federal 110% poverty floor to state LIHEAP programs (DC, MA, MS, NJ, OR) #10279's states, and it binds from 23 members in FY2026 and FY2027.
  • S7. Row G is a parameter per fuel column (deliverables, natural_gas and other 400; electricity 0).
  • S8. UNSPECIFIED, SOLAR and COAL heat in rent read the Other cell ($400). ri_liheap.yaml Case 14 pins that, and the body discloses the overpayment when a building heats with electricity.

Pavel's G8–G17 are all done or answered; G8 (lottery winnings) is kept with documentation, which I accept.

There are no new critical or should findings. Three new suggestions:

Batch checks:

I checked every new expectation by hand: 18 new cases, plus the cases whose unread inputs were removed. No existing expected value changed. CI is 29/29 green at the head. The branch is 15 commits ahead of main and 17 behind, and merges cleanly.

Prior findings status

Finding Status Evidence
S1: the unearned list read the raw unemployment_compensation, so main's #9558 guard failed after the merge Fixed The list. P/income/sources/unearned.yaml:16 reads total_unemployment_compensation. No Rhode Island LIHEAP file reads the raw input. The guard. All four test_unemployment_compensation_readers.py tests pass at the head (Rest shard-1). The case. Income Case 25 reports 10,010 (the DLT formula: 10,000 × 0.0385 = 385 a week; 0.33 × 40,000 / 385 = 34.3 weeks, capped at 26, so 26 × 385 = 10,010). Rhode Island has no modeled UI, so the total and ri_liheap_income are both 10,010. The issue. rulespec-us#1537's input list names the total.
S2: row G prints no Electric amount, but electric heat in unsubsidized rent with no electric bill got $400 Fixed The value. P/payment/heat_in_rent.yaml:12-13 gives direct.electricity 0, with a comment on the blank cell. The test. ri_liheap.yaml Case 12 (ELECTRICITY, unsubsidized, wages 33,280): [eligible, eligible], base [0, 430], award [0, 430]. Disclosure. The body's not-modeled table has an "Electric heat in unsubsidized rent with no electric bill" row (eligible, $0, no enhancement). This is the eligible-but-$0 treatment the siblings give unpriced fuels.
S3: three pieces of logic had no test that would fail Fixed (1) Interest mask. Income Case 27 has a parent with 12,000, a 17-year-old with 800 of interest and a 20-year-old full-time student with 600, and expects 12,000. Without the mask, 12,000 + (1,400 − 500) = 12,900. (2) Sources. Income Case 26 sets all 18 unearned sources to distinct amounts ($100–$2,000) and expects 17,300, so dropping any entry fails. (3) Size gate. Eligibility Case 3 is an undocumented adult with no income and a gas bill: size 0, limit 0, income 0 and ri_liheap_eligible: false. Only size > 0 makes it false.
S4: six descriptions off the template Fixed All six use my wording. All 15 Rhode Island descriptions, including the new fpg_year_lag.yaml, end at "under the Low Income Home Energy Assistance Program."
S5: a wrong anchor, Appendix H without its page and on two hosts, multi-page titles without page lists Fixed Rental rule. P/income/rental_income_rate.yaml:12-13 opens #page=16, with the title "... Rental Income #page 16,20", and the comment says pages 16 and 20. Appendix H. Every entry uses dhs.ri.gov/media/9671 at #page=2, and the westbaycap.org copy is gone. The July 2026 edition (media/12306, #page=2) is cited next to it in student_age_limit.yaml and ri_liheap_income.py. Page lists. The earned and unearned titles end "#page 14-20" and "#page 5-7". Variable references use # PDF pages comments (ri_liheap_eligible.py:12,14; ri_liheap_income.py:13,16).
G1: backfilled years pay FY2026 amounts that earlier sources contradict Declined; comments reworded (accepted) Declined. History stays out of scope, with no gate and no FY2023–FY2024 matrices, as in #9967–#9970. Reworded. ri_liheap.yaml Cases 5 and 11 and base-payment Case 9 now say they check only the backfill. Cases 5 and 9 cite FY2025's $64–$1,148 range, and the body's years table labels 2025 and earlier unverified.
G2: give row F its own amounts Declined; comment fixed (accepted) V/payment/ri_liheap_base_payment.py:43-47 now says row F reads row E's band because the FY2026 cells match, and that a matrix with different row-F cells would need its own amounts. Base-payment Case 3 is renamed. Earlier matrices fall under G1.
G3: cite DHS's current summaries (Part B, lottery, self-employment) Fixed; lottery kept with documentation (accepted) Part B. P/income/deduction_sources.yaml:9-17 cites plan 1.9 and the draft FFY2027 gloss, and the body no longer lists a conflict. Self-employment. earned.yaml:2-7 cites the FY2026 summary's "Self-employment income (60%)". Lottery. gambling_winnings stays, and unearned.yaml:42-46 and the body's conflict row say that the FY2026 and draft FFY2027 summaries and the instructions omit it.
G4: sources and naming Fixed Edition. The code calls the manual the 2019 edition, and the body says "published June 11, 2019" and notes the May 2025, July 2025 and July 2026 references to later editions. Hosts. ri_liheap_income_limit.py:16 cites the DHS copy (media/12266), and the July 2026 instructions are cited.
G5: the FY2027 enhancement filing Fixed P/payment/utility_enhancement.yaml:2-5 records the Docket 26-34-GE filing and labels FY2027's $350 an unverified estimate. Its third reference is marked "(2027 credit amount not yet set)". On 2026-10-20 the docket page still lists only that filing and a procedural schedule.
G6: PR body and issue housekeeping Fixed Body. It has the plan 2.3 / manual II.B conflict row, also noted in ri_liheap_eligible.py:42-45. It says "no matrix amount", and the make format box is checked. Issue. #1537 no longer says "open as a draft".
G7: test hygiene Fixed Comments. A grep finds no squashed numbers and no "approved" or "no final award" wording. Unread inputs. heating_type and bills are gone from the income, limit, band and household-size cases. Income Case 15 keeps them because it asserts a payment. Unpriced fuels. SOLAR, OTHER and COAL eligible at $0 are now documented in ri_liheap_eligible.py:49-51 and the body, and pinned by ri_liheap.yaml Case 15.

Pavel's review (between rounds). He approved with three non-blocking should items. All are fixed, and every suggestion is answered:

Pavel's item Status Evidence
S6: the federal 110% floor was not encoded Fixed The code. V/eligibility/ri_liheap_eligible.py:24-32 computes fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) on the qualified size, then floor = np.round(guideline * p_hhs.fpg_floor, 2) and income_eligible = (income <= limit) | (income < floor). It is the same line as #10279's states. The lag. P/fpg_year_lag.yaml (moved from payment/) cites IM 2025-02 Attachment 2 and IM 2026-01. It serves both the bands and the floor, so FY2026 uses the 2025 guideline and FY2027 the 2026 guideline. Where it binds. From 23 members in FY2026 (limit 148,694 against floor 150,315) and FY2027 (152,770 against 155,012). In the backfills it binds from 21 in 2025 (floor(75,196 × 1.77) = 133,096 against 1.1 × 122,660 = 134,926) and from 19 in 2024. Tests. Eligibility Case 4 and ri_liheap.yaml Case 13; see Verified.
S7: the row G Electric cell was a literal in the formula Fixed P/payment/heat_in_rent.yaml:7-15 holds direct.deliverables / natural_gas / other 400 and electricity 0. V/payment/ri_liheap_base_payment.py:85-89 selects them with the rows A–F fuel mapping and default=hir.direct.other, with no special case for electricity.
S8: UNSPECIFIED heat in rent paid $400 with no test and an unclear comment Fixed (outcome kept, accepted) The comments. Lines 68-71 scope "UNSPECIFIED receives none" to rows A–F and say heat in rent uses rows G–I. Lines 80-84 and the documentation say what row G pays. The test. ri_liheap.yaml Case 14 (UNSPECIFIED, SOLAR, COAL; unsubsidized; no electric bill) expects [true ×3] and [400 ×3]. Disclosure. The body says that when the building heats with electricity, the model overpays $400. That is a reasonable default, since HeatingType documents UNSPECIFIED as heat in rent with an unknown fuel.
G8: lean toward dropping gambling_winnings Declined (accepted) Kept under the stated rule (the manual governs where it conflicts with the plan), and disclosed in unearned.yaml:42-46 and the body. Income Cases 22 and 26 keep 21,500 and 17,300.
G9: the self-employment comment was inaccurate Fixed ri_liheap_income.py:38-44 and earned.yaml:2-7 say net income in full matches 60% of receipts only at a 40% expense ratio and is off by receipts × (0.4 − expense ratio), citing Kansas. No 0.4 parameter is added, which is right: 0.6 × net would deduct expenses twice.
G10: pin the subsidized term on row G Fixed Base-payment Case 10: heat in rent, no electric bill, natural gas: [0, 0, 400] for housing assistance, public housing and neither.
G11: pin COAL, SOLAR and OTHER eligible at $0 Fixed ri_liheap.yaml Case 15.
G12: coverage gaps Fixed integration.yaml (5 cases), ri_liheap.yaml Cases 16–17 (two-person limit through a mixed-status family), income Case 28 (negative interest) and Case 29 (deductions of excluded members).
G13: cite the FY2026 summary; name unrepresented sources Fixed unearned.yaml:59-60 cites media/9371#page=1, and lines 9-13 and a body row name the sources without inputs.
G14: titles Fixed The FY2026 summary entry is titled "Section 1, Program Components", which is the document's heading. The FFY2027 filing is marked "(2027 credit amount not yet set)". The appendix titles use one style. "Countable Income" stays in deduction_sources.yaml, which is correct: it is the draft FFY2027 summary's heading.
G15: "so the sources agree" rested on the draft gloss Fixed deduction_sources.yaml:9-14 says the plan and manual agree only as read through the draft gloss, which stays cited until DHS posts a final summary.
G16: test-comment sourcing Fixed Income Case 26 attributes strike pay and VA benefits to plan 1.9 (p. 6), and Case 25 links the DLT UI FAQ.
G17: nits Fixed ri_liheap and ri_liheap_household_size use adds. The fragment is changelog.d/ri-liheap-wave2a.added.md, which is top level and typed added. The DHS links stay on the official host, with one entry per source.

New findings

Critical (must fix)

None.

Should address

None.

Suggestions

1. After #10182, count military SBP survivor annuities through military_retirement_income.

  • Where: P/income/sources/unearned.yaml:24 lists military_retirement_pay, with pension_income at line 23 and survivor_benefits at line 26. The comment at lines 20-22 says military retirement pay is listed separately from pension_income.
  • What changed on main: Wire military retirement pay and survivors into federal and state tax (#10181) #10182 merged on 2026-10-20, after this head's last merge at 1661d715bd.
    • At this head, military_retirement_pay is documented as including survivor benefits.
    • On main it reads "Taxable retirement pay received by former members of the uniformed services".
    • SBP annuities now go in military_retirement_pay_survivors: "Taxable survivor annuity payments received by surviving spouses ... (such as the Survivor Benefit Plan (SBP)...)".
    • military_retirement_income adds both. pension_income does not include the new input.
  • The rule counts these payments.
    • Manual III.E (p. 15) lists "Pension and Retirement Income" (documented by "1099-R").
    • FY2026 plan 1.9 (p. 6) lists "Retirement / pension benefits", and the DHS FY2026 summary (p. 1) lists "Retirement and pension benefits".
  • Effect on the merged tree (worked out from the code, not run). A surviving spouse aged 60 (not Medicare-enrolled) has $24,000 a year of SBP annuity entered in military_retirement_pay_survivors, natural gas heat with a $1,200 bill and no other income, in 2026:
  • Why a suggestion, not should:
  • Fix, if taken here:
    • Replace the entry with military_retirement_income, and update the lines 20-22 comment.
    • Add a military_retirement_pay_survivors amount to income Case 26, or add a separate case. Case 26's 17,300 is unchanged by the swap itself.
    • Update the countable-income input list in rulespec-us#1537.

2. After #10168, count Rhode Island's State Supplementary Payment (ri_ssp).

  • Where:
    • P/income/sources/unearned.yaml lists ssi (line 19) but not ri_ssp. Its comment at line 5 says "SSI is the federal benefit; a separate RI state supplement is not modeled."
    • The body's not-modeled table has "State SSI supplement | — | Not modeled; ssi is the federal benefit."
    • T/integration.yaml Case 1 says the retiree "receives only federal SSI" (line 15), and income Case 11 says "no Rhode Island state supplement is added" (line 306).
  • What changed on main: Add Rhode Island state supplementation for 2026 #10168 merged on 2026-10-20 (e180056384), after this head's last merge.
    • It adds ri_ssp, a monthly, person-level payment gated to Rhode Island. In 2026 it is $39.92 in the recipient's own household, $51.92 in another's household, $332 in certified residential care and $45 in a Title XIX facility.
    • It lists ri_ssp in SNAP's and HUD's unearned sources, household_state_benefits and spm_unit_benefits.
  • The rule counts these payments. Two of the three documents below are ones the PR already cites:
    • The DHS Summary of the FFY2026 State Plan (p. 1), cited in both source lists, counts "Supplemental Security Income (SSI) including State Supplemental Payment (SSP)".
    • The draft FFY2027 summary (file p. 3) repeats it.
    • Appendix H, May 2025 and July 2026 (p. 2), asks for "Fixed Income such as SSDI, SSI, SSP, RI Works: A copy of the current award letter".
  • Effect on the merged tree (worked out from the code, not run):
    • integration.yaml Case 1 as written. The 72-year-old in her own household with SSI only also gets ri_ssp on main. Her countable SSI income is 0, so there is no reduction: 39.92 × 12 = 479.04. Counting it gives ri_liheap_income 12,407.04 instead of 11,928. That is still row B (at most 15,650), so the award stays $707. Case 1's income assertion would change if the fix is taken.
    • A case where the award changes. A disabled SSI recipient aged 45 lives alone, works for $500 a month ($6,000 a year), and has natural gas heat with a bill. SSI is 994 − (500 − 20 − 65) / 2 = 786.50 a month, or 9,438 a year. Her SSI countable income (207.50) is below the federal amount, so ri_ssp is the full 39.92.
      • Merged tree: 6,000 + 9,438 = 15,438, at most 15,650: row B, 211 + 350 = $561.
      • Counting ri_ssp: 15,438 + 479.04 = 15,917.04, above 15,650: row C, 192 + 350 = $542.
    • Unaffected cases. Income Cases 11 and 26 do not change, because their SSI members (aged 40, 8 and 60, not disabled) are not SSI-eligible, so ri_ssp is 0.
  • Why a suggestion, not should:
  • Fix, if taken here:
    • Add ri_ssp to P/income/sources/unearned.yaml next to ssi, and drop the line 5 comment and the body row.
    • Update integration.yaml Case 1 (ri_liheap_income 12,407.04; award unchanged) and the Case 11 comment. Optionally add the wage case above.
    • Update Add OR income subtraction of taxable social security benefits #1537's countable-income inputs and its "Rhode Island SSI supplement (ssi is federal)" gap note.

3. Pin the floor's cent rounding.

  • Where: V/eligibility/ri_liheap_eligible.py:31 rounds the floor with np.round(guideline * p_hhs.fpg_floor, 2). Pavel's S6 asked for that rounding (as Add Florida LIHEAP regular heating assistance #9969 S4), and the body says the floor is "rounded to the cent".
  • Why no test pins it: in floating point, 1.1 × 136,650 is exactly 150,315.0. Eligibility Case 4 row 2 (150,315) is therefore ineligible with or without the rounding. No other case reaches the floor arm at an exact boundary.
  • A case that would pin it (hand-computed). Forced size 28 in 2026: guideline 15,650 + 27 × 5,500 = 164,150, and 1.1 × 164,150 = 180,565.00000000003 in floating point. The limit is floor(81,254 × 1.98) = 160,882, so the floor arm decides. At a forced income of 180,565, the rounded floor gives false; without the rounding the result is true.
  • Why a suggestion: the line is right and identical to Apply the federal 110% poverty floor to state LIHEAP programs (DC, MA, MS, NJ, OR) #10279's states. Only a sub-cent edge for households of 28 or more members depends on it.

Verified

  • Mutation check (item 13), reasoned from the tests and code at the head:
    • New floor logic in ri_liheap_eligible:
      • The | floor arm. Eligibility Case 4 row 1 (150,314.99 is above the 148,694 limit, but eligible) and ri_liheap.yaml Case 13.
      • The rate and the strict <. Case 4 brackets the floor: 150,314.99 true, 150,315 false and 150,315.01 false. A <= would admit row 2.
      • The one-year lag. Lag 0 (1.1 × 140,920 = 155,012) would admit row 2, and lag 2 (1.1 × 133,420 = 146,762) would reject row 1.
      • Qualified size, not SPM size. Case 4 forces size 23 in a one-person SPM unit. The SPM size would give a floor of 17,215 and reject row 1.
      • The cent rounding: not pinned (Suggestion 3).
    • Row G by fuel column:
      • Each cell. Deliverables, Natural Gas and Other: ri_liheap.yaml Case 10 units 1–3 (FUEL_OIL, NATURAL_GAS, OTHER, all 400). Electricity: Case 12 unit 1 (0).
      • The Other default for UNSPECIFIED, SOLAR and COAL: Case 14.
      • where(subsidized, 0, ...): base-payment Case 10 under both flags.
    • The S3 mutations: income Cases 26 and 27 and eligibility Case 3 (above).
    • adds rewrites. ri_liheap still has defined_for = "ri_liheap_eligible", and ri_liheap.yaml Case 3 pins its zeros. ri_liheap_household_size is pinned by household-size Case 1 and Cases 16–17.
    • Unchanged since round 1: the other branches. Round 1 confirmed them by mutation runs.
  • State-gated keys (item 15, NH Add New Hampshire state supplementation for 2026 #10156).
    • The pattern is present. ri_liheap_income_band is an int gated to Rhode Island with default 0, and p.amount.*[band] reads it as a key (breakdown range(1, 6)).
    • The guard and its test. max_(band, 1) covers it (V/payment/ri_liheap_base_payment.py:35). Base-payment Case 4 row 2 forces band 0 and gets 0, so removing the guard would raise there. ri_liheap.yaml Case 3 runs RI and MA units in one simulation.
    • The rest. The row-F key, len(p.fpg_rates) + 1 = 5, is always valid. The new floor uses size only in arithmetic, and state_group is always a valid key. Row G is a select, not a keyed lookup.
  • Integrate modeled state unemployment insurance into income flows #9558 (item 11). The guard's four tests pass at the head, and no Rhode Island file reads raw unemployment_compensation.
  • Document disjoint health premium inputs and correct consumer treatment #10046 (item 14) and the wage lessons (OK Add Oklahoma state supplementation for 2026 #10165, NH Add New Hampshire state supplementation for 2026 #10156 round 3).
  • Federal 110% floor (42 U.S.C. 8624(b)(2)(B)). It is applied in every period through gov.hhs.liheap.fpg_floor (1.1 from 1985-10-01), so the 2024 and 2025 backfills are covered too. The plan restates it (p. 45), and the variable cites it at #b_2_B.
  • IIJA and FY2027 (item 12).
    • IIJA. Rhode Island pays no supplement; the $350 is ratepayer-funded under § 39-1-27.12.
    • FY2027 sources. On 2026-10-20 the Clearinghouse returns 404 for a Rhode Island FY2027 plan and matrix, and Docket 26-34-GE has no amount yet. The FY2027 limits are encoded, and FY2027 payments remain documented estimates.
  • Other main commits.
  • New expectations, checked by hand. For 2026 the limits are floor(81,254 × share): 42,252 (size 1), 55,252 (size 2), 68,253 (size 3), 81,254 (size 4) and 148,694 (size 23). The 2025 guideline is 15,650 + 5,500 per additional person.
    • ri_liheap.yaml:
      • Case 12: 33,280 ≤ 42,252. Heat in unsubsidized rent meets the burden, so [true, true]. Unit 1 has no electric bill: row G Electric 0, and no enhancement because no utility account receives a grant. Unit 2 gets row H, 80 + 350 = 430.
      • Case 13: 150,000 > 148,694 but < 150,315, so eligible. The bands are 102,488 / 136,650 / 170,813 (170,812.50 rounded half up), giving band 3 and row C gas 192 + 350 = 542.
      • Case 14: [true ×3], and row G Other 400 with no enhancement: [400 ×3].
      • Case 15: each fuel's bill (coal, pre-subsidy electricity for SOLAR, other fuel) gives a positive heating_expense, so [true ×3]. No matrix amount and no utility grant: [0 ×3].
      • Case 16: the undocumented parent is not in the size, so the size is 2, but her 55,252 counts. 55,252 ≤ 55,252 gives eligible. 55,252 is above 31,725 (150% of 21,150), so band 5 and gas 159 + 350 = 509.
      • Case 17: 55,252.01 is above the limit and above the 23,265 floor, so false and 0.
    • eligibility/ri_liheap_eligible.yaml:
      • Case 3: size 0, limit 0, income 0, false.
      • Case 4: limit 148,694 ×3; floor 1.1 × 136,650 = 150,315.00; [true, false, false].
    • payment/ri_liheap_base_payment.yaml Case 10: [0, 0, 400].
    • income/ri_liheap_income.yaml:
      • Case 25: 10,010.
      • Case 26: 1,000 + 500 + 1,200 + 600 + 1,500 + 2,000 + 700 + 800 + 900 + 1,100 + 1,300 + 1,400 + 1,600 + 300 + 200 + 1,700 + 400 + 100 = 17,300. At 60 the member is not Medicare-enrolled, so there is no Part B deduction.
      • Case 27: 12,000 (12,900 without the mask).
      • Case 28: 12,000 + max(0 + 700 − 500, 0) = 12,200.
      • Case 29: size 2. Counted 33,280 + 16,640 = 49,920 (the student's 8,320 is excluded). Every member's support and alimony paid is deducted: 49,920 − 1,200 − 1,800 = 46,920.
    • integration.yaml:
      • Case 1: 11,928, which is above 11,738 and within 15,650: band 2, electric 357 + 350 = 707.
      • Case 2: size 3 and 33,280. The size-3 guideline is 26,650, and 125% is 33,312.50, rounded to 33,313. So band 3 and gas 192 + 350 = 542.
      • Case 3: size 4. 33,280 + 16,640 = 49,920 is above 48,225 (150% of 32,150), so band 5. Deliverables pay 657, with no enhancement.
      • Case 4: public housing, heat in rent and an electric bill, so eligible. 16,640 is band 3 (unused). Row I, 50 + 350 = 400.
      • Case 5: 66,560 is above 55,252 and the 23,265 floor, so false. The base is band 5 gas 509, and the award is 0.
    • Changed inputs, unchanged outputs:
      • The cases: income-limit Cases 1–3, band Cases 1–4, household-size Cases 1–2 and income Cases 1–14 and 16–24 drop heating_type and bills.
      • None of those variables reads them. The limit reads size and state. The band reads size, income and state group. Income reads person sources. Size reads is_citizen_or_legal_immigrant.
  • Inputs not checked. I didn't check the 2026 Rhode Island minimum wage ($16) or the DLT benefit parameters (3.85%, 26 weeks). They are inputs only, and every expectation follows from them.
  • Wiring.
    • Registry. The programs.yaml RI entry is partial, with verified_years: "2026" and a two-sentence note, and test_programs_registry passes.
    • Aggregates. No aggregate wiring, which matches every merged LIHEAP state.
    • Gating. defined_for = StateCode.RI is on six variables, and ri_liheap is gated by ri_liheap_eligible.
    • Changelog. The fragment is top level and typed added, and it names the floor.
  • Partner tests. The PR touches none, and Household API Partners passes.

Checklist results (LIHEAP wave 2a)

  1. State plan and manual: pass. Encoded matrix values are unchanged since round 1; the row G split encodes the printed cells. I re-read the DHS FY2026 and draft FFY2027 summaries, both Appendix H editions, manual III.E and III.H and plan 1.9 for Suggestions 1–2 and item 14.
  2. Income definition: pass. Gross wages, gross Social Security less Part B, per-source floors and the Integrate modeled state unemployment insurance into income flows #9558 total. Suggestions 1 and 2 cover the post-Wire military retirement pay and survivors into federal and state tax (#10181) #10182 SBP input and the post-Add Rhode Island state supplementation for 2026 #10168 ri_ssp.
  3. Backdating: pass for the claimed year. 2025 and earlier are documented, unclaimed estimates (G1, declined). The floor applies in every year.
  4. Household and arrangement rules: pass. Every heat-in-rent route, both subsidy flags and the unpriced fuels are pinned (Cases 12, 14 and 15, base Case 10).
  5. Tests: pass. 74 cases in 8 files; every new expectation checked by hand. Periods are plain, and the two-person and 23-person edges are covered.
  6. Descriptions: pass. All 15 follow the template.
  7. References: pass. One entry per source, #page 16,20, #page 14-20 and #page 5-7 titles, # PDF pages comments and the #b_2_B anchor.
  8. Wiring: pass. Registry, no aggregate (as in the siblings), defined_for gating, and no take-up beyond tanf's.
  9. Axiom: valid queued line. Add OR income subtraction of taxable social security benefits #1537 matches the head (see below).
  10. Branch and CI: 29/29 green. A clean merge with main; the siblings conflict only in programs.yaml.
  11. Integrate modeled state unemployment insurance into income flows #9558: fixed. The guard passes.
  12. IIJA / FY2027: not applicable (no supplement). No FY2027 plan, matrix or enhancement amount is published.
  13. Mutation check: pass, except the floor's cent rounding (Suggestion 3).
  14. Document disjoint health premium inputs and correct consumer treatment #10046 health premiums: not applicable. Only Medicare Part B is deducted, and wages are gross employment_income.
  15. State-gated index defaults: guarded. The band is raised to 1, and base Case 4 row 2 pins it.
  16. Wire military retirement pay and survivors into federal and state tax (#10181) #10182 survivor annuities: Suggestion 1.
  17. Merged state SSPs: Suggestion 2. DHS's summaries and Appendix H count SSP, and ri_ssp is missing from the list.

Axiom line assessment

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

  • Issue state.
    • Add OR income subtraction of taxable social security benefits #1537 is open and labelled pe-parity and enhancement. It was last updated 2026-10-19 21:03 UTC and has no comments.
    • rulespec-us main (5796861e58, 2026-10-20) has no Rhode Island DHS or LIHEAP module: us-ri/policies/ holds only cms and income_tax. So queued is still the right form.
    • It records its blockers: sources that need ingest, an unchecked signed release, encoder approval and no reviewed PE revision.
  • Dispatch-ready. It has:
    • module paths with corpus status;
    • the verbatim manual, plan, matrix, instruction, PUC and federal text;
    • required outputs for every variable;
    • companion tests 1–19, "hand-derived from the sources ... none is taken from policyengine-us output", and mapped to PE cases.
  • Matches the head d58c4a21f9:
    • Cases: 74 cases in 8 files, listed per file.
    • Eligibility: the floor is round(1.1 × G, 2) on the qualified size with the year-before guideline.
    • Row G: by fuel column, Electric 0, with unlisted and unknown fuels reading Other.
    • Inputs: they name total_unemployment_compensation.
    • Companion tests 17–19 match the floor cases, Cases 16–17 and integration.yaml.
  • Updates it would need if the suggestions are taken: the countable-income inputs (military_retirement_income, ri_ssp) and the "Rhode Island SSI supplement (ssi is federal)" gap note.

CI status

29 pass, 0 pending, 0 failed (run 39324242551 on head d58c4a21f9, pull_request, 2026-10-19 21:02 UTC to 2026-10-20 01:46 UTC). I re-checked gh pr checks 9972 at the end of this review.

  • Quick Feedback ran all eight Rhode Island LIHEAP files at the head: 4 + 3 + 29 + 5 + 10 + 4 + 17 + 2 = 74 passed. The whole Rhode Island tree also passed (473).
  • Rest (Python, shard-1) passed:
  • Also passed: Household API Partners, Microsimulation, both Rest jobs, all 11 Baseline shards, all 9 Contrib shards, PR validation, Package and compatibility, and codecov patch and project.
  • Locally: no tests or probes were run; I checked only plain floating-point products for Suggestion 3.

Branch status

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.

Round 2: all five should-address items from round 1 are fixed, and so are Pavel's S6-S8 (the 110% floor among them). Three open suggestions: #10182 survivor annuities, ri_ssp now that #10168 has merged, and pinning the floor's cent rounding. Full report in the comment above.

# Conflicts:
#	policyengine_us/programs.yaml
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 Rhode Island LIHEAP regular heating assistance

3 participants