Skip to content

Add Oklahoma LIHEAP regular heating assistance - #9970

Merged
hua7450 merged 13 commits into
mainfrom
ok-liheap
Oct 20, 2026
Merged

hua7450 merged 13 commits into
mainfrom
ok-liheap

Conversation

@hua7450

@hua7450 hua7450 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Adds Oklahoma's LIHEAP regular winter heating assistance for FY2025 through FY2027. The model counts members who meet SNAP's citizenship and immigration rules for household size, adds income deemed from ineligible members after their own deductions and a need allowance, and tests monthly gross income against 130% of the prior year's poverty guidelines. It then subtracts the earned-income, medical, child support and child care copay deductions and reads the Appendix C-7-A winter matrix by net monthly income, household-size group, fuel and dwelling type. In FY2026, a 70-year-old who heats with natural gas and receives $1,000 a month of Social Security has $1,000 of gross income, within the $1,696 limit. After the $202.90 Medicare Part B premium and a $150 Medigap premium are deducted, net income is $647 a month, and the household receives $265. The limit test counts Social Security before the premium, so a retiree with $1,780 a month is ineligible even when the premium is withheld.

Fixes #9961

Regulatory authority

Eligibility

Requirement Source How modeled
Oklahoma residence — defined_for = StateCode.OK
Household size counts members who meet the citizenship and immigration rules OAC 340:20-1-10(d)(3) and (h)(3), pointing to the SNAP rule OAC 340:50-5-67(a); 7 CFR 273.4; P.L. 119-21 section 10108 Oklahoma lists no LIHEAP categories of its own, so the model reuses is_snap_immigration_status_eligible for January of each year: the SNAP status list then in force and its qualified-alien waiting rule. Before July 2025 the list includes refugees, asylees, people granted withholding of deportation, parolees and conditional entrants; from then it is citizens, lawful permanent residents and Cuban and Haitian entrants. So 2025 uses the earlier list and 2026 and 2027 the narrowed one. A household with no qualifying member is ineligible.
Income deemed from ineligible members OAC 340:20-1-11(a)(4); Appendix C-1 Schedules IX-A and IX-B Each tax unit's ineligible members contribute their countable income minus their own deductions and a monthly need allowance: TANF Schedule IX-A when the group includes an adult, otherwise the children-only Schedule IX-B ($193 for one child up to $1,333 for nine or more). The contribution enters gross income before the limit test.
Gross income limit FY2025 and FY2026 plans, section 2.1, page 9; Appendix C-7; LIHEAP IM 2024-02, IM 2025-02 and IM 2026-01; December 2024 and January 2026 announcements 130% of the prior year's guideline. The monthly limit for sizes 1–8 and the amount for each member above eight are each rounded up to the dollar, which reproduces every printed C-7 amount in FY2025, FY2026 and FY2027. Monthly gross income is rounded half up to the dollar (OAC 340:20-1-11(a)), and the limit is inclusive.
Heating responsibility OAC 340:20-1-10(e) and (h)(1); OAC 340:20-1-19(d)(1)–(2); OAC 340:20-1-13(2)(B)–(C); FY2026 plan section 2.3, page 9 A household billed directly qualifies with a positive bill for its heating_type or a reported obligation (has_heating_expense). A renter or roomer whose rent includes heat must pay a verified surcharge, subsidized or not; a positive bill for its heating_type stands in for the surcharge, and the flag alone does not qualify. Housing-assistance inputs do not change the result. heating_type NONE is ineligible.
No categorical eligibility and no asset test FY2025 and FY2026 plans, item 2.3, page 9; FY2026 plan question 1.4, page 5, and resource statement, page 14 SSI or TANF receipt does not waive the income limit. Resources are not tested in any year. In FY2025 and FY2026 the adopted text still pointed to a resource level in Appendix C-7, but the 10/1/2024 and 10/1/2025 editions print none (see the source conflicts below).

Countable income

Item Source How modeled
Earned income OAC 340:20-1-11(a)–(b); OAC 340:50-7-22(9) Counts wages and net self-employment, SSTB, farm operations and partnership/S-corporation income, each floored at zero, with no further business-expense deduction. Excludes the earnings of a member under 18 who attends elementary or high school and is a tax dependent.
Unearned income OAC 340:20-1-11(a)–(b); OAC 340:50-7-29(c), applied by analogy; FY2025–FY2027 plans, section 1.9, page 6 Counts unemployment (total_unemployment_compensation: the reported amount, otherwise modeled Oklahoma unemployment insurance), strike benefits, Social Security, SSI, pensions, retirement account distributions, military retirement pay, survivor benefits, railroad retirement (gross), workers' compensation, disability benefits, rental and farm rental income, alimony, child support received, interest, ordinary dividends, veterans benefits, cash support (financial_assistance) and estate income. Floors each source at zero, so a loss in one source offsets nothing.
Social Security OAC 340:20-1-11(a) and (c) Counts gross Social Security in the income test. The Medicare Part B premium is a medical deduction after the test (see the source conflicts below).
TANF FY2026 plan section 1.9, page 6 Counts the take-up-gated tanf aggregate, which includes ok_tanf, once per household.
Deductions for the payment band OAC 340:20-1-11(c); OAC 340:50-5-4; OAC 340:50-7-31(a)(3)(A), applied by analogy; Appendix C-7 After the gross test, subtracts for each qualifying member $240 a month of earnings per employed member (capped at earnings), medical expenses of members who are elderly or disabled under OAC 340:50-5-4, and child support paid. OAC 340:50-5-4 restates the 7 CFR 271.2 definition, so the model reuses is_usda_elderly (60 or older) and is_usda_disabled (benefit receipt). Medical expenses are snap_allowable_medical_expenses, the modeled part of SNAP's list in OAC 340:50-7-31(a)(3)(A), without SNAP's $35 threshold: health premiums paid after tax or through payroll, the whole Part B premium of Medicare enrollees (medicare_enrolled; a nonzero health_insurance_premiums input replaces the non-Medicare and Part B split) and other medical costs. Subtracts the household's child care copay when it receives an Oklahoma child care subsidy. Ineligible members' deductions apply only within deeming.
Monthly rounding OAC 340:20-1-11(a) Rounds monthly gross and net income half up to the dollar before the limit test and the band lookup.

Benefit

Each cell lists household sizes 1–3 / 4–6 / 7 or more.

Schedule When used Net income $0–$400 $401–$700 $701 and up
Ordinary Natural gas, electricity, wood or coal, billed directly $365 / $402 / $430 $265 / $292 / $312 $235 / $259 / $277
Delivered Propane, fuel oil or kerosene, billed directly $425 / $468 / $500 $350 / $385 / $412 $280 / $308 / $330
Renter Heat included in rent, any fuel $150 / $165 / $180 $110 / $120 / $135 $100 / $110 / $125
Roomer Heat included in rent, ok_liheap_dwelling_type ROOMER $70 / $0 / $0 $50 / $0 / $0 $40 / $0 / $0
  • ok_liheap_dwelling_type (STANDARD by default, or ROOMER) is the only new input. It selects the roomer schedule for heat-in-rent households; C-7-A prints $0 for roomer households of four or more.
  • The heat-in-rent schedules cover "All Energy Sources", so the matrix prices any fuel other than NONE. The award still needs the surcharge bill for the household's heating_type, so an UNSPECIFIED fuel, which carries no bill, pays $0. Directly billed OTHER, SOLAR and UNSPECIFIED fuels have no column and pay $0; a household that meets the other conditions stays eligible.
  • Appendix C-7-A, dated 10/1/2021, sets the amounts in all three years; the FY2026 clearinghouse matrix prints the same cells.
  • The reported bill does not cap the award.

Years covered

Model year Program year Guideline One-person monthly limit Each member above eight
2025 FY2025, from October 1, 2024 2024 $1,632 $583
2026 FY2026, from October 1, 2025 2025 $1,696 $596
2027 FY2027, from October 1, 2026 2026 $1,729 $616

A calendar-year period reads the parameters in force on January 1. Formulas are undated and verified_years is "2025-2027". The income-limit parameters take effect October 1, 2024, the start of FY2025. LIHEAP IM 2024-02, IM 2025-02 and IM 2026-01 make each January's poverty guidelines mandatory from the next October 1, and plan item 2.1 names only the HHS Poverty Guidelines. The C-7 limits confirm that Oklahoma uses the mandatory year: 1.3 × $15,060 / 12 = $1,631.50 rounds up to the printed FY2025 $1,632, while the 2025 guideline would give $1,696. The 10/1/2024, 10/1/2025 and 10/1/2026 editions of Appendix C-7 match the model's limits and print the $240 deduction; the 1/1/2025, 7/1/2025, 4/1/2026 and 7/1/2026 editions of Appendix C-1 print the same Schedule IX-B. A 2025 period applies OAC 340:20-1-11 as adopted effective September 15, 2025, which replaced a 38-item list of income exclusions (Register pages 578–580); the earlier list gives the same result for every modeled source. The text as amended effective September 15, 2026 (43 Ok Reg No. 23), in force for FY2027, keeps every modeled rule, drops the liquid-resource subsection 340:20-1-11(e) and sets out the surcharge verification in 340:20-1-13(2)(B)–(C). Years before 2025 are unverified backfilled estimates.

Not modeled and source conflicts

Item Source Model treatment
Gross business receipts and the 50% business-expense deduction OAC 340:20-1-11(c)(4) Uses existing net business inputs with no further deduction.
Partnership and S corporation income OAC 340:20-1-11(a)(2); OAC 340:50-7-29(b)(2) and (c)(8) Counts partnership_s_corp_income as earned income, as the Kansas, Kentucky, Oregon and New York LIHEAP lists do. The input does not separate active partners' earnings from S corporation profit shares and passive partners' distributions, which Oklahoma SNAP counts as unearned; only the $240 earned-income deduction differs.
Exclusions that aggregate inputs cannot isolate: irregular small gifts, qualified educational and VA aid, restricted tribal trust receipts, redirected support and third-party payments OAC 340:20-1-11(b); OAC 340:50-7-22 Not separated from the counted sources.
Composition of the ineligible need group OAC 340:20-1-11(a)(4) Tax units approximate it; actual claiming, several possible claimants and separate returns can differ.
Payer of the child care copay OAC 340:20-1-11(c) Deducted once from net income. A copay that an ineligible member pays is not moved into deeming, which can overstate gross income.
Disability categories with no input OAC 340:50-5-4(a)(3)–(5) and (a)(10)–(11); 7 CFR 271.2 Supplemental and government disability retirement benefits, Railroad Retirement disability annuities, interim assistance and disability-based Medicaid have no inputs, so members under 60 who qualify only through them get no medical deduction. The general is_disabled flag is not used because it shows no benefit receipt. The veteran flags that is_usda_disabled reads stand in for (a)(6)–(9), so an aid-and-attendance or housebound veteran ((a)(7)) is entered as is_permanently_disabled_veteran.
Noncitizen nationals, Compact of Free Association residents, trafficking victims and battered noncitizens 7 CFR 273.4; 7 U.S.C. 2015(f) No immigration_status category; not counted in household size.
Written roomer agreements, shared meters, institutional living and tribal LIHEAP receipt OAC 340:20-1-10 Not identified by existing inputs.
Utility allowances on direct bills OAC 340:20-1-10 Reported heating costs are assumed to be the obligation remaining after any allowance.
OTHER, SOLAR and unspecified fuels billed directly Appendix C-7-A Pay $0 as a coverage gap (#9754 for unspecified fuel). Solar is not an approved main energy source under OAC 340:20-1-10(b)(1).
State supplementary payments — Not modeled; ssi is the federal benefit.
Crisis, cooling, weatherization and equipment assistance — Out of scope.

Where the FY2026 plan and the OAC differ, the model follows the OAC; where the OAC is silent, it follows the plan:

Topic FY2026 plan OAC and model
Child earnings Section 1.9 (page 6) does not count "Earned income of a child under the age of 18" OAC 340:20-1-11(b) applies the SNAP exclusions, and OAC 340:50-7-22(9) excludes only the earnings of an elementary or high school student 17 or younger under parental control. The model excludes earnings of school-attending tax dependents under 18 and counts other minors' earnings.
Resources Page 14: "Oklahoma does not use resources (assets) to determine eligibility for energy assistance" The September 2025 adoption (Register pages 576, 581) kept 340:20-1-10(h)(2) ("gross income and resource standards") and a liquid-resource limit "per OKDHS Appendix C-7" in 340:20-1-11(e). The 10/1/2024 and 10/1/2025 C-7 editions print no resource level, plan item 2.3 answers No to an assets test in FY2025 and FY2026 (page 9), and the text as amended effective September 15, 2026 removes the resource standard from (h)(2) and drops 340:20-1-11(e). The model has no asset test, and a comment in ok_liheap_eligible records these sources.
Medicare premium Section 1.9 of the FY2025, FY2026 and FY2027 plans (page 6) checks "Excluding MediCare deduction" for SSA benefits OAC 340:20-1-11(a) counts "All gross earned and unearned income", and 340:20-1-11(c) requires the household to meet the gross income standard "before allowing applicable income deductions", which include "Medicare premiums" (OAC 340:50-7-31(a)(3)(A)(vi)). The FY2026 plan's narrative (page 7) agrees: "OKDHS uses gross income to determine LIHEAP eligibility." The model counts gross Social Security in the income test and deducts the premium afterwards.

Two readings are recorded in code notes but not followed:

Topic Reading not followed Model
Immigration status The eCFR text of 7 CFR 273.4(a)(6) still lists refugees and asylees, which would keep them eligible. OAC 340:20-1-10(d)(3) points to the SNAP rule 340:50-5-67, so the model follows SNAP's list as amended by P.L. 119-21.
Heat in rent OAC 340:20-1-10(c) counts "undesignated payments for energy in the form of rent", and (f)(3) names only subsidized heat-in-rent households as non-vulnerable, which could pay an unsubsidized renter with no surcharge. OAC 340:20-1-19(d)(1) pays renters, roomers and boarders "who pay a surcharge", 340:20-1-19(d)(2) and 340:20-1-13(2)(B)–(C) set how it is verified, and 340:20-1-10(h) denies households that do not verify responsibility. Plan section 2.3 (page 9) agrees, so the model requires the surcharge.

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

80 YAML cases in 13 files cover:

  • all 36 C-7-A cells including the roomer zeros, size-group edges at 3, 4, 6 and 7, all seven priced fuels, heat in rent for standard renters and roomers with any fuel, and $0 for directly billed OTHER, SOLAR and UNSPECIFIED;
  • half-up rounding at the $401 and $701 band starts and at the gross limit ($1,696.25 a month is eligible; $1,696.50 is not);
  • FY2026 limits for sizes 1–8, FY2027 limits for sizes 1–10 and FY2025 limits for sizes 1, 8 and 9, and $1,000,000 in a bank account leaving FY2026 and FY2027 eligibility unchanged (no asset test);
  • each represented immigration status under the narrowed 2027 SNAP list, the five-year waiting rule and its exceptions for permanent residents, and a refugee who is eligible in 2025 but not in 2027;
  • deeming for one ineligible adult, an adult couple with a dependent, two tax units, children-only groups up to the nine-or-more amount and a child turning 18, plus the 2025 Schedule IX-B and $240 deduction;
  • the student earnings conditions, positive net farm income, per-source loss floors in earned and unearned income, gross Social Security in the income test with the Part B premium deducted afterwards, modeled Oklahoma unemployment insurance ($432 a week for 15 weeks, or $6,480, which moves a one-person household from $365 to $265), retirement account distributions, military retirement pay, TANF with and without take-up, and SNAP and housing assistance excluded;
  • the $240 allowance per worker, an unused allowance, medical deductions per elderly or disabled member (payroll and after-tax health premiums, the whole Part B premium, and an SSDI recipient under 60 beside a member flagged disabled with no qualifying benefit), child support paid, the zero floor, the copay with and without a subsidy, and a 50-year-old with $9,000 of SSDI whose medical deduction raises the award from $235 to $265, while the same income from employer disability insurance earns no deduction;
  • heating responsibility: the heat-in-rent surcharge for subsidized and unsubsidized renters and roomers, the responsibility flag counting only for direct payers, public housing and a direct obligation, directly billed SOLAR and OTHER households that stay eligible with a $0 award, plus no heat, no qualifying member and out of state;
  • final awards for a mixed-status household, a delivered-fuel household, renter, roomer and surcharge routes, deemed income entering the gross test before the worker's deduction, TANF and the copay each applied once, a retiree whose Part B premium does not restore eligibility, and military retirement pay above and below the limit;
  • five end-to-end households in integration.yaml: an FY2025 retiree heating with propane ($350), an FY2026 single parent of three with a child care copay ($259), an FY2026 SSI recipient roomer with heat in rent ($40), an FY2026 mixed-status family with deemed income ($235) and an FY2027 nine-person household at the additional-member limit ($277).

Every case specifies heating_type. The tests were not run locally; CI validates them. A reviewer's local run passed all 72 earlier cases at f0e2f40.

  • 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#1535 queued

🤖 Generated with Claude Code

hua7450 and others added 4 commits October 3, 2026 19:49
- Count Social Security net of the Medicare Part B premium, floored per
  person (FY2025-FY2027 plans section 1.9).
- Count military retirement pay; correct the pension comment.
- Count TANF through the take-up-gated tanf variable instead of ok_tanf.
- Round monthly income half up to the dollar before the gross test and
  the band lookup (OAC 340:20-1-11).
- Date the $240 earned-income deduction from 10/1/2024 and the child-only
  need standard from 1/1/2025, the earliest official editions.
- Follow SNAP's noncitizen rule, as OAC 340:20-1-10(d)(3) directs through
  340:50-5-67, by reusing is_snap_immigration_status_eligible (narrowed by
  P.L. 119-21 from July 2025).
- Require a utility surcharge for heat-in-rent renters and roomers (OAC
  340:20-1-19(d), plan item 2.3), proxied by a positive heating expense.
- Set verified_years to 2025-2027 and shorten the programs.yaml note.
- Add and update 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 (7df6017).
⚠️ Report is 541 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##              main     #9970    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files            4        13     +9     
  Lines           76       220   +144     
  Branches         2         2            
==========================================
+ Hits            76       220   +144     
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 4 commits October 7, 2026 22:56
…miums

Count retirement_distributions; deduct other health premiums and any Part B premium above Social Security for members 60+ or disabled (OAC 340:20-1-11(c)(1)); household size uses adds.

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>
@hua7450
hua7450 marked this pull request as ready for review October 12, 2026 05:54
@DTrim99

DTrim99 commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Add Oklahoma LIHEAP regular heating assistance

PR #9970: Add Oklahoma LIHEAP regular heating assistance (author: hua7450, head 9b6b0dac45)

Scope: the regular payment of Oklahoma Human Services' (OKDHS) LIHEAP Winter Heating Program for federal fiscal years 2025-2027. The PR covers:

  • household size, which counts members who meet SNAP's citizenship and alien rules (OAC 340:20-1-10(d), which points to the SNAP rule 340:50-5-67), with income deemed from ineligible members after their own deductions and an Appendix C-1 Schedule IX need allowance;
  • the gross income test: 130% of the prior year's poverty guideline, with the monthly base and the per-member amount each rounded up to the dollar, against monthly gross income rounded to the nearest dollar;
  • countable income: gross earned and unearned income less the SNAP exclusions, each source floored at zero, Social Security net of the Medicare Part B premium, and take-up-gated TANF;
  • the deductions taken after the gross test: $240 per employed member, medical expenses of members 60 or older or disabled, child support paid, and the child care copay;
  • the Appendix C-7-A winter matrix (four tables by three net-income bands by three household-size groups), and heating responsibility: a bill or reported obligation for direct payers, and a surcharge (a positive bill) for heat-in-rent renters and roomers, subsidized or not.

Cooling, crisis (ECAP), weatherization, equipment and pre-authorization are out of scope. The PR changes 43 files: 16 parameters, 13 variables, 12 test files (68 cases), programs.yaml and a changelog fragment. The matrix, band and size-group parameters are dated 2021-10-01 (the only C-7-A edition), the limit parameters 2025-10-01, the income lists and the student and medical ages 2025-09-15, the $240 deduction 2024-10-01 and the children-only need standard 2025-01-01. The adult need standard reuses the existing Oklahoma TANF Schedule IX-A parameter. The tests use periods 2025-2027, and the registry lists Oklahoma partial with verified_years: "2025-2027".

Overall: the matrix, the income limits, the deeming standards and the deduction amounts are right where the sources print them.

  • All 36 C-7-A cells match the edition OKDHS still serves (dated 10/1/2021, file dated June 17, 2026) and the FY2026 Clearinghouse matrix. Table headings, band starts, size groups and the roomer zeros are encoded as printed. Every plan from FY2023 to FY2027 gives the same $40 minimum and $500 maximum.
  • 26 of the 27 printed limit figures for FY2025-FY2027 were checked against OKDHS documents and all reproduce. The 27th, FY2025's $583 per member, follows the rule but rests only on the PR's archived copy. Schedule IX-A and IX-B and the $240 deduction match Appendices C-1 and C-7, and the limit is above 110% of poverty at every size in every year.
  • The income structure follows OAC 340:20-1-11: the gross test comes before the deductions, deeming follows steps (a)(4)(A)-(E), SNAP exclusions apply (student earnings, housing subsidies and SNAP itself), losses are floored per source, and amounts are rounded to the nearest dollar. The heat-in-rent surcharge follows 340:20-1-19(d) and 340:20-1-13(2)(B)-(C).
  • The tests are strong. Every branch has a test that would fail if it broke, apart from one income-source entry (S6), and both control mutations fail as expected.

There are no critical findings. The six 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, so main's guard fails on the merged tree. Oklahoma's unemployment insurance (ok_ui) is modeled on main, so modeled UI drops out of LIHEAP income. Reproduced: one household gets $365 instead of $235, and another $235 instead of $0.
  • S2: Social Security counts net of the Part B premium in the gross income test. The OAC and OKDHS's staff guide count all gross income and allow the premium only as a medical deduction after the test. The PR follows plan item 1.9 and calls the OAC "silent", although its own rule is to follow the OAC where the two differ. The PR body's headline retiree gets $235 at head and $0 under the OAC.
  • S3: the medical deduction misses payroll (pretax) premiums, which main's Document disjoint health premium inputs and correct consumer treatment #10046 now keeps in a separate input. It also reads is_disabled instead of the 7 CFR 271.2 definition that the rule incorporates (is_usda_disabled). Reproduced: a band change, an eligibility flip through deeming, and an SSDI recipient paid $235 instead of $265.
  • S4: eight of the 16 parameter descriptions use verbs outside the house template, and three misdescribe what the parameter covers.
  • S5: two missing page lists and one missing #page=1. The four limit parameters are also dated 2025-10-01 and cite only FY2026-FY2027 sources, although the registry claims FY2025.
  • S6: farm_operations_income is never positive in any test; removing it from the earned list passes every case.

All 68 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 and S3. Values that a proposed fix or another reading would produce are hand computations and are labelled as such. The S6 claim and the control mutations come from mutating the code and rerunning the PR's tests.

Path prefixes used below:

  • P/ = policyengine_us/parameters/gov/states/ok/dhs/liheap/
  • V/ = policyengine_us/variables/gov/states/ok/dhs/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/
  • R = Oklahoma Register Vol. 42 No. 20 (July 1, 2025; 1,508 pp; PDF page = printed page − 878)
  • Q = Quest, the OKDHS staff policy guide for LIHEAP workers

Line numbers refer to head 9b6b0dac45.

Source Documents

# Document Link Use
1 OAC Title 340, current official text (HTML; LIHEAP sections as amended effective 9-15-26 by 43 Ok Reg No. 23) Title 340 340:20-1-10 (program factors), -11 (income), -13(2) (surcharge verification), -14(2) (supplements), -19 (winter heating); 340:50-5-4 (elderly or disabled, 7 CFR 271.2), -5-67 (alien status), -7-22 (exclusions: "No other income is excluded"), -7-29 (inclusions), -7-31 (medical expenses)
2 R: OAR Docket #25-364, permanent adoption effective September 15, 2025 R, p. 576 Gist "adjust the LIHEAP income determination in light of federal feedback" (p573); 340:20-1-10 (p574-576); 340:20-1-11 (p576-581), with the struck 38-item exclusion list (p578-580) and (c) unchanged except "may" (p580-581). Read from rendered pages, because the text layer merges struck and inserted words
3 FY2026 Oklahoma LIHEAP State Plan (50 pp, Revision #1, "Submission Accepted by CO") p. 6 1.1 heating 12/16/2025-12/26/2025 (p4); 1.4 No, 1.8 Gross Income (p5); 1.9 with "Excluding MediCare deduction" and Cash gifts checked (p6); narrative "OKDHS uses gross income ..." (p7); 2.1 130%, 2.3 (p9); 2.6 $40 / $500 (p10); "Oklahoma does not use resources" (p14). The text layer lacks the checkbox states, so the rendered pages were read
4 FY2025 plan (51 pp, Revision #2, accepted) and the FY2027 plan OKDHS posted (50 pp, a draft edited from the FY2026 form) FY2025, p. 6, FY2027, p. 6 Heating 12/17/2024-02/28/2025 and 01/12/2027-01/20/2027 (p4); the same 1.9 boxes (p6, rendered); 2.1 130% (p9); 2.6 $40 / $500 (p10)
5 FY2023 and FY2024 plans FY2023, p. 8, FY2024, p. 8 Backdating check: 2.1 130% (p8); 2.6 $40 / $500 (p9)
6 Appendix C-7 (1 p each): 10/1/2026 edition; 10/1/2025 edition; 10/1/2024 edition 10/1/2026, 10/1/2025 capture, 10/1/2024 capture "Allowable monthly gross income must be equal to or less than the following income standards that are 130 percent of federal poverty level"; sizes 1-8, the per-member amount and the $240 deduction. The 10/1/2024 capture refused automated requests (HTTP 429), so FY2025 was checked against item 9
7 Appendix C-7-A (2 pp, footer "10/1/2021", file dated June 17, 2026) and the FY2026 Clearinghouse matrix C-7-A, p. 1, OK_BenefitMatrix_2026.docx The four winter tables; the same 36 cells in both
8 Appendix C-1, 7/1/2026 edition (8 pp) C-1, p. 4 Schedule IX-A need standards (p4), IX-B (p5)
9 OKDHS enrollment notices, December 17, 2024 and January 6, 2026 Dec. 17, 2024, Jan. 6, 2026 Winter heating opened on those dates; FY2025 limits $1,632 ... $5,712 (not cited in the PR) and FY2026 limits $1,696 ... $5,867
10 Q: "LIHEAP / ECAP: Eligibility – Income" and "Energy Assistance Income Exclusions" (both updated August 12, 2026), "Eligibility – Household Composition & Other Factors" (December 27, 2024) Income, Exclusions, Household Not cited in the PR. Staff procedure for the gross test, deductions, exclusions, open-case gross income, deeming and resources ("Effective October 1, 2024, the Energy Assistance program does not consider resources")
11 HHS LIHEAP Model Plan Reference Guide (FY25) Reference Guide Lists "SSA benefits (including or excluding Medicare deduction)" without defining the boxes (S2)
12 42 USC 8624(b)(2)(B) LII The 110%-of-poverty floor

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 and modeled Oklahoma UI drops out

  • Where: P/income/sources/unearned.yaml:14 (- unemployment_compensation).

  • What changed on main: Integrate modeled state unemployment insurance into income flows #9558 (merged 2026-10-13, the day 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 and added policyengine_us/tests/code_health/test_unemployment_compensation_readers.py, which fails on any raw list entry. Main's gov.states.household.modeled_state_unemployment_compensation lists ok_ui from 2022.

  • 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/ok/dhs/liheap/income/sources/unearned.yaml:14. The file's other three tests pass, and the PR's 68 cases still pass on that tree.

  • Source: OAC 340:20-1-11(a) counts "All gross earned and unearned income the household receives", OAC 340:50-7-29(c)(3) makes "unemployment compensation payments" countable unearned income, and plan item 1.9, p. 6 checks "Unemployment insurance". None separates reported from modeled amounts.

  • Impact on the merged tree, period 2026 (reproduced): one adult with gas heat, ok_ui of $6,000 and no reported UI. The right-hand column was reproduced with the same $6,000 reported as unemployment_compensation, which gives the same total.

    Wages Merged tree as is With total_unemployment_compensation
    $6,000 countable $6,000, net $260 a month, band 1, $365 countable $12,000, net $760 a month, band 3, $235
    $18,000 countable $18,000 ($1,500 ≤ $1,696), $235 countable $24,000 ($2,000 > $1,696), $0
  • Why should, not critical: the head is correct against its base and CI is green. The conflict comes from a main commit merged after the last push, and git merge-tree shows a clean textual merge, but this has to change before merge (as Add Alabama LIHEAP regular heating assistance #9967 S1, Add Rhode Island LIHEAP regular heating assistance #9972 S1, Add Georgia LIHEAP regular heating assistance #9968 S1, Add Ohio HEAP regular heating assistance #9975 S1 and Add South Dakota LIEAP regular heating assistance #9974 S1). Unlike Ohio and South Dakota, Oklahoma UI is modeled, so values change, as in Alabama (Add Alabama LIHEAP regular heating assistance #9967 S1).

  • Fix: replace the entry with total_unemployment_compensation, add a modeled-ok_ui case like main's New Jersey regression case (nj_liheap_countable_income_person.yaml Case 7), and update rulespec-us#1535's countable-income output.

S2. Social Security counts net of the Part B premium in the gross income test, but the OAC counts gross income and allows the premium only as a deduction after the test

  • Where:
    • V/income/ok_liheap_countable_income.py:30-37 counts max_(social_security - medicare_part_b_premium, 0). Its comment says the OAC "is silent on premium withholding".
    • V/income/ok_liheap_income_deductions.py:30-35 deducts only the part of the premium that Social Security does not cover.
    • Pinned by T/ok_liheap.yaml Case 7 (line 256) and T/income/ok_liheap_countable_income.yaml Cases 2 (line 55) and 4 (line 126).
  • What the rule says (OAC Title 340):
    • 340:20-1-11(a): "All gross earned and unearned income the household receives, except for income exclusions per (b) of this Section, determines a household's financial eligibility".
    • (b) excludes only what SNAP (or TANF, SSP, ABD Medicaid or Child Care Subsidy) excludes. The SNAP list, 340:50-7-22, ends "No other income is excluded", and nothing in it excludes a Medicare premium.
    • (c): "The household must meet the gross income standard for its household size, per OKDHS Appendix C-7 before allowing applicable income deductions". The first deduction is "(1) verified non-reimbursed medical expenses paid by persons 60 years of age and older or persons considered disabled".
    • SNAP's medical-expense list, which the PR itself uses, includes "(vi) Medicare premiums" (340:50-7-31(a)(3)(A)). So the premium is an expense deducted after the test, not an exclusion from gross income.
    • (a)(1)(B): when every member is on SNAP, TANF, SSP, ABD Medicaid or Child Care Subsidy, "eligibility staff uses the gross income used to establish eligibility for the other program". SNAP's gross income counts Social Security before the premium.
  • What OKDHS tells its workers: Q, "Eligibility – Income" (updated August 12, 2026).
    • "Except for excluded income and the self-employed business expense, EA staff uses all other income the household receives to determine income eligibility."
    • "The household has to meet the gross income standard prior to receiving any income deductions."
    • "unreimbursed medical expenses for household members 60 years of age or older or with a disability" is listed among the deductions.
    • Q, "Energy Assistance Income Exclusions" has staff take "The gross unearned income" from an open benefit case.
  • The plan's own narrative agrees (p. 7): "OKDHS uses gross income to determine LIHEAP eligibility. Households must meet gross income eligibility standard first, and then countable net income is used to determine the benefit amount".
  • Against: plan item 1.9 checks "Excluding MediCare deduction" in the FY2025, FY2026 and FY2027 plans (p6, rendered). The batch reads that box as net, and HHS's Model Plan Reference Guide does not define it.
  • The PR body states its own rule: "Where the FY2026 plan and the OAC differ, the model follows the OAC; where the OAC is silent, it follows the plan". It applies that rule to child earnings, following 340:50-7-22(9) over the plan's unchecked "Earned income of a child under the age of 18" box. For Social Security it treats the OAC as silent, but (a), (b) and (c) together do address the premium: it counts in gross income and is deducted afterwards.
  • Impact:
    • Reproduced at head: the PR body's headline example (T/ok_liheap.yaml Case 7). In period 2026, a 70-year-old with $21,360 of Social Security and a $2,434.80 premium has countable income of $18,925.20, or $1,577 a month, within $1,696, and gets $235.
    • Under the OAC (hand-computed): gross income is $1,780 a month, above $1,696, so $0.
    • The reach is every Part B enrollee whose gross income falls between the limit and the limit plus the premium ($202.90 a month in 2026, about 12% of the one-person limit).
    • The payment band does not change for members 60 or older or disabled, because the PR already deducts any premium it does not net. Deeming does not change either, since (a)(4)(D) subtracts the same deduction. Only the eligible members' gross test changes.
  • Why should, not critical: the accepted plans check the box the PR follows, so its result has official support, and the PR documents the conflict (PR body; rulespec-us#1535 interpretation 1). Wave 1 rated a Social Security gross-versus-net error SHOULD even where the state's handbook and plan agreed (Add New Jersey LIHEAP regular heating assistance #9745 S1). Here the OAC, the staff guide and the plan narrative point to gross, and the PR mislabels the OAC as silent.
  • Fix:
    • Follow the OAC. Count social_security gross: add it to P/income/sources/unearned.yaml and drop the netting. Under (c)(1), deduct the whole medicare_part_b_premium for members 60 or older or disabled: replace unnetted_part_b_premium with the premium.
    • Then T/ok_liheap.yaml Case 7's first household gets $0, countable-income Case 2 counts $13,200 and Case 4 $15,600. Case 12 is unchanged at $265 (hand-computed).
    • Correct the PR body's headline example, its conflict table and Make a pa_income_tax_forgiveness variable #1535 interpretation 1.
    • If OKDHS confirms that its workers net the premium before the gross test, keep the netting instead, but replace "silent" with the actual conflict and cite the confirmation.

S3. The medical deduction misses payroll (pretax) premiums after main's #10046, and reads is_disabled instead of the definition the rule incorporates

  • Where: V/income/ok_liheap_income_deductions.py:26-28 (medical_eligible = age >= 60 | is_disabled) and :36-40. The premium inputs read are health_insurance_premiums_without_medicare_part_b, other_medical_expenses and medicare_part_b_premium; pre_tax_health_insurance_premiums is never read.
  • Source: OAC 340:20-1-11(c)(1) deducts "verified non-reimbursed medical expenses paid by persons 60 years of age and older or persons considered disabled, per OAC 340:50-5-4". The PR reads the expenses with SNAP's list, "(v) health, dental, and hospitalization policy premiums" (340:50-7-31(a)(3)(A)). Wages count gross (340:20-1-11(a)), so a premium withheld from pay is paid by the person.
  • Part 1, payroll premiums:
    • What changed on main: Document disjoint health premium inputs and correct consumer treatment #10046 (merged 2026-10-14) documents that "Pretax payroll payments belong only in pre_tax_health_insurance_premiums. The pretax and non-pretax sets are disjoint". Main's SNAP allowable medical expenses now include pre_tax_health_insurance_premiums (snap_allowable_medical_expenses.py:32).
    • Reproduced on the merged tree, period 2026, gas heat:
      • A 62-year-old with $12,000 of wages and a $1,200 payroll premium in the pretax input has deductions of $2,880, net income of $760 a month (band 3) and gets $235. With the same premium in the non-pretax input, deductions are $4,080, net income $660 (band 2), and the award $265.
      • Deeming: a citizen aged 40 with $4,500 of wages and an undocumented spouse aged 62 with $24,000 of wages and a $1,200 payroll premium. With the pretax input, the deemed amount is $16,344 and gross income $20,844 ($1,737 a month, above $1,696), so $0. With the non-pretax input, the deemed amount is $15,144 and gross income $19,644 ($1,637 a month), and the household gets $235.
  • Part 2, who counts as disabled:
    • 340:50-5-4 adopts 7 CFR 271.2. A member is disabled if he or she "(2) receives Supplemental Security Income ... or disability or blindness payments under Titles I, II, XIV, or XVI of the Social Security Act", or receives VA total-disability and the other listed benefits.
    • PolicyEngine implements that benefit-receipt test as is_usda_disabled, which SNAP's has_snap_elderly_disabled_member uses. The code comment says is_disabled "approximates the incorporated SNAP disability test".
    • Reproduced at head, period 2026: a 50-year-old with $9,000 of SSDI and $1,200 of medical costs, with is_disabled unset. is_usda_disabled is true, but nothing is deducted: net income is $750 a month and the award $235. With the deduction (reproduced by setting is_disabled), net income is $650 and the award $265.
  • Why should, not critical: the PR follows its base's conventions, and Document disjoint health premium inputs and correct consumer treatment #10046 merged after the last push. 2026 is claimed, though, and both gaps change awards.
  • Fix:
    • Add pre_tax_health_insurance_premiums to the medical expenses, preferably from a parameter list.
    • Use is_usda_disabled for "persons considered disabled". Keeping is_disabled alongside it would stand in for 340:50-5-4's permanent-disability categories, (a)(5) and (a)(9).
    • Add a payroll-premium case and an SSDI case, and update Make a pa_income_tax_forgiveness variable #1535's "Personal deductions" output.

S4. Eight parameter descriptions use verbs outside the house template, and three misdescribe the parameter

All 16 descriptions end with "under the Low Income Home Energy Assistance Program." with nothing after it. The template's verbs are limits, provides, sets, excludes, deducts and uses.

File:line Current Suggested
P/income/deductions/medical_age_threshold.yaml:1 "allows medical expense deductions beginning at this age or for a qualifying disabled member" "Oklahoma limits the medical expense deduction to members this age or older, or disabled, under the ..."
P/income/deeming/child_only_need_standard.yaml:1 "protects this monthly need amount for a represented children-only ineligible group before deeming its income" "Oklahoma deducts this monthly need standard from the income of a children-only group of ineligible members before deeming it under the ..."
P/income/limit/max_table_size.yaml:1 "publishes monthly income limits through this household size before adding a separate additional-person amount" "Oklahoma sets monthly income limits through this household size and adds a per-member amount above it under the ..."
P/income/limit/rounding_increment.yaml:1 "publishes monthly income limits in increments of this amount" "Oklahoma rounds monthly income limits up to this increment under the ..."
P/income/sources/earned.yaml:1 "counts these earned income sources for fully qualified households" "Oklahoma uses these sources as earned income under the ..."
P/income/sources/unearned.yaml:1 "counts these unearned income sources for fully qualified households" "Oklahoma uses these sources as unearned income under the ..."
P/payment/household_size_group.yaml:1 "assigns this payment group based on household size" "Oklahoma uses this household-size group for the regular heating payment under the ..."
P/payment/income_band.yaml:1 "assigns this payment band based on net monthly income" "Oklahoma uses this net monthly income band for the regular heating payment under the ..."

S5. References: two missing page lists, one missing #page=1, and FY2025 limit values dated and cited only from FY2026

File:line Problem Fix
P/income/sources/earned.yaml:18-19 and P/income/sources/unearned.yaml:46-47 "OAC 340:20-1-11(a)-(b)" opens R p576, but (a)(2)-(3) are on p577 and (b) on p578, and the title has no page list End the titles with "#page 576-578", as the variable's # PDF pages 576-578 comment already does
V/ok_liheap.py:14 C-7-A linked without a page; the winter tables are on p1 of 2 Add #page=1, as V/payment/ok_liheap_matrix_amount.py and the matrix parameters do
P/income/limit/fpg_rate.yaml:3, fpg_year_lag.yaml:5, max_table_size.yaml:3, rounding_increment.yaml:6 Dated 2025-10-01, citing only the FY2026 plan, the January 2026 notice and the 10/1/2026 C-7, although the registry claims FY2025 and FY2025 (like FY2023-FY2024) used 130%. The 2025 values come only from backward extrapolation Date them 2024-10-01 and cite FY2025 plan item 2.1, p. 9 and the 10/1/2024 C-7 or the December 17, 2024 notice

Consistency: #9972 S5, #9975 S6 and #9974 S3 rated wrong anchors and missing page lists SHOULD; the brief rates period or instant mistakes with limited reach SHOULD.

S6. One listed income source has no test that would fail if it were dropped

  • P/income/sources/earned.yaml:10 lists farm_operations_income, but its only test value is the -$1,200 loss in T/income/ok_liheap_countable_earned_income.yaml Case 1 (line 19), which floors to $0 whether or not the entry is there.
  • Removing the entry still passes the four files that compute earned income (32 cases). No other case sets farm income. Reproduced at head: a member with $12,000 of farm income counts $12,000 of earned income, so the entry matters.
  • Fix: give an existing case a positive farm_operations_income (for example $1,200 in countable-earned Case 1 alongside the loss case), or add one.
  • Two control mutations confirm the method. Dropping the NONE check from V/eligibility/ok_liheap_eligible.py:53 fails T/eligibility/ok_liheap_eligible.yaml Case 4. Dropping the eligible-member mask on the net-income deductions fails six cases in T/ok_liheap.yaml and T/income/ok_liheap_deemed_income.yaml.
  • By inspection, the rest is pinned:
    • every other listed source (all positive in at least one case), the per-source floors, the Social Security floor and the student exclusion's three conditions;
    • the deeming need switch, the tax-unit representative and TANF take-up;
    • each limit rounding and the size-0 mask;
    • the medical age and disability arms, the copay subsidy condition and the zero floor;
    • every responsibility route, the band and size-group edges, each fuel table, the roomer table, and the size-0 and NONE masks.
  • This is the only gap. Consistency: Add Georgia LIHEAP regular heating assistance #9968 S2 rated untested income sources SHOULD (checklist item 13).

Suggestions

G1. Fuels and routes that are eligible but paid $0, and an unknown-fuel heat-in-rent household that reports a surcharge

  • Reproduced at head (period 2026, no income):
    • SOLAR with an electric bill and OTHER with an other-fuel bill are ok_liheap_eligible: true with ok_liheap: 0. T/payment/ok_liheap_matrix_amount.yaml Case 7 asserts only the matrix amount.
    • UNSPECIFIED fuel with heat in rent and has_heating_expense: true is ineligible, with a matrix amount of $150 and an award of $0.
  • OAC 340:20-1-10(b)(1): "The main energy source may be electricity, natural gas, propane, kerosene, firewood, coal, butane, or heating oil." The PR body agrees that "Solar is not an approved main energy source". Either make SOLAR and OTHER direct payers ineligible so the flag matches the $0, or add a # See #9754 note.
  • The heat-in-rent tables cover "All Energy Sources", and heating_type documents UNSPECIFIED as "the right value when heat is included in rent and the fuel is unknown".
    • has_heating_expense means "Whether the household incurs home heating costs separately from its rent", which is what a verified surcharge shows (340:20-1-13(2)(B): "a rent receipt designating that the fuel cost is separate from the total shelter payment").
    • Accepting the flag for heat-in-rent households would let them be paid without a made-up fuel bill. The PR chose otherwise, and T/eligibility/ok_liheap_eligible.yaml Case 2 and T/ok_liheap.yaml Case 10 pin that choice, so this is optional.
  • Consistency: Add Alabama LIHEAP regular heating assistance #9967 G2, Add Georgia LIHEAP regular heating assistance #9968 G2, Add Ohio HEAP regular heating assistance #9975 G3.

G2. Backfilled years and the 2025 income rule

  • FY2025: OKDHS's December 17, 2024 notice prints all eight limits ($1,632, $2,215, $2,798, $3,380, $3,963, $4,546, $5,129, $5,712), matching the head. It can be fetched, unlike the Wayback captures, so cite it.
  • The rule in force on January 1, 2025 was the pre-September 2025 text: the struck 38-item exclusion list on R pp. 578-580.
    • For every modeled source it gives the same result as the SNAP list carried back. Its item (14) excludes "a minor dependent child's earnings when he or she is a full-time student".
    • Its deductions in (c) were the same: only "may" is struck on p580.
    • So the 2025 carry-back is harmless. Say so in Make a pa_income_tax_forgiveness variable #1535 interpretation 10.
  • Earlier years (unclaimed):
    • The FY2023 and FY2024 plans also set 130% (p8) and $40 / $500 (p9), so the carried-back limit rule and matrix fit.
    • Q says "Effective October 1, 2024, the Energy Assistance program does not consider resources". FY2024 and earlier therefore had the liquid-resource test in the old 340:20-1-11(e), which the backfill omits. Record this in the registry notes or Make a pa_income_tax_forgiveness variable #1535.

G3. Partnership and S-corporation income is counted as earned

  • P/income/sources/earned.yaml:11 lists partnership_s_corp_income as earned income, which gets the $240 deduction.
  • OAC 340:20-1-11(a)(2) defines earned income as income "for which he or she puts forth labor". Oklahoma SNAP treats S-corporation profit shares and the distributions of partners who are not self-employed as unearned (340:50-7-29(b)(2) and (c)(8)).
  • The comment says passive and active income cannot be told apart, which is fair. Moving the source to the unearned list would follow the SNAP classification for the common case, and only the $240 deduction is affected. Optional.

G4. Test and comment hygiene

  • Many comments lost the spaces around their numbers, for example:
    • T/ok_liheap.yaml:2 ("tested in2027", also in six other headers);
    • T/eligibility/ok_liheap_income_limit.yaml:3 ("Jan6,2026 officialannouncement monthly[1696,...], multipliedby12") and line 29 ("Unverified2025 estimate uses2024FPG15060 ...");
    • T/income/ok_liheap_countable_earned_income.yaml:3 ("Register pp576-578 and approved existing-net-input convention:12000+2400+600+0+1200=16200");
    • T/payment/ok_liheap_matrix_amount.yaml:3 ("matchingFY2026matrix literal36cells").
  • Several comments refer to internal decisions: "under contract v1.3" (seven file headers), "approved existing-net-input convention" and "the contracted schedule-classification approximation" (deeming Case 7). See Add Rhode Island LIHEAP regular heating assistance #9972 G7 and Add Ohio HEAP regular heating assistance #9975 G6.
  • T/eligibility/ok_liheap_income_limit.yaml:29 calls 2025 an "Unverified2025 estimate" that "Does not verify historical fullprogram", while the registry claims 2025.
  • is_full_time_student is set in T/income/ok_liheap_countable_earned_income.yaml Cases 3-7, but no Oklahoma variable reads it; the rule reads is_in_k12_school.
  • The isolated limit and matrix tests set heating inputs that those variables never read.

G5. PR body and issue housekeeping

  • "The tests were not run locally; CI validates them": all 68 pass locally at this head and on the merged tree (policyengine-core 3.32.29).
  • "replaced an itemized list of income types": the struck list was of income exclusions (R pp. 578-580).
  • The OAC was amended again effective 9-15-26 (43 Ok Reg No. 23), and Make a pa_income_tax_forgiveness variable #1535 says that filing "was not read".
    • The current text keeps every modeled rule, drops the liquid-resource subsection (340:20-1-11(e)), and puts surcharge verification for subsidized and unsubsidized heat-in-rent households in 340:20-1-13(2)(B)-(C).
    • Mention it for FY2027, and add 340:20-1-13(2) to the heat-in-rent row of the conflict table.
  • The make format box is unchecked, although CI lint passed.
  • rulespec-us#1535 still calls the PR "open as a draft" (it is not a draft) and says the tests were "not run locally".

G6. References polish

  • The undated C-7 and C-1 links will resolve to whatever edition OKDHS posts next. That affects P/income/deductions/earned_income.yaml:29-30 (titled "10/1/2026 edition"), the four limit parameters and V/eligibility/ok_liheap_income_limit.py:14. Prefer dated captures or the enrollment notices.
  • V/income/ok_liheap_income_deductions.py:14-15 relies on OAC 340:50-7-31(a)(3)(A)(v)-(vi) and 340:50-5-4, but links only Title 340 and C-7. Naming the sections in the reference comment would help. The LII copy of 340:50-7-22 could point to the official Title 340 file instead.

Verified correct

  • Matrix (C-7-A, p. 1; FY2026 Clearinghouse matrix):

    • All 36 cells.
    • Headings map natural gas, electricity, wood and coal to the first table, and LP gas, kerosene and heating oil to the second. The renter and roomer tables apply when "Heating Cost is Included in Rent" for "All Energy Sources".
    • Rows "$0 - $400", "$401 - $700" and "$701 - ineligible"; columns 1-3, 4-6 and 7+; roomer $0 for four or more.
    • Plan item 2.6 gives $40 / $500 in every plan from FY2023 to FY2027 (p9-10). There is no bill cap ("estimated benefit amounts"; one payment per year).
  • Limits:

    • 130% of the prior year's guideline (C-7: "equal to or less than ... 130 percent"; plan 2.1).
    • Rounding the monthly base and the per-member amount up separately reproduces every figure: FY2025 $1,632 ... $5,712 (December 17, 2024 notice); FY2026 $1,696 ... $5,867 and $596 (C-7 10/1/2025 and the January 6, 2026 notice); FY2027 $1,729 ... $6,037 and $616 (C-7 10/1/2026).
    • The exact-dollar cases (1.3 × 15,960 / 12 = 1,729.00; 1.3 × 31,200 / 12 = 3,380.00) do not round up.
    • Monthly gross income is rounded to the nearest dollar, and the limit is inclusive.
  • Federal floor (42 USC 8624(b)(2)(B)). FY2026 monthly limit against 110% of the higher (2026) guideline, by household size:

    Size 1 2 3 4 5 6 7 8 Each additional
    Limit $1,696 $2,292 $2,888 $3,483 $4,079 $4,675 $5,271 $5,867 $596
    110% $1,463.00 $1,983.67 $2,504.33 $3,025.00 $3,545.67 $4,066.33 $4,587.00 $5,107.67 $520.67
    • FY2025's limits clear 110% of the 2025 guideline ($1,434.58 to $4,963.75, plus $504.17 per member). FY2027's clear 110% of the 2026 guideline; the 2027 guideline would have to rise 18% to bind (1.3 / 1.1).
    • The per-member amount exceeds 110% of the guideline increment, so the margin grows with size.
  • Timing: winter enrollment opened December 17, 2024 (FY2025), January 6, 2026 (FY2026) and is planned for January 12-20, 2027 (FY2027 plan p4). Period N reads FY N on January 1, so each season falls in the year the PR maps.

  • Income (OAC 340:20-1-11; R pp. 576-581; Q):

    • Gross earned and unearned income, with the SNAP exclusions: student earnings under 340:50-7-22(9), exempt "unless not attending school or dependent" (Q); housing subsidies; SNAP.
    • Each listed source maps to an OAC category or a checked 1.9 box, including Cash gifts (financial_assistance), retirement distributions and military retirement pay. TANF counts once, through the take-up-gated tanf.
    • Losses are floored per source, and net business inputs stand in for the documented 50% self-employment rule ((c)(4)).
    • No Oklahoma state supplement is modeled on main or at head, as the PR says.
  • Deeming ((a)(4)(A)-(E)): the earned deduction, the other (c) deductions and Schedule IX are subtracted before the gross test. IX-A matches the TANF need-standard parameter ($398 ... $1,436), and IX-B matches C-1 7/1/2026 p5 ($193 ... $1,333). The PR subtracts the earned deduction once, a reasonable reading of (A) and (D).

  • Deductions after the gross test ((c)): $240 per employed member, capped at earnings (C-7, all three editions; Q "currently, $240"); child support paid; the copay only with a subsidy; medical expenses for members 60 or older (plus S3).

  • Household and eligibility:

    • Size excludes ineligible aliens ((h)(3)); a unit with no eligible member is ineligible.
    • SNAP alien eligibility under 340:50-5-67(a), with P.L. 119-21 from July 2025. January reads keep FY2025 on the earlier list.
    • No categorical eligibility (plan 1.4 No) and no asset test (plan p14; Q).
    • Heat-in-rent renters and roomers need a verified surcharge (340:20-1-19(d)(1)-(2); 340:20-1-13(2)(B)-(C); plan 2.3). Subsidized households with out-of-pocket costs get the same benefit (340:20-1-10(g)(3)). NONE is ineligible.
  • Code patterns:

    • No hard-coded policy values. defined_for = StateCode.OK is on all 13 variables, all 16 parameters are read, and the formulas are vectorized. The shared fpg() helper and the TANF need standard are reused.
    • Matrix keys come from bracket lookups that always return 1-3, so non-residents cannot hit a missing key. Tests that mix TX and OK rows (eligibility Case 4, ok_liheap Case 6, matrix Case 6) pass.
  • Tests:

    • 68 of 68 pass locally at head (policyengine-core 3.32.29) and on the merged tree. Periods are plain (2025-2027), and every case sets heating_type.
    • Hand-checked against C-7, C-7-A, C-1 and the OAC:
      • limit Cases 1-3 (all 21 values);
      • T/ok_liheap.yaml Cases 1, 2, 4, 5, 9 and 11;
      • matrix Cases 1-3;
      • deemed-income Cases 2, 3, 5 and 8;
      • net-income Case 4.
  • Changelog: changelog.d/ok-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 following and verified every encoded cell, limit, standard, deduction and branch:
    • the FY2023-FY2027 plans (rendered checkboxes for FY2025-FY2027), OAC chapter 340:20 and the incorporated 340:50 sections in the current text;
    • the 2025 adoption in R (rendered strikethrough), C-7 (10/1/2025 and 10/1/2026), C-7-A, C-1 Schedule IX, OKDHS's two enrollment notices and the Quest staff pages.
  2. Income definition: pass on sources, exclusions, loss floors, rounding and deeming. Social Security counts net of Part B in the gross test against the OAC and staff guidance (S2). The medical deduction misses payroll premiums and reads is_disabled (S3), and UI needs the total after rebase (S1).
  3. Backdating: FY2025-FY2027 are represented and correct, apart from S2 and S3.
    • The 2025 values come from parameters dated 2025-10-01 and 2025-09-15 (S5), and the pre-September 2025 rule gives the same results for modeled sources (G2).
    • Unclaimed earlier years: the FY2023-FY2024 plans confirm 130% and $40-$500, but the backfill omits the resource test that applied before October 1, 2024 (G2).
    • The published FY2027 C-7 is used.
  4. Household and arrangement rules: pass. Subsidized and public housing, heat in rent with the surcharge, renters and roomers, no categorical eligibility and the $40 / $500 range are all handled. Priority affects enrollment only, so no supplement is due. Two fuels are eligible but paid $0 (G1).
  5. Tests: 68 cases, more than 8 hand-checked.
    • Covered: FY2026 sizes 1-8, FY2027 sizes 1-10 and FY2025 sizes 1, 8 and 9; the limit edge at ±50 cents; the band edges; the 3/4/6/7 size edges; the age-60 and age-18 boundaries; plain periods.
    • Gap: one source (S6).
  6. Parameter descriptions: eight are off-template and three misdescribe the parameter (S4). None has a trailing clause.
  7. References: two missing page lists, a missing #page=1, and FY2025 values cited only from FY2026 (S5). Polish is in G6.
  8. Wiring: pass.
    • The programs.yaml entry and coverage line are well formed, and the registry test passes on the merged tree. There is no aggregate wiring, which matches OR, NY, NJ and MD on main (none feeds household_state_benefits).
    • defined_for gating is on every variable, and the state-gating check passes on the merged tree. Take-up applies only through tanf, as in the siblings.
  9. Axiom: valid queued line. rulespec-us#1535 is open, labelled pe-parity, dispatch-ready and current to 9b6b0dac45. It needs updates for S1-S3 and S6 (see below).
  10. Branch and CI: all checks are green at head. The branch is 8 ahead and 82 behind main. There are no textual conflicts, but main's UI guard fails on the merged tree (S1), and Document disjoint health premium inputs and correct consumer treatment #10046 changes the premium inputs (S3).
  11. Integrate modeled state unemployment insurance into income flows #9558: S1. Oklahoma UI (ok_ui) is modeled from 2022, so values change on the merged tree (reproduced).
  12. IIJA and FY2027: no IIJA supplement in any FY2023-FY2027 plan or in the OAC.
    • 340:20-1-14(2) allows discretionary "supplements" from unencumbered funds to SSP, TANF and SNAP recipients; they are not IIJA-specific and are reasonably out of scope.
    • FY2027: the 10/1/2026 C-7 is encoded, C-7-A is unchanged, the FY2027 plan keeps 130% and $40 / $500, and the 9-15-26 OAC amendment leaves the modeled rules unchanged (G5).
  13. Mutation check: S6. Both control mutations fail as expected.
  14. Health premiums after Document disjoint health premium inputs and correct consumer treatment #10046: S3. Reproduced on the merged tree: a band change and an eligibility flip through deeming.
  15. State-gated index defaults: pass. ok_liheap_household_size (int) feeds bracket lookups (max_(size, 1)), the matrix keys are always 1-3, and ok_liheap_dwelling_type (enum) is used only in where. The mixed TX and OK test rows run in one simulation without error.

CI status

28 of 28 checks pass at 9b6b0dac45 (gh pr checks 9970, 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#1535 queued: valid format, and the issue meets the bar.

  • rulespec-us#1535 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:
    • proposed us-ok/ module paths with corpus status;
    • verbatim OAC, Register, plan, C-7, C-7-A, C-1 and federal text;
    • required outputs for all 13 variables;
    • 16 companion tests hand-derived from the sources ("None is taken from policyengine-us output").
  • It describes head 9b6b0dac45 correctly, including the Medicare reading and the one not followed (interpretation 1), the heat-in-rent surcharge, the deeming details and the 2025 carry-back (interpretation 10).
  • Updates needed when the fixes land:
    • total_unemployment_compensation in the countable-income output (S1);
    • the Social Security reading, companion tests C15-C16 and ok_liheap.yaml Case 7 (S2);
    • payroll premiums and is_usda_disabled in the personal-deductions output (S3), and the farm case (S6);
    • the 9-15-26 amendment it says was not read, and the stale "open as a draft" and "not run locally".

Next steps

  1. S1: rebase onto main, switch P/income/sources/unearned.yaml:14 to total_unemployment_compensation, and add a modeled-ok_ui case.
  2. S2: count Social Security gross in the gross test and deduct the whole Part B premium under (c)(1). Or, if OKDHS confirms that its workers net the premium, keep the netting and correct the conflict table.
  3. S3: deduct pre_tax_health_insurance_premiums, use is_usda_disabled for "persons considered disabled", and add a case for each.
  4. S4-S6: align the eight descriptions, fix the references and the limit-parameter dates, and give farm_operations_income a positive test value.
  5. Optionally address G1-G6, then refresh the PR body and rulespec-us#1535 and re-request review.

0 critical and 6 should-address findings, plus 6 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 6 should items; details in the full report above. Verified: all 36 Appendix C-7-A cells, the $40–$500 range, 26 of the 27 printed FY2025–FY2027 limits, the deductions, the deeming steps, the heat-in-rent surcharge, and the 110% floor at every size. All 68 tests pass and CI is green. (1) Merge blocker from main's #9558: unearned.yaml:14 reads the raw unemployment_compensation, so modeled ok_ui drops out on the merged tree. (2) Social Security is counted net of Part B in the gross test. OAC 340:20-1-11(a)–(c), the OKDHS staff guide and the plan narrative count gross income and deduct the premium after the test. Plan box 1.9 supports the PR's reading, but the regulation governs, and the PR calls the OAC "silent". Headline retiree: $235 at head, $0 under the OAC. (3) The medical deduction misses pre_tax_health_insurance_premiums (separate on main since #10046), and it uses is_disabled instead of the 7 CFR 271.2 test (is_usda_disabled). (4) Eight parameter descriptions are off the house template or misdescribe their parameters. (5) References: missing page lists and anchors, and the limit parameters are dated 2025-10-01 although FY2025 is claimed. (6) farm_operations_income is never positive in any test.

hua7450 and others added 2 commits October 15, 2026 15:13
- S1: Merge blocker from #9558: the unearned list reads the raw unemployment_compensation, so modeled ok_ui drops ou
- S2: Social Security counts net of Part B in the gross test; the OAC counts gross income and deducts the premium af
- S3: The medical deduction misses pretax payroll premiums (#10046) and reads is_disabled instead of the 7 CFR 271.2
- S4: Eight parameter descriptions are off the house template, and the student parameter misdescribes its scope
- S5: References: two missing page lists, a missing #page=1, and FY2025 limits dated and cited only from FY2026
- S6: farm_operations_income has no test that would fail if it were dropped

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 f0e2f40.

The branch also merges upstream/main (PRs 9558 and 10046). Your floor check shows Oklahoma's limit above 110% of the poverty guideline at every size in FY2025-FY2027, so this PR does not add the shared gov.hhs.liheap.fpg_floor parameter (42 U.S.C. 8624(b)(2)(B)).

  • S1: unearned.yaml now lists total_unemployment_compensation, so modeled ok_ui counts when no amount is reported. New countable-income Case 5 covers this. Its wage inputs give a $432 weekly benefit (DOL's Oklahoma average is $432.08). Fifteen weeks come to $6,480 of ok_ui, or $540 a month, which falls in band 2 and pays $265 ($365 without UI).

  • S2: Done as you proposed. social_security is now a gross unearned source, the netting is gone, and members 60 or older or disabled deduct the whole Part B premium after the gross test. The unearned.yaml comment and the PR body's conflict table set OAC 340:20-1-11(a) and (c), 340:50-7-31(a)(3)(A)(vi) and the plan narrative (page 7) against the plan item 1.9 box. Updated cases:

    • ok_liheap.yaml Case 7 now pays $0 to both retirees.
    • Case 12 counts $12,000 and deducts $4,234.80, for $265.
    • Countable-income Cases 2 and 4 count $13,200 and $15,600, matching your hand values.
    • The PR body's headline example now uses Case 12.
  • S3: The medical deduction now reads is_usda_disabled and snap_allowable_medical_expenses. That SNAP aggregate already sums, per person, the non-pretax premiums (with Part B for Medicare enrollees), pre_tax_health_insurance_premiums and other_medical_expenses. This is the modeled part of the 340:50-7-31(a)(3)(A) list, so I reused it in place of a new parameter list and left out SNAP's $35 threshold; PA CCW sums the same three inputs.

    • I did not keep is_disabled alongside it. 340:50-5-4(a)(5) and (a)(9) also require a government disability retirement or VA survivor benefit, which the flag does not show. NY HEAP, NC LIEAP and SNAP use is_usda_disabled alone. The PR body lists the categories that have no inputs.
    • New deductions Case 3 covers payroll and after-tax premiums: $4,320 each at age 62 ($265), and only the $2,880 earned allowance at age 40 ($235).
    • New ok_liheap.yaml Case 13 gives an SSDI recipient at the 2026 average of $1,630 a month the $1,200 medical deduction ($235). A member flagged disabled with no qualifying benefit gets no medical deduction.
    • Deductions Case 1 now sets is_usda_disabled. Net-income Case 4 now reports its 39-year-old's $6,000 as social_security_disability, so the $1,200 medical deduction still applies and net income stays $23,520.
  • S4: All eight descriptions now use your suggested wording, and the student parameter says "elementary or high school students".

  • S5:

    • The earned and unearned titles end with #page 576-578, and the ok_liheap C-7-A link opens #page=1.
    • The four limit parameters are dated 2024-10-01 and all cite the December 17, 2024 notice. fpg_rate and fpg_year_lag also cite FY2025 plan item 2.1 (page 9), and max_table_size and rounding_increment the 10/1/2024 C-7 capture.
    • No values change.
  • S6: Countable-earned Case 8 adds $1,200 of net farm income to $12,000 of wages, for $13,200.

  • G1: Comment only, under the settled heating_type decision. Directly billed OTHER and SOLAR stay eligible with a $0 matrix amount as a documented coverage limit. With heat in rent, UNSPECIFIED carries no surcharge bill, so it pays $0; the default is tracked in Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754. ok_liheap_eligible.py now records both and cites 340:20-1-13(2)(B)-(C) for surcharge verification.

  • G2: Partly done. FY2025 now cites plan item 2.1 and the December 17, 2024 notice (S5). The PR body and the rulespec-us issue note that the pre-September 2025 exclusion list gives the same result for every modeled source. History is out of scope for this PR, so FY2023-FY2024 stay unclaimed, and the resource test that applied before October 1, 2024 is recorded only in the rulespec-us issue.

  • G3: Kept as earned income. The earned.yaml comment and a new not-modeled row give the reasons. The input mixes active partners' earnings with S corporation and passive shares. The KS, KY, OR and NY lists on main count it as earned, and only the $240 deduction differs.

  • G4: Done.

    • Comments are re-spaced and no longer use the internal "contract" wording.
    • The 2025 limit case now describes FY2025.
    • The unread is_full_time_student and bill inputs are removed from the earned-income, limit and matrix cases.
    • heating_type stays in every case under the LIHEAP test convention.
    • No expected value changed.
  • G5: Done in the PR body:

    • the struck list is now described as income exclusions (Register pages 578-580);
    • the September 15, 2026 amendment is noted for FY2027;
    • 340:20-1-13(2)(B)-(C) is added to the heat-in-rent rows;
    • make format is checked.

    The rulespec-us issue no longer calls the PR a draft. The body still says the tests were not run locally because we leave test runs to CI. Thanks for running all 68 at 9b6b0da.

  • G6: Partly done.

    • The LII links now point to the official Title 340 file.
    • earned_income.yaml adds the dated 10/1/2025 C-7 capture.
    • ok_liheap_income_limit adds the December 2024 notice.
    • The deduction variable names 340:50-5-4 and 340:50-7-31(a)(3)(A)(v)-(vi).
    • The 10/1/2026 C-7 keeps its live link, titled by edition. No dated capture of that edition was available because the Wayback index was offline on 2026-10-15.
  • LIHEAP wave 2a: encode Oklahoma LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1535 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 six round-1 should-address items are resolved, the gross Social Security treatment follows OAC 340:20-1-11, the FY2025 limits now trace to the 10/1/2024 C-7, and CI is green. The suggestions below are optional; G7 (a comment on why the FY2025-FY2026 resource rule is not modeled) is the most useful one.

Program Review

IDs: S = should address, G = suggestion. S1-S6 and G1-G6 carry over from the round-1 review (DTrim99, 9b6b0dac45). G7-G19 are new in this round.

Prefixes: P/ = policyengine_us/parameters/gov/states/ok/dhs/liheap/, V/ = policyengine_us/variables/gov/states/ok/dhs/liheap/, T/ = policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/. Line numbers refer to f0e2f4033e.

Source Documents

Branch Status

  • 10 commits ahead of main and 38 behind (merge base 9560e7f183). The branch merges cleanly with main.
  • The staleness did not affect any finding. Informational only.

Critical (Must Fix)

None.

Investigated and cleared:

  • Social Security counted gross against plan item 1.9. P/income/sources/unearned.yaml:17-23 counts social_security gross and deducts Part B after the gross test. The FY2025-FY2027 plans check "Excluding MediCare deduction" (FY2025 p. 6). Under that box, a 70-year-old with $21,360 of Social Security and a $2,434.80 premium gets $235 in 2026; under the code, $0.
    • Cleared by code-path verification. OAC 340:20-1-11(a) ("All gross earned and unearned income") and (c) (the gross standard comes "before allowing applicable income deductions") govern. The same plan checks "Gross Income" (item 1.8) and says "OKDHS uses gross income" (p. 7). The PR documents the conflict.
    • It would reverse on a written OKDHS statement (Quest or a policy memo) that workers net Part B before the gross test.

Should Address

None.

Suggestions

  • G7. No comment records why the FY2025-FY2026 liquid-resource rule is not modeled. V/eligibility/ok_liheap_eligible.py:10-15; T/eligibility/ok_liheap_eligible.yaml:5 says "no asset test" without a cite and runs only in 2027.
    • The 9-15-25 text keeps 340:20-1-11(e), which caps liquid resources "per OKDHS Appendix C-7" (Register p. 581), and 340:20-1-10(h)(2) (p. 576). The 9-15-26 amendment removed both.
    • No resource level existed, so no code change is needed. The 10/1/2024 and 10/1/2025 C-7 editions print none. Plan item 2.3 answers "No" to an assets test (FY2025 p. 9, FY2026 p. 9), and FY2026 p. 14 says "Oklahoma does not use resources".
    • Fix: add a comment with these cites. Optionally run eligible Case 1 (bank_account_assets: 1_000_000) in 2026.
    • The reference checker rated this SHOULD; it is a suggestion because it is documentation only, with no value change.
  • G8. The Part B cases rely on medicare_enrolled defaulting to true at age 70 (T/ok_liheap.yaml:271, 372, 409). Set medicare_enrolled: true. Note at V/income/ok_liheap_income_deductions.py:33-35 that Part B counts only for enrollees, and that a nonzero health_insurance_premiums replaces the split.
  • G9. Case 13 (T/ok_liheap.yaml:436) pays $235 in both rows, so the award does not show the is_usda_disabled arm. Add a case like $9,000 of SSDI with $1,200 of medical costs: $650 a month, $265 (with the arm) against $235 (without). An SSI recipient under 60 is optional.
  • G10. No OK variable reads is_disabled now (89 test inputs). T/income/ok_liheap_net_income.yaml:137 (is_disabled: true) misleads, because the deduction comes from SSDI. Drop it or add a note.
  • G11. V/income/ok_liheap_income_deductions.py:36 reads the SNAP-named snap_allowable_medical_expenses, and medical_age_threshold.yaml duplicates is_usda_elderly. Both are defensible. Optional: an OK-owned list, or is_usda_elderly | is_usda_disabled.
  • G12. The FY2026 per-member $596 has no cite in P/income/limit/{max_table_size,rounding_increment,fpg_rate,fpg_year_lag}.yaml or V/eligibility/ok_liheap_income_limit.py:12-16. Add the 10/1/2025 C-7 capture that P/income/deductions/earned_income.yaml:16-17 already cites (verified: $596, $240).
  • G13. Five parameters cite 340:20-1-11 only from the 9-15-25 Register text (for example medical_age_threshold.yaml:10-11, unearned.yaml:52-53), but FY2027 runs under the 9-15-26 text. Add the Title 340 link, titled "as amended effective 9-15-26". The wording is unchanged, so the values hold.
  • G14. The unearned.yaml:54 title calls 340:50-7-29(c) "incorporated", but 340:20-1-11(b) incorporates only 340:50-7-22; the 340:50-7-31 medical list (:19-20) is also applied by analogy. Also, :20 claims item 1.9 for FY2025-FY2027, while :56-57 cites only FY2026. Add the FY2025 and FY2027 #page=6 links (all three verified).
  • G15. No cited source states the one-year lag in fpg_year_lag.yaml: plan 2.1 (p. 9) says only "HHS Poverty Guidelines". Add the reconciliation at lines 2-3: 1.3 × 15,060 / 12 = 1,631.50, rounded up to $1,632.
  • G16. V/income/ok_liheap_income_deductions.py:27-29 lists the unmodeled 340:50-5-4 categories but omits (a)(7), the VA aid-and-attendance or housebound veteran. List it, or say that is_permanently_disabled_veteran covers it.
  • G17. P/income/deeming/child_only_need_standard.yaml:52-53 links the 1/1/2025 C-1 capture at #page=4 for Schedule IX-B, but the 7/1/2026 edition prints IX-B on p. 5. The Wayback archive was blocked here, so confirm the page.
  • G18. No case pins prior G1 (ok_liheap_eligible: true with ok_liheap: 0 for directly billed SOLAR or OTHER). T/payment/ok_liheap_matrix_amount.yaml Case 7 checks only the matrix amount.
  • G19. There is no integration.yaml (IL, KS, NJ and OR LIHEAP have one). A suggestion only, because T/ok_liheap.yaml cases already chain 4-6 intermediates.

Cross-PR note: Oklahoma's limit is 130% of the same lagged guideline, so the shared 110% FPG floor (gov/hhs/liheap/fpg_floor.yaml in #9968 and #9969) can never bind. No change is needed.

Prior Findings

ID Finding Status
S1 Raw unemployment_compensation RESOLVED: unearned.yaml:15; countable Case 5
S2 Social Security netted of Part B RESOLVED: gross; Case 7 $0, Case 12 $265
S3 Payroll premiums; is_disabled RESOLVED: deductions Case 3, Case 13
S4 Off-template descriptions RESOLVED
S5 Page lists, #page=1, limit dates RESOLVED: dated 2024-10-01; FY2025 $583 verified
S6 farm_operations_income never positive RESOLVED: earned Case 8
G1 SOLAR/OTHER eligible at $0 RESOLVED: documented (ok_liheap_eligible.py:45-49); see G18
G2 FY2025 cites; resource test STILL OPEN (partly): limit cites done; income lists and ages stay dated 2025-09-15 (harmless); pre-10/2024 resource test only in rulespec-us#1535
G3 Partnership/S-corp income as earned STILL OPEN: declined by author (earned.yaml:4-7)
G4 Test and comment hygiene RESOLVED (new leftover: G10)
G5 PR body and issue housekeeping STILL OPEN (partly): "not run locally" kept, declined by author
G6 References polish STILL OPEN (partly): live C-7 and C-1 links remain, under three title forms

PDF Audit Summary

Category Count
Values matching source 31
Confirmed value mismatches (code path + visual) 0
Source conflicts investigated and cleared 1
Changed page anchors correct 34 of 34
Context anchors correct / unverifiable 10 / 1 (G17)
Citation-precision notes 4 (G14-G16)
External documents verified 2 (C-7 10/1/2025; FY2026 plan pp. 9, 14)

Validation Summary

Check Result
Regulatory accuracy 0 critical, 0 should
References 0 critical; 1 should, rated G7 (documentation)
Code patterns 0 critical, 0 should
Test coverage 0 critical, 0 should; 72 of 72 pass locally
Code-path verification 1 item, cleared
CI 29 of 29 checks pass

Review Severity: APPROVE

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 af84edb.

Thanks also for tracing the gross Social Security question. The model keeps that treatment.

  • G7: ok_liheap_eligible.py now has a comment explaining why no asset test applies. The September 2025 text kept 340:20-1-10(h)(2) and 340:20-1-11(e) (Register pages 576, 581). However, the 10/1/2024 and 10/1/2025 C-7 editions print no resource level, plan item 2.3 answers No (FY2025 and FY2026, page 9), and the FY2026 plan says "Oklahoma does not use resources" (page 14). The variable's references add the Register and the FY2025 plan. New eligibility Case 5 runs 2026 with $1,000,000 and with $0 in a bank account, and both rows are eligible at the $20,352 limit.

  • G8: Cases 7, 11 and 12 now set medicare_enrolled: true, and no expected value changes. The ok_liheap_income_deductions comment now says the Part B premium counts only for members with medicare_enrolled, and that a nonzero health_insurance_premiums input replaces the non-Medicare and Part B split.

  • G9: New ok_liheap.yaml Case 14 (2026, age 50, $1,200 of medical costs) uses your figures. $9,000 of SSDI gives the $1,200 deduction, $650 a month and $265. The same $9,000 from employer disability insurance (disability_benefits) gives no deduction, $750 a month and $235. Integration Case 3 covers the SSI recipient under 60 (G19).

  • G10: I kept is_disabled: true on the SSDI recipient in net-income Case 4, since the flag is realistic, and added your note. The SSDI receipt (is_usda_disabled) qualifies the member, and no Oklahoma LIHEAP variable reads is_disabled.

  • G11: Partly done. The medical test now reads is_usda_elderly | is_usda_disabled, because 340:50-5-4(a)(1) restates the 7 CFR 271.2 age-60 member. deductions/medical_age_threshold.yaml is deleted. Both thresholds are 60 and inclusive, so no value changes. snap_allowable_medical_expenses stays: it already sums the modeled part of the 340:50-7-31(a)(3)(A) list, and an Oklahoma-owned list would duplicate it.

  • G12: max_table_size, rounding_increment, fpg_rate, fpg_year_lag and earned_income now cite three C-7 editions: 10/1/2024, 10/1/2025 (Wayback 20260509201726, printing $596 and $240) and 10/1/2026. All five use one title form ("OKDHS Appendix C-7, 10/1/2025 edition"). ok_liheap_income_limit lists all three editions.

  • G13: earned_income.yaml adds the Title 340 link, titled "as amended effective 9-15-26". earned.yaml, unearned.yaml and student_earned_income_age_limit.yaml already linked that file. I retitled their entry to name 340:20-1-11 as amended effective 9-15-26, keeping one entry per source. G11 removes medical_age_threshold.yaml.

  • G14: The unearned.yaml Title 340 reference title now calls 340:50-7-22 the incorporated SNAP exclusions, and 340:50-7-29(c) and 340:50-7-31(a)(3)(A) SNAP rules applied by analogy. The Social Security comment in unearned.yaml and the medical-expense comment in ok_liheap_income_deductions.py also mark the 340:50-7-31(a)(3)(A) list as applied by analogy. The references add item 1.9 of the FY2025 and FY2027 plans at #page=6.

  • G15: The fpg_year_lag.yaml comment now cites LIHEAP IM 2024-02, IM 2025-02 and IM 2026-01, which make each January's guidelines mandatory from the next October 1. It notes that plan 2.1 names only the HHS guidelines. It also gives your reconciliation: 1.3 × 15,060 / 12 = 1,631.50, rounded up to $1,632 (the 2025 guideline would give $1,696), and the FY2026 ($1,696) and FY2027 ($1,729) checks. The three IM references match PR 10279's entries.

  • G16: The rewritten deduction comment says the veteran flags that is_usda_disabled reads stand in for 340:50-5-4(a)(6)-(9). An aid-and-attendance or housebound veteran ((a)(7)) is therefore entered as is_permanently_disabled_veteran. The PR body's not-modeled row says the same.

  • G17: No change. The Wayback 20250222193016 capture of the 1/1/2025 C-1 prints Schedule IX-B ("B. Children only", $193 to $1,333) on PDF page 4 of 8. The 7/1/2026 edition moves IX-B to page 5, and the file cites that edition in a separate entry.

  • G18: New ok_liheap.yaml Case 15 (2026, $12,000 of wages, $1,200 bills, net $9,120) covers directly billed SOLAR and OTHER. Both are eligible, with ok_liheap_matrix_amount and ok_liheap at $0. A natural gas row in the same case receives $235.

  • G19: Added integration.yaml with five households, each checking 8 to 10 values:

    • an FY2025 retiree heating with propane ($350);
    • an FY2026 single parent of three with a child care copay ($259);
    • an FY2026 SSI recipient roomer with heat in rent ($40);
    • an FY2026 mixed-status family with deemed income ($235);
    • an FY2027 nine-person household at the additional-member limit ($277).

    The PR now has 80 cases in 13 files.

  • Cross-PR note: Agreed. Oklahoma's 130% limit stays above the 110% floor at every size, so the PR adds no fpg_floor parameter or floor code.

  • G2: Partly done. The code now documents the FY2025-FY2026 resource provisions (G7), and one of the dated ages is gone (G11). The income lists and the student age keep the 9-15-25 date because the 2025 backfill gives the same result. History is out of scope for this PR, so the pre-October 2024 resource test stays in the rulespec-us issue.

  • G3: Still declined. Splitting partnership and S corporation income would need a new input, because partnership_s_corp_income cannot separate active partners' earnings from S corporation and passive shares. The KS, KY, OR and NY LIHEAP lists count it as earned, and only the $240 deduction differs.

  • G5: The body still says the tests were not run locally, because we leave test runs to CI. It now also notes your local run of all 72 cases at f0e2f40.

  • G6: Partly done. The 7/1/2026 C-1 links now use the Wayback 20260903155011 capture in child_only_need_standard.yaml, ok_liheap_deemed_income.py and the PR body. Every C-7 entry now uses one title form (G12). The 10/1/2026 C-7 keeps its live link because the latest Wayback capture of c-7.pdf (June 17, 2026) is still the 10/1/2025 edition.

  • LIHEAP wave 2a: encode Oklahoma LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1535 is refreshed to match.

@DTrim99

DTrim99 commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

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

PR #9970 (author: hua7450). This round reviews head 7df60173a4; round 1 reviewed 9b6b0dac45. Four commits and one outside review came in between:

Neither merge had a hand-resolved conflict, and neither touches an Oklahoma LIHEAP file.

Path prefixes, as in round 1: P/ = policyengine_us/parameters/gov/states/ok/dhs/liheap/, V/ = policyengine_us/variables/gov/states/ok/dhs/liheap/, T/ = policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/. Line numbers refer to 7df60173a4.

Summary

Ziming fixed all six round-1 should items:

  • S1. The unearned list reads total_unemployment_compensation. Main's guard passes at the head, and countable Case 5 pins modeled ok_ui ($6,480 moves the award from $365 to $265).
  • S2. He took the fix I proposed. Social Security counts gross in the income test, and members 60 or older or disabled deduct the whole Part B premium afterwards. ok_liheap.yaml Case 7 now pays $0 to both retirees, and the PR body's headline example (Case 12) is correct.
  • S3. The medical deduction reads snap_allowable_medical_expenses, which includes pre_tax_health_insurance_premiums, and gates it on is_usda_elderly | is_usda_disabled. Deductions Case 3 and ok_liheap.yaml Cases 13 and 14 pin both parts.
  • S4. All 15 descriptions follow the template.
  • S5. The page lists and #page=1 are added. The four limit parameters start on 2024-10-01 and cite FY2025 sources.
  • S6. Countable-earned Case 8 adds $1,200 of positive farm income.

Of the six suggestions, G1 and G4 are fixed. G2, G5 and G6 are partly done, and G3 is declined; I accept the reasons for each. Pavel's G7–G19 are all done or answered, and I checked his open G17 page anchor against the archived file.

There are no new critical or should findings. Two new suggestions come from main commits merged after this head's last merge:

Batch checks:

I checked every new or changed expectation by hand: 12 new cases, 4 changed cases, and the cases whose inputs were renamed or removed. CI is 29/29 green at the head. The branch is 12 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 and modeled ok_ui dropped out Fixed The list. P/income/sources/unearned.yaml:15 reads total_unemployment_compensation. No Oklahoma LIHEAP file reads the raw input. The guard. All four test_unemployment_compensation_readers.py tests pass at the head (Rest shard-1). Modeled path. Countable Case 5 has no reported UI and ok_ui of 6,480. That gives 540 a month, row $401–$700 and $265; without the UI it would be $365. The issue. rulespec-us#1535's countable-income output names the total.
S2: Social Security counted net of Part B in the income test, against OAC 340:20-1-11(a) and (c) Fixed The code. The netting is gone from V/income/ok_liheap_countable_income.py, and social_security is a gross entry (P/income/sources/unearned.yaml:25). The deduction reads the whole premium through snap_allowable_medical_expenses. The tests. ok_liheap.yaml Case 7: 21,360 / 12 = 1,780 > 1,696, so [false, false] and [$0, $0]. Case 12 counts 12,000 and deducts 4,234.80, for $265. Countable Cases 2 and 4 count 13,200 and 15,600, my round-1 hand values. Disclosure. The unearned.yaml comment, the body's conflict table and #1535 interpretation 1 set the OAC and the plan narrative (p. 7) against the item 1.9 box. Pavel cleared the same reading.
S3: the medical deduction missed payroll premiums (#10046) and read is_disabled Fixed Payroll premiums. V/income/ok_liheap_income_deductions.py:43 reads snap_allowable_medical_expenses, which adds medical_expense_health_insurance_premiums (non-pretax premiums plus Part B for enrollees), pre_tax_health_insurance_premiums and other_medical_expenses. Deductions Case 3: age 62, payroll or after-tax premium of 1,440, gives 4,320 and $265 in both rows; age 40 gives 2,880 and $235. Disability. Lines 34-35 read is_usda_elderly | is_usda_disabled. ok_liheap.yaml Case 13: SSDI qualifies and a bare is_disabled flag does not. Case 14 (Pavel's G9): SSDI of 9,000 gives $265, and the same amount as employer disability insurance gives $235.
S4: eight descriptions off the template, three misdescribing the parameter Fixed All eight use my wording, and the student parameter says "elementary or high school students". All 15 remaining descriptions end at "under the Low Income Home Energy Assistance Program." medical_age_threshold.yaml is deleted (Pavel's G11).
S5: missing page lists, a missing #page=1, and FY2025 limits dated and cited only from FY2026 Fixed Pages. The earned and unearned Register titles end "#page 576-578", and V/ok_liheap.py opens C-7-A at #page=1. Dates. fpg_rate, fpg_year_lag, max_table_size and rounding_increment start on 2024-10-01. They cite FY2025 plan item 2.1 (#page=9), the December 17, 2024 notice and the 10/1/2024 C-7 capture. No value changes.
S6: farm_operations_income was never positive in a test Fixed Countable-earned Case 8: 12,000 + 1,200 = 13,200. It would be 12,000 without the entry.
G1: SOLAR and OTHER eligible at $0; an UNSPECIFIED heat-in-rent household with a surcharge flag Documented and pinned (accepted) V/eligibility/ok_liheap_eligible.py:56-60 records both and cites #9754. ok_liheap.yaml Case 15 (Pavel's G18) gives SOLAR and OTHER eligibility with $0 and a gas control $235. The heat-in-rent choice was optional and stays pinned by eligibility Case 2 and ok_liheap.yaml Case 10.
G2: FY2025 citations, the 2025 rule, earlier years Partly done (accepted) Done. FY2025 citations, and the body says the pre-September 2025 exclusion list gives the same result for every modeled source. Declined. FY2023–FY2024 stay unclaimed (history out of scope, as in #9967–#9969). The pre-October 2024 resource test is recorded in #1535 only. The income lists keep their 2025-09-15 dates, which is harmless because the backfill gives the same result.
G3: partnership and S-corporation income counted as earned Declined (accepted) P/income/sources/earned.yaml:4-7 and a not-modeled body row give the reason: the input cannot split active partners' earnings from passive shares. The KS, KY, OR and NY lists on main do the same, and only the $240 deduction differs.
G4: test and comment hygiene Fixed Comments. They are re-spaced, and the internal "contract" wording is gone. FY2025 case. The limit case describes FY2025. Unread inputs. is_full_time_student and unread bills are removed from the countable-earned, limit and matrix cases. heating_type stays by convention, which is harmless. The many remaining is_disabled: false inputs are unread but harmless.
G5: PR body and issue housekeeping Mostly done (accepted) The body. It describes the struck list as exclusions, notes the 9-15-26 amendment and adds 340:20-1-13(2)(B)–(C) to the heat-in-rent rows. The make format box is checked. The issue. "Draft" is gone from #1535. Declined. "Not run locally" stays, because the team leaves test runs to CI; the body now notes the reviewers' runs.
G6: references polish Partly done (accepted) Done. The LII links point to the official Title 340 file. The 7/1/2026 C-1 uses the Wayback 20260903155011 capture. Every C-7 entry uses one title form, and the deduction variable names 340:50-5-4 and 340:50-7-31(a)(3)(A)(v)–(vi). Declined. The 10/1/2026 C-7 keeps its live link. That is fair: the Wayback index's newest c-7.pdf capture (2026-06-17) still has the 10/1/2025 file's digest.

Pavel's review (between rounds). He requested nothing as should. Every suggestion is answered:

Pavel's item Status Evidence
G7: no comment on why the FY2025–FY2026 resource rule is not modeled Fixed V/eligibility/ok_liheap_eligible.py:12-18 cites Register pp. 576 and 581, both plan item 2.3 answers and FY2026 p. 14. The references add the Register (# PDF pages 576, 581) and the FY2025 plan. Eligibility Case 5 (2026): 18,000 with $1,000,000 or $0 in the bank gives a limit of 20,352 and [true, true].
G8: Part B cases relied on the medicare_enrolled default Fixed Cases 7, 11 and 12 set medicare_enrolled: true, with no value change. The deduction comment (lines 37-42) states the enrollee rule and the health_insurance_premiums override, which match medical_expense_health_insurance_premiums.
G9: Case 13's award did not show the is_usda_disabled arm Fixed ok_liheap.yaml Case 14: [$265, $235], with net [7,800; 9,000]. Integration Case 3 adds an SSI recipient under 60.
G10: a misleading is_disabled: true in net-income Case 4 Fixed (note) A comment says the SSDI receipt qualifies the member and no Oklahoma LIHEAP variable reads is_disabled.
G11: SNAP-named aggregate; age parameter duplicates is_usda_elderly Partly done (accepted) is_usda_elderly (threshold 60, inclusive) replaces the deleted parameter. Deductions Case 1 row 2 (age 60) pins the inclusive edge. The SNAP aggregate stays, which is reasonable: the rule applies SNAP's list by analogy, and an Oklahoma list would duplicate it.
G12: no cite for the FY2026 $596 Fixed The four limit parameters, earned_income.yaml and ok_liheap_income_limit cite the 10/1/2024, 10/1/2025 and 10/1/2026 C-7 editions.
G13: 340:20-1-11 cited only from the 9-15-25 text Fixed earned_income.yaml adds Title 340 "as amended effective 9-15-26". The earned, unearned and student titles name the 9-15-26 text in their existing Title 340 entry (one entry per source).
G14: "incorporated" for 340:50-7-29(c); FY2025 and FY2027 item 1.9 links Fixed The unearned.yaml title calls 340:50-7-22 incorporated and 340:50-7-29(c) and 340:50-7-31(a)(3)(A) "applied by analogy". It adds the FY2025 and FY2027 plans at #page=6.
G15: no source states the one-year lag Fixed fpg_year_lag.yaml:2-9 cites IM 2024-02, IM 2025-02 and IM 2026-01 and reconciles 1.3 × 15,060 / 12 = 1,631.50 → $1,632. The three IM entries are the same URLs and titles as main's MS, NJ, OR and DC fpg_year_lag files.
G16: the (a)(7) aid-and-attendance veteran Fixed Lines 25-33 say the veteran flags stand in for (a)(6)–(9), so an (a)(7) veteran is entered as is_permanently_disabled_veteran. The body's not-modeled row says the same.
G17: confirm the 1/1/2025 C-1 page for Schedule IX-B No change needed (verified) The Wayback 20250222193016 capture prints "Schedule IX – TANF", with IX-A ($398 … $1,436) and "B. Children only" ($193 … $1,333), on "Page 4 of 8". So #page=4 is right. The 7/1/2026 entry opens p. 5.
G18: no case pinned directly billed SOLAR or OTHER Fixed ok_liheap.yaml Case 15.
G19: no integration.yaml Fixed Five households, each checking 8–10 values (hand-checked below).
Cross-PR note: the 110% floor cannot bind Agreed See Verified.

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:31 lists military_retirement_pay (with pension_income at line 30 and survivor_benefits at line 35).
  • 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 "The benefits received under a United States military retirement plan, 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. OAC 340:20-1-11(a) counts "All gross earned and unearned income", and 340:50-7-29(c)(2) (applied by analogy) makes "Annuities, pensions, retirement, and Social Security benefits" unearned income. T/ok_liheap.yaml Case 8 counts $24,000 of military retirement pay.
  • Effect on the merged tree (worked out from the code, not run). A surviving spouse aged 62 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.
    • Add a military_retirement_pay_survivors amount to ok_liheap.yaml Case 8 or to a countable-income case.
    • Update the countable-income output of rulespec-us#1535.

2. After #10165, count Oklahoma's State Supplemental Payment (ok_ssp).

  • Where:
    • P/income/sources/unearned.yaml has no ok_ssp entry.
    • Its comment at line 10 says "State SSP receipts are not modeled; SSI is federal".
    • The body's not-modeled table says "State supplementary payments | — | Not modeled; ssi is the federal benefit".
  • What changed on main: Add Oklahoma state supplementation for 2026 #10165 merged on 2026-10-20, after this head's last merge.
    • It adds ok_ssp, a monthly person-level payment of up to $40 from 2026-01-01 (Appendix C-1 7/1/2026, Schedule VIII.A).
    • It lists ok_ssp in SNAP's and HUD's unearned sources, Form 538-H gross income, household_state_benefits and spm_unit_benefits.
    • A full SSI recipient with no other income gets the whole $40: 994 + 40 − 994 = 40.
  • The rule counts these payments.
    • OAC 340:20-1-11(a) counts all gross unearned income, and (b) excludes only what SNAP (or the recipient's own program) excludes.
    • Oklahoma SNAP's inclusion rule, which the PR already cites by analogy, says: "The worker counts payments from a federally aided public assistance program, such as Supplemental Security Income (SSI), ... or assistance programs based on need, such as State Supplemental Payments, as unearned income" (340:50-7-29(c)(1)).
    • 340:20-1-11(a)(1)(B) also names "State Supplemental Payment (SSP) cash assistance" among the programs whose gross income LIHEAP reuses.
  • Effect on the merged tree (worked out from the code, not run). A disabled SSI recipient aged 45, who meets ok_ssp_eligible, lives alone. She has SSI of $994 a month, $3,840 a year of uncovered medical costs ($320 a month) and natural gas heat with a bill, in 2026:
    • Merged tree: countable 11,928; medical deduction 3,840 (is_usda_disabled through SSI); net 8,088, or 674 a month: row $401–$700, $265.
    • Counting ok_ssp ($480 a year through the list's ADD option): countable 12,408; net 8,568, or 714 a month: row $701 and up, $235.
    • At $40 a month, only households near a row start or the gross limit change. No existing case changes, because the list never reads ok_ssp.
  • Why a suggestion, not should:
    • At this head's base there was no Oklahoma SSP, so the head is correct against its base.
    • Add New York state supplementation for 2026 #10158 likewise left the merged New York HEAP list without ny_ssp.
    • No guard flags it, and the amount is small.
    • The fix is one line, and it keeps the PR's own comment and body from going stale on merge.
  • Fix, if taken here:
    • Add ok_ssp to P/income/sources/unearned.yaml, and drop the "not modeled" comment and body row.
    • Optionally add a case like the one above.
    • Update Make a pa_income_tax_forgiveness variable #1535's countable-income output and its "Oklahoma's state supplement is not modeled" note.
    • Optional: a member with SSP but $0 SSI now falls under 340:50-5-4(a)(3), which the body lists as having no input.

Verified

  • Mutation check (item 13), reasoned from the tests and code at the head:
    • ok_liheap_income_deductions:
      • The is_usda_elderly arm. Integration Case 1 (4,020 at age 68), ok_liheap.yaml Cases 7, 11 and 12, and deductions Case 1 row 2 (age 60). A strict > would fail row 2: 3,280 instead of 3,880.
      • The is_usda_disabled arm. ok_liheap.yaml Cases 13 and 14, integration Case 3, net-income Case 4 and deductions Case 1 row 3.
      • Payroll premiums. Deductions Case 3 row 1.
      • Non-pretax premiums. Deductions Case 3 row 2 and ok_liheap.yaml Case 12.
      • Part B for enrollees. Cases 7, 11 and 12 and integration Case 1.
      • Not pinned, harmless: the max_(..., 0) floor on the aggregate, whose parts are non-negative inputs.
    • ok_liheap_countable_income:
      • Gross Social Security. Case 7 row 1 and countable Cases 2 and 4. Restoring the netting changes eligibility and both totals.
      • total_unemployment_compensation. Countable Case 5 (modeled path).
      • Farm income. Countable-earned Case 8.
    • Unchanged since round 1: the other branches. Round 1 confirmed them by mutation runs, and only comments changed in ok_liheap_eligible, ok_liheap_income_limit, ok_liheap_deemed_income and ok_liheap.
  • State-gated keys (item 15, NH Add New Hampshire state supplementation for 2026 #10156).
    • No int or enum key is new. The deleted age parameter was a scalar. ok_liheap_household_size still feeds bracket lookups through max_(size, 1), and the matrix keys come from bracket lookups that return 1–3.
    • Mixed-state tests. TX and OK rows still run together in eligibility Case 4, ok_liheap.yaml Case 6 and matrix Case 6.
  • Integrate modeled state unemployment insurance into income flows #9558 (item 11). The guard's four tests pass at the head, and no Oklahoma LIHEAP 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).
    • Premiums. Payroll premiums count as medical expenses for members 60 or older or disabled, as SNAP's list does on main (deductions Case 3).
    • Gross wages. Wages come from employment_income, documented as gross before pre-tax payroll deductions, not from ssi_earned_income. That matches 340:20-1-11(a)'s gross count.
  • Federal 110% floor (42 U.S.C. 8624(b)(2)(B)). It never binds.
  • IIJA and FY2027 (item 12).
    • IIJA. No supplement, as in round 1.
    • FY2027 sources. On 2026-10-20 the Clearinghouse returns 404 for an Oklahoma FY2027 plan and matrix. OKDHS's C-7-A file is still the June 17, 2026 file. The encoded 10/1/2026 C-7 and the posted FY2027 plan remain the latest sources.
  • Other main commits.
  • New and changed expectations, checked by hand.
    • Limits used: FY2025 size 1 is 1,632 (1.3 × 15,060 / 12 = 1,631.50, rounded up). FY2026 is 1,696 / 2,888 / 3,483 for sizes 1 / 3 / 4. FY2027 is 6,037 for size 8 plus 616 per extra member.
    • Matrix rows: $0–$400, $401–$700, $701 and up.
    • ok_liheap.yaml:
      • Case 7 (changed): 1,780 > 1,696 gives [false, false] and [0, 0]. Net: 21,360 − 2,434.80 = 18,925.20, and 21,360 for the member with no premium.
      • Case 11 (input added): 9,000 − 2,434.80 = 6,565.20, or 547 a month: $265.
      • Case 12 (changed): countable 12,000; deductions 1,800 + 2,434.80 = 4,234.80; net 7,765.20, or 647 a month: $265.
      • Case 13 (new): gross 19,560 (1,630 ≤ 1,696) in both rows. Deductions are [1,200 (SSDI), 2,880 (earned only)]. Net [18,360; 16,680] is 1,530 and 1,390 a month, so [235, 235].
      • Case 14 (new): 750 a month ≤ 1,696. Deductions [1,200, 0], net [7,800; 9,000], or 650 and 750 a month: [265, 235].
      • Case 15 (new): 12,000 − 2,880 = 9,120, or 760 a month. Each row has a bill for its fuel, so eligibility is [true, true, true]. SOLAR and OTHER have no column, so [0, 0, 235].
    • integration.yaml (new):
      • Case 1 (2025): 1,000 ≤ 1,632. Age 68: Part B 2,220 (185 × 12, enrolled) + 1,800 = 4,020. Net 7,980, or 665 a month. Propane is the delivered table, sizes 1–3: $350.
      • Case 2: size 4; 2,600 ≤ 3,483 (41,796). The copay counts because the subsidy is 2,272.80 > 0, so 31,200 − 2,880 − 2,268 = 26,052, or 2,171 a month. Gas, sizes 4–6: $259.
      • Case 3: SSI 11,928 makes is_usda_disabled true. 994 ≤ 1,696. The heat-in-rent roomer has a $300 surcharge bill. 11,928 − 600 = 11,328, or 944 a month. Roomer, sizes 1–3: $40.
      • Case 4: size 3 without the undocumented parent. Deemed 24,000 − 2,880 − 398 × 12 = 16,344 (IX-A $398, which I confirmed on the 1/1/2025 C-1 p. 4). Gross 28,344, or 2,362 ≤ 2,888 (34,656). Only the eligible parent's 2,880 reaches net: 25,464, or 2,122 a month. Gas, sizes 1–3: $235.
      • Case 5 (2027): size 9; limit (6,037 + 616) × 12 = 79,836. 4,333 ≤ 6,653. Net 49,120, or 4,093 a month. Electricity, 7 or more: $277.
    • ok_liheap_eligible.yaml Case 5 (new): 1,500 ≤ 1,696; limit 20,352; bank assets unread, so [true, true].
    • ok_liheap_countable_income.yaml:
      • Case 2 (changed): 1,200 + 12,000 = 13,200.
      • Case 4 (changed): 12,000 + 3,600 = 15,600.
      • Case 5 (new): 6,480 is 540 a month: $265. Without the UI, $365.
    • ok_liheap_countable_earned_income.yaml Case 8 (new): 13,200.
    • ok_liheap_income_deductions.yaml:
      • Case 1 (input renamed): [1,200 + 300; 2,880 + 600 + 400; 2,880 + 700 + 500] = [1,500; 3,880; 4,080].
      • Case 3 (new): [4,320; 4,320; 2,880]. Net [7,680; 7,680; 9,120] is 640, 640 and 760 a month: [265, 265, 235].
    • ok_liheap_net_income.yaml Case 4 (input renamed): 30,000 − 2,880 − 2,400 − 1,200 = 23,520, with the SSDI recipient qualifying through social_security_disability.
    • Changed inputs, unchanged outputs:
      • The cases: income-limit Cases 1–4 and matrix Cases 1–7 drop bills; countable-earned Cases 3–7 drop is_full_time_student.
      • None of those variables reads them. The limit reads size and state. The matrix amount reads fuel, size, net income, dwelling type and heat in rent. The student exclusion reads is_in_k12_school and dependency.
  • Inputs not checked. I didn't re-derive these amounts; they are inputs only, and every expectation follows from them:
    • the ok_ui statutory steps behind 6,480 (an existing model output that CI computes);
    • SSA's $1,630 SSDI average;
    • KFF's $1,440 premium;
    • the Appendix C-4 child care figures.
  • Wiring.
    • Registry. The programs.yaml entry is unchanged since round 1 (OK partial, verified_years: "2025-2027"), and test_programs_registry passes.
    • Aggregates. No aggregate wiring, which matches every merged LIHEAP state.
    • Gating. defined_for = StateCode.OK is on all 13 variables.
    • Changelog. changelog.d/ok-liheap.added.md is top level and typed added.
  • Partner tests. The PR touches none, and Household API Partners passes.

Checklist results (LIHEAP wave 2a)

  1. State plan and manual: pass. Encoded values are unchanged since round 1, apart from the new start dates. I re-read the 1/1/2025 C-1 (G17) and OAC 340:20-1-11 and 340:50-7-29(c)(1) in the current Title 340 (Suggestion 2).
  2. Income definition: pass.
  3. Backdating: pass for claimed years. The FY2025 limit parameters now start on 2024-10-01 with FY2025 cites. FY2023–FY2024 are unclaimed (G2, declined).
  4. Household and arrangement rules: pass. Directly billed SOLAR and OTHER are now pinned at $0 (Case 15). Every route has a test.
  5. Tests: pass. 80 cases in 13 files; every new or changed expectation was checked by hand. Periods are plain.
  6. Descriptions: pass. All 15 follow the template.
  7. References: pass.
    • Multi-page titles use #page 576-578 and #page 6-7.
    • Variable tuples use # PDF pages 576, 581 and # PDF pages 9, 14 comments.
    • The C-7 editions use one title form, and the IM entries match main.
  8. Wiring: pass. Registry, no aggregate (as in the siblings), defined_for on every variable, and no take-up beyond tanf's.
  9. Axiom: valid queued line. Make a pa_income_tax_forgiveness variable #1535 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 Clearinghouse plan or matrix is published.
  13. Mutation check: pass. Every new branch is pinned.
  14. Document disjoint health premium inputs and correct consumer treatment #10046 health premiums: fixed. Payroll premiums are deducted (deductions Case 3), and wages are gross.
  15. State-gated index defaults: not present. No new keys, and the mixed TX/OK cases still run.
  16. Wire military retirement pay and survivors into federal and state tax (#10181) #10182 survivor annuities: Suggestion 1.
  • Federal 110% floor: never binds (ratio at least 1.18), so no floor parameter is needed.

Axiom line assessment

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

  • Issue state.
    • Make a pa_income_tax_forgiveness variable #1535 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 Oklahoma LIHEAP module: us-ok/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 OAC, Register, plan, C-7, C-7-A, C-1 and federal text;
    • 13 required outputs;
    • companion tests C1–C20, hand-derived from the sources ("None is taken from policyengine-us output") and mapped to PE cases.
  • Matches the head 7df60173a4:
    • Cases: 80 cases in 13 files, listed per file.
    • Countable income: gross Social Security and total_unemployment_compensation.
    • Personal deductions: snap_allowable_medical_expenses (with payroll premiums and Part B for enrollees) if is_usda_elderly or is_usda_disabled.
    • Interpretations: the resource and Medicare readings.
    • Companion tests C15–C20 match deductions Case 3, countable Case 5, Cases 13 and 14, earned Case 8 and integration.yaml.
  • Updates it would need if the suggestions are taken: the countable-income output (military_retirement_income, ok_ssp) and the "state supplement is not modeled" note.

CI status

29 pass, 0 pending, 0 failed (run 39324237627 on head 7df60173a4, pull_request, 2026-10-19 21:02 UTC to 2026-10-20 02:33 UTC). I re-checked gh pr checks 9970 at the end of this review.

  • Quick Feedback ran all 13 Oklahoma LIHEAP files at the head: 5 + 5 + 4 + 8 + 5 + 8 + 5 + 3 + 8 + 5 + 15 + 2 + 7 = 80 passed.
  • 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.

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 six should-address items from round 1 are fixed (#9558 reader, gross Social Security with Part B deducted afterwards, medical deduction including pre-tax premiums, descriptions, references, farm case). Two open suggestions: #10182 survivor annuities, and ok_ssp now that #10165 has merged. Full report in the comment above.

# Conflicts:
#	policyengine_us/programs.yaml
@hua7450
hua7450 merged commit b169b34 into main Oct 20, 2026
1 check failed
@hua7450
hua7450 deleted the ok-liheap branch October 20, 2026 21:20
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 Oklahoma LIHEAP regular heating assistance

3 participants