Skip to content

Add Georgia LIHEAP regular heating assistance - #9968

Merged
PavelMakarchuk merged 21 commits into
mainfrom
ga-liheap
Oct 22, 2026
Merged

PavelMakarchuk merged 21 commits into
mainfrom
ga-liheap

Conversation

@hua7450

@hua7450 hua7450 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Adds Georgia's LIHEAP regular heating assistance for FY2025 and FY2026. The model tests income against 60% of state median income, places eligible households in Level I or Level II by the published lower-income cutoffs, and pays the fixed amount for the primary heating fuel. Federal law bars excluding a household on income below 110% of the poverty guideline (42 U.S.C. 8624(b)(2)(B)). Georgia's 60% limit, including its printed size-16 rows, falls below that floor from household size 16, so the model keeps a household of 16 or more eligible above the 60% limit when its income is below 110% of its poverty guideline. The model rounds that floor to the cent, so income exactly at 110% does not qualify. Unsubsidized renters whose rent includes all utilities and who report neither an electric bill nor a bill for their main heating fuel receive the lowest award for their income level. Renters with heat in rent who report a separate electric bill or a bill for their main heating fuel receive the amount for their main heating fuel, paid to the vendor, with or without a subsidy and whatever tenant_pays_utilities says. In FY2026, a one-person household with $12,000 of wages and electric heat receives the Level I electric amount, $500. In FY2025, a one-person household with $13,000 of wages is above the $12,995 Level I cutoff and receives $400.

Fixes #9959

Regulatory authority

The January 2022 manual is the newest Georgia LIHEAP income manual located. The current PAMMS export contains administrative chapters 100–800, not a replacement for income chapter 1200. The contemporaneous FY2022 plan already contains the cash-gift checkbox disagreement, so the detailed manual is used for cash contributions and gifts. Annual income approximates the application-month assessment.

Eligibility

Requirement Source How modeled
Georgia residence — defined_for = StateCode.GA
Household size excludes nonqualified noncitizens Manual pages 51–52 and 62; PAMMS chapter 100, page 4; DFCS LIHEAP page Counts members with is_citizen_or_legal_immigrant, with no SNAP waiting bars. A household with no qualified member is ineligible. Nonqualified adults' income counts in full. PAMMS chapter 100 ("Be US citizens or lawfully admitted immigrant") and the DFCS LIHEAP page ("The applicant needs to be a U.S. citizen or legally admitted immigrant") support counting lawful immigrants.
Income at or below 60% of state median income, or below 110% of the poverty guideline FY2026 plan section 2.1, page 8; FY2025 and FY2026 matrices, step 1; 42 U.S.C. 8624(b)(2)(B); FY2025 and FY2026 plans, assurance 2 (page 43); LIHEAP IM 2025-02 and IM 2024-02, Attachment 2 Calls the shared liheap_smi_limit helper (#10019): floors 60% of the four-person state median income, applies the federal size factor and floors again. This order reproduces all 16 FY2026 limits and the FY2025 limits tested for sizes 1, 4 and 16 ($33,038, $63,535 and $102,926); the sources do not state the order. One person in FY2026: $34,549. The limit is inclusive. Income below 110% of the poverty guideline also qualifies, through the shared federal parameter gov.hhs.liheap.fpg_floor (1.1), whose file is identical to the copy in #10279. As in #10279, the model rounds the floor to the cent, so income exactly at 110% does not qualify ("less than 110 percent"). Georgia assures this floor in both plans (page 43). Georgia's limit uses no poverty guideline, so the model uses the one HHS makes mandatory for the fiscal year (fpg_year_lag 1: the 2025 guidelines in FY2026, the 2024 guidelines in FY2025 and the 2026 guidelines in the carried-forward 2027 estimate). The printed size-16 limits, $107,634 (FY2026) and $102,926 (FY2025), are below 110% of poverty ($107,965 and $105,336), so the floor applies from size 16 and governs over the printed row. A protected household above the 60% limit gets the Level II amount, and ga_liheap_income_limit still reproduces the printed table.
Energy burden Manual pages 3–4, 50, 57, 82 and 89; PAMMS chapter 100, page 4 A household qualifies with its own heating obligation (has_heating_expense) or a positive primary-fuel bill, including when heat is in rent or the household receives a housing subsidy. Unsubsidized rent that includes all utilities (heat in rent, tenant_pays_utilities false, positive rent, no housing assistance or public housing) qualifies with no bill. A renter with heat in rent, rent above $0 and a positive pre_subsidy_electricity_expense qualifies with or without a housing subsidy and whatever tenant_pays_utilities says (manual page 89, third row: "Paid to electric vendor because gas usage is indeterminate"; page 4: subsidized renters qualify when "their utility bill is in their name"; page 57: subsidized households whose rent includes utilities are ineligible only if they "cannot verify an energy burden"). For payment this route, like a bill for the main heating fuel, takes precedence over the all-utilities route, because page 57 limits the unsubsidized all-in-rent class to rent that "includes utilities with no separate bill for heating/cooling costs". The same inputs therefore get the same award with or without a subsidy. The model reads page 82's ineligibility for subsidized housing where "the rent includes utilities" as rent that covers every utility, which a separate electric bill rules out. Heat in rent with none of these does not qualify, and a bill for a fuel other than the primary fuel does not establish the burden (PAMMS chapter 100: "a vendor bill/statement for the main heating source"). heating_type NONE is ineligible.
Categorical eligibility Manual Not applied; every household takes the ordinary income test (see below).

Countable income

Item Source How modeled
Members under 18 Manual section 1200.2, page 62 Excludes all income of members under 18.
Wages and business income Manual sections 1200.6–1200.7, pages 64–66 Counts wages and net self-employment, SSTB, farm operations and partnership/S-corporation income. Floors each source at zero, so a business loss offsets nothing.
Other income Manual section 1200.7, pages 65–69, and application item 12, page 83; FY2025 and FY2026 plans section 1.9, pages 5–7 Counts unemployment through total_unemployment_compensation (the reported amount, or modeled state unemployment insurance when none is reported; the model has no Georgia unemployment insurance program, so the reported amount counts), SSI, pensions, military retirement pay, railroad retirement (gross), survivor benefits, veterans benefits, disability benefits, workers' compensation, strike benefits, General Assistance, rental and farm rental income, dividends, capital gains, gambling winnings, alimony and child support. Floors each source at zero, so capital, rental and farm losses offset nothing.
Social Security net of the Medicare premium FY2025 and FY2026 plans section 1.9, page 6 ("Excluding MediCare deduction"); manual section 1200.7, page 69 Counts max(social_security − medicare_part_b_premium, 0) per adult.
Interest Manual section 1200.7, pages 66 and 69 Subtracts the first $25 a month ($300 a year) once from the household's adult interest. The manual does not say whether the disregard repeats per person or per account.
TANF FY2025 and FY2026 plans section 1.9, page 6 Counts the take-up-gated tanf aggregate, which includes ga_tanf, once per household.
Lottery winnings Manual section 1200.7, page 66 Counts gambling_winnings, the closest input; it also covers non-lottery gambling (see source conflicts).
Cash gifts and contributions Manual section 1200.7, page 65 Counts adults’ cash support through the existing financial_assistance input; receipts of members under 18 are excluded.

Benefit

Primary heating fuel Level I Level II
Electricity $500 $400
Natural gas $660 $560
Fuel oil $810 $710
Propane $680 $580
Wood $500 $400
  • The FY2025 and FY2026 matrices print the same amounts. Level I cutoffs are inclusive: one person $12,995 (FY2025) and $13,589 (FY2026); four people $24,355 and $25,469; sixteen people $40,485 and $42,336. Households above size 16 use the size-16 cutoff.
  • Every printed Level I amount equals the Level II amount plus $100 on both matrices. The model stores the Level II column and the $100 difference, an inferred pattern that reproduces all ten printed cells.
  • An unsubsidized renter whose rent includes all utilities and who reports no separate bill is paid directly at the lowest award for the income level, $500 in Level I or $400 in Level II (FY2026 plan page 30; manual page 89), whatever the fuel, including an unpriced or unspecified one. Manual page 57 limits this class to rent that "includes utilities with no separate bill for heating/cooling costs". A reported electric bill or a bill for the main heating fuel puts the renter on a vendor payment instead, even when tenant_pays_utilities is false.
  • A renter with heat in rent who is billed for electricity is paid the amount for the main heating fuel, to the electric vendor (manual pages 4 and 89). The FY2024 matrix explains the asterisk on "main heating fuel type*": "The main fuel type is not always where the benefit is applied", so a natural gas household that applies its benefit to an electric bill receives the natural gas amount. A one-person household with natural gas heat in rent, a $1,200 electric bill and $12,000 of wages receives $660 in FY2026, with or without a housing subsidy and whatever tenant_pays_utilities says.
  • A renter with heat in rent who reports a bill for the main heating fuel is paid that fuel's amount to the vendor (manual page 89, first row, "Paid to vendor"). With tenant_pays_utilities false, a $1,200 bill and $12,000 of wages in FY2026, natural gas pays $660 with or without a subsidy, fuel oil $810 and propane $680.
  • Kerosene, coal, solar, other and unspecified fuels have no matrix column, so every vendor payment for them is $0. An unsubsidized renter whose rent includes all utilities, with one of these fuels and $12,000 of wages, receives $500 in FY2026 with no separate bill and $0 once it reports an electric bill or a bill for its main heating fuel.
  • The reported bill does not cap the payment.
  • PAMMS chapter 100 (page 5) still prints benefits of "a minimum of $350 and maximum of $400" with a senior maximum. FY2026 plan item 16.1 (page 30) says Georgia updated the benefit matrix to remove the senior rule, so the model follows the matrix.

Years covered

Model year Program year One-person income limit One-person Level I cutoff
2025 FY2025, from October 1, 2024 $33,038 $12,995
2026 FY2026, from October 1, 2025 $34,549 $13,589

A calendar-year period reads the parameters in force on January 1. Formulas are undated and verified_years is "2025-2026". Other years are unverified backfilled estimates; no adopted FY2027 table was found, only a draft plan. The 110% poverty floor applies from size 16 in FY2025 and FY2026, and from size 17 in the carried-forward 2027 estimate.

Not modeled and source conflicts

Item Source Model treatment
Categorical eligibility for households receiving only public assistance Manual Requires every member's receipt and assistance-only income and resources; aggregate TANF and SNAP inputs cannot establish those facts.
Utility account credits of $1,000 or more and administrative household exclusions Manual Not identified; the selected heating account is assumed to meet them.
Level I cutoff above household size 16 FY2026 matrix, step 1 Uses the size-16 cutoff as a provisional value.
Printed size-16 income limit below the federal floor FY2025 matrix step 1, size 16 ($102,926); FY2026 matrix step 1, size 16 ($107,634); 42 U.S.C. 8624(b)(2)(B); FY2025 and FY2026 plans, assurance 2 (page 43) Both plans assure that Georgia "may not exclude a household from eligibility in a fiscal year solely on the basis of household income if such income is less than 110 percent of the poverty level for such State". The floor governs: a size-16 household qualifies below $105,336 (FY2025) or $107,965 (FY2026). ga_liheap_income_limit keeps the printed table.
Kerosene, coal, solar, other and unspecified fuels on vendor payments FY2026 matrix, step 2 Pay $0 as a coverage gap (#9754 for unspecified fuel), on every vendor route. Only the direct payment with no separate bill pays them the lowest award.
Military Survivor Benefit Plan annuities entered in military_retirement_pay_survivors Manual section 1200.7, pages 65–66 ("Annuity", "Pension"); #10182 Not counted. A cross-state follow-up PR will count survivor annuities the same way in every LIHEAP state.
Other direct payments to the applicant FY2026 plan item 16.1 (page 30); manual page 89 (fourth and seventh rows), page 4 and section 1300.2 (page 70) Plan item 16.1 pays the lowest award when the benefit goes to the applicant. The manual also pays the applicant directly when utilities are paid to "the landlord or trailer park owner" and when the energy supplier has no vendor agreement or is not on the Approved Vendor List; subsidized tenants who pay "a landlord for utility costs" are paid directly or through the electric supplier. No input identifies these households; the model pays them the main-fuel amount when they report a bill.
Roomer and boarder allowances, mortgage-sale contracts and stipends Manual section 1200.7 Not handled.
Roomers, boarders, foster-child elections and group quarters Manual pages 51–52 Not identified; the SPM unit approximates the household.
Lawful noncitizens in household size Manual sections 101.2 (page 3), 1100.3 (page 50) and 1100.5 a (page 51) against 1100.14 (page 57) and the glossary (page 76) The manual conflicts with itself: page 57 lists "Applicants where ALL household members are non-U.S. citizens" as ineligible, and the glossary leaves non-citizens out of the size while counting their income. The model follows the eligibility sections: lawful immigrants count in the size, undocumented members do not, and a household of lawful immigrants can qualify.
Crisis, cooling, weatherization and equipment assistance — Out of scope.
Topic State plan Manual and model
Lottery winnings FY2025 and FY2026 plans, section 1.9 (page 6), leave one-time lump sums such as winnings from lotteries unchecked The January 2022 manual, section 1200.7 (page 66), includes "Lottery Winnings". The model follows the manual and counts gambling_winnings, which also covers non-lottery gambling.
Cash gifts FY2025 and FY2026 plans, section 1.9 (page 6), leave cash gifts unchecked The manual, section 1200.7 (page 65), includes "Contribution/Cash Gift"; the model counts adults’ receipts through financial_assistance. The contemporaneous FY2022 plan already has the same unchecked checkbox, so it does not establish a later exclusion. The detailed income manual is followed.
Disability payments and workers' compensation FY2025 and FY2026 plans, section 1.9 (page 6), leave "Insurance payments made directly to the insured" unchecked The manual, section 1200.7, includes "Disability Payment" (page 65) and "Workers Compensation" (page 68). The model follows the manual and counts both.
Subsidized renters and utilities in rent FY2026 plan, section 2.3 (page 8), answers No to "additional/differing eligibility policies" for "Renters Living in subsidized housing?" and "Renters with utilities included in the rent?" The manual applies energy-burden rules to both (pages 4, 57, 82 and 89), for example "Subsidized housing residents whose fuel cost is included in their rental payment are not eligible for assistance unless the applicant can verify an energy burden" (page 4). The model follows the manual.

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

65 YAML cases in 6 files cover:

  • all 16 FY2026 income limits, FY2025 limits for sizes 1, 4 and 16, a mixed Georgia and Alabama array, and a $0 limit for a unit with no qualified member;
  • all 16 FY2026 Level I cutoffs, FY2025 cutoffs for sizes 1, 4 and 16, and sizes 17 and 25 at the size-16 cutoff;
  • all five priced fuels at both levels, a small bill that does not cap the award, and no heat;
  • each energy-burden route: a primary bill with heat in rent with and without a subsidy, an obligation with no bill, an unrelated utility bill, all utilities in unsubsidized rent (including unspecified fuel and each requirement that fails it), and heat in rent with an electric bill, with and without a subsidy, by main fuel, income level and missing rent or bill;
  • renters with heat in rent, tenant_pays_utilities false and a $1,200 electric bill: natural gas pays $660 and $560 to an unsubsidized renter with $12,000 and $24,000 of wages and $660 to a subsidized renter, an unsubsidized renter with an unspecified main fuel is eligible at $0, and the subsidized renter without the bill is ineligible;
  • the same renters with a $1,200 bill for the main heating fuel instead of the electric bill: natural gas pays $660 with or without a subsidy and $560 at $24,000 of wages, fuel oil $810 and propane $680;
  • kerosene heat in unsubsidized rent: $500 with no separate bill, $0 with a kerosene bill (whether tenant_pays_utilities is true or false) or an electric bill, and the same precedence at the matrix-amount level for an electric, gas and kerosene bill;
  • the under-18 boundary at 17 and 18, nonqualified adult income, the $300 interest boundary, TANF counted once and with and without take-up, Social Security net of the Part B premium and its floor, military and gross railroad retirement, and self-employment, capital, rental and farm losses;
  • the eight remaining adult sources (unemployment, veterans' benefits, disability, workers' compensation, strike benefits, General Assistance, alimony and child support) at $100 to $800 each, $3,600 in total;
  • unemployment compensation at Georgia's $365 maximum weekly benefit amount (WBA), up to the 14 x WBA maximum benefit (14 x $365 = $5,110; USDOL, January 2026), which moves a one-person household with $12,000 of wages from the $500 Level I electric award to the $400 Level II award;
  • the FY2025 Level I cutoff in a final award and a 17-person household;
  • a 17-person household whose four adults earn Georgia's median wages for cashiers and for fast food and counter workers (BLS OEWS, May 2025), $111,980 in total: above the $109,627 limit and below the $114,015 poverty floor, so it receives Level II natural gas, $560. With one adult undocumented, the Georgia size falls to 16 (SPM size 17) and the floor to $107,965, so the same $111,980 makes the household ineligible;
  • threshold edges at the federal poverty floor, with income entered directly: size 16 is eligible at $107,964.99 and ineligible at $107,965 in FY2026 (limit $107,634), and eligible at $105,335.99 and ineligible at $105,336 in FY2025 (limit $102,926). Two ineligible rows would qualify without the guideline lag: size 17 at $115,000 in FY2026 (floor $114,015; $117,524 with the 2026 guidelines) and size 16 at $106,000 in FY2025 (floor $105,336; $107,965 with the 2025 guidelines);
  • adult cash contributions, excluded minor gifts, and FY2025/FY2026 final benefits at $12,000, $24,000 and $36,000 of cash support.

Every eligibility and payment case specifies heating_type. The isolated household-size, income and income-limit cases set no heating inputs, which those variables do not read; income Case 8 keeps heating_type because it also asserts the matrix amount. Expected values come from hand arithmetic on the sources. The current head was not run locally; CI validates it.

  • YAML tests whose expected values come from an external source (statute, official form or worksheet, official calculator)
  • Source-conflict register entry and marker: the one statute-side reading is the 110% floor, which follows 42 U.S.C. 8624(b)(2)(B) over the printed size-16 limits. It is backlog item us-ga:liheap-income-floor-vs-smi-limit in source_conflicts/candidates.yaml. A marker can name only a registered entry, so the floor line in ga_liheap_eligible takes its marker once rulespec-us registers the entry. The lawful-noncitizen question (us-ga:liheap-lawful-noncitizen-household-members) sets the manual against itself, and 42 U.S.C. 8622(5) defines a household with no citizenship rule. The plan-versus-manual rows above have no statute side either, so neither needs a marker.
  • make format
  • Changelog fragment in changelog.d/

axiom: TheAxiomFoundation/rulespec-us#1533 queued

🤖 Generated with Claude Code

hua7450 and others added 6 commits October 3, 2026 19:49
…income

- Add the published FY2025 Level I income cutoffs for sizes 1-16.
- Make renters whose heat is in rent and who are billed for electric
  eligible (manual p89 row 3; p4 for subsidized renters with the bill in
  their name), paid the matrix amount for the main heating fuel.
- Count Social Security net of the Medicare Part B premium; count military
  and railroad retirement; floor each income source at zero; read
  take-up-gated tanf instead of ga_tanf.
- Shorten the registry note; set verified_years to 2025-2026.
- Add period-2025, heat-in-rent, income-source and branch cases; tidy test
  comments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The manual's income table (section 1200.7) includes lottery winnings and
cash gifts; plan section 1.9 leaves both unchecked. Follow the manual:
count gambling_winnings as the closest input for lottery winnings, and note
that cash gifts have no input. Also note the same plan-versus-manual
conflict for disability payments and workers' compensation, which the
manual counts (pages 65 and 68) and the model already follows.

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 (a9dae48).
⚠️ Report is 579 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9968   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         7    +3     
  Lines           76       112   +36     
  Branches         2         1    -1     
=========================================
+ Hits            76       112   +36     
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
Quote manual 1100.14 (page 57) and the glossary (page 76) against 101.2, 1100.3 and 1100.5 a; the code keeps counting lawful immigrants in the size.

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. Also cite manual section 1100.4 (not 1100.5 a) for the undocumented-adults sentence in the household-size comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450 and others added 2 commits October 11, 2026 23:45
Calls liheap_smi_limit from PR 10019 instead of repeating the HHS
floor-then-floor calculation. Limits are unchanged.

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

DTrim99 commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Add Georgia LIHEAP regular heating assistance

PR #9968: Add Georgia LIHEAP regular heating assistance (author: hua7450, head 50aaa0096e)

Scope: Georgia's LIHEAP regular heating assistance, run by DFCS through Community Action Agencies, for FY2025 and FY2026. The PR covers:

  • household size, which counts citizens and qualified noncitizens (undocumented and DACA members are left out, but their income counts), and countable income, which counts members 18 and over, with Social Security net of the Part B premium, a $25-a-month interest disregard and per-source loss floors;
  • the income limit at 60% of state median income, through the shared liheap_smi_limit helper;
  • the Benefit Matrix: Level I or Level II by the printed cutoffs for sizes 1-16 in FY2025 and FY2026, and the step 2 amount for five fuels;
  • the energy-burden test, including heat in rent and subsidized housing; the lowest award for unsubsidized renters whose rent includes all utilities (plan item 16.1); and the main-fuel award, paid to the electric vendor, for heat-in-rent renters billed for electricity.

Cooling, crisis, weatherization, categorical eligibility and the $1,000 account-credit screen are out of scope. The PR changes 24 files: 9 parameters, 6 variables plus a helper module, 6 test files (54 cases), programs.yaml and a changelog fragment. Every parameter has a single 2025-10-01 value except the Level I cutoffs (2024-10-01 and 2025-10-01). The tests use periods 2026 and 2025, and the registry lists verified_years: "2025-2026".

Overall: the FY2025 and FY2026 policy values are right.

  • All 10 step 2 amounts and all 32 printed Level I cutoffs (16 per year) match the two matrices, and all 32 printed income limits reproduce with the HHS floor-then-floor method.
  • The income rules follow the manual's Include/Exclude table. Social Security is counted net of the Part B premium, which is right for Georgia: plan item 1.9 checks "Excluding MediCare deduction" in the FY2022, FY2025 and FY2026 plans and the FY2027 draft, and the manual excludes "Health Premiums" (p69). That is the counterpart of Alabama's "Including" box, read as gross in Add Alabama LIHEAP regular heating assistance #9967.
  • The heat-in-rent routes follow the manual's energy burden table (p89) and plan item 16.1. A note on the FY2024 matrix, which the PR does not cite, backs the main-fuel amount on the electric route (G3).
  • The plan-versus-manual choices (lottery winnings, cash gifts, disability and workers' compensation) are documented and defensible: the FY2022 plan, which covers the program year in which the manual was revised, already leaves the same boxes unchecked.

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

  • S1: a merge blocker from main's Integrate modeled state unemployment insurance into income flows #9558. The person source list reads the raw unemployment_compensation input, so main's new code-health guard fails on the merged tree. Georgia has no modeled unemployment insurance yet, so no household value changes today.
  • S2: eight of the 24 person income sources are never nonzero in any test, including two that the PR defends against the plan, and two smaller pieces of logic are also unpinned.
  • S3: six parameter descriptions fall outside the house template.

All 54 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. Values that a proposed fix or an earlier year's schedule would produce are hand computations and are labelled as such. The untested-logic claims in S2 were confirmed by mutating the code and rerunning the PR's tests.

Path prefixes used below:

  • P/ = policyengine_us/parameters/gov/states/ga/dfcs/liheap/
  • V/ = policyengine_us/variables/gov/states/ga/dfcs/liheap/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/ga/dfcs/liheap/
  • M = Georgia LIHEAP Policy Manual, revised January 2022 (PDF page = printed page)

Line numbers refer to head 50aaa0096e.

Source Documents

# Document Link Use
1 FY2026 Georgia LIHEAP State Plan (47 pp, report period 10/01/2025-09/30/2026, "Submission Accepted by CO") GA_Plan_2026.pdf 1.1 dates (p4); 1.4 Yes, 1.8 Gross Income, 1.9 (p5-7); 2.1 60% SMI, 2.2-2.3 (p8); 2.5 with the $1,000 credit rule, 2.6 $400 / $810 (p9); 16.1 lowest benefit for direct payment (p30). The text layer lacks the checkbox states, so the rendered pages were read
2 FY2025 plan (Revision #2) GA_Plan_2025.pdf 1.9 "Excluding MediCare deduction", cash gifts and lottery unchecked (p6); 2.1 (p8); 2.6 $400 / $810 (p9); the same 16.1 sentence (p30)
3 FY2022-FY2024 plans FY2022, FY2023, FY2024 FY2022 1.9 boxes (p6); 2.6 ranges $350-$450, $350-$500 and $400-$810 (p9); FY2024 16.1 (p30)
4 Draft FY2027 plan (report period 10/01/2026-09/30/2027, status "Saved") DFCS download Heating 12/01/2026-07/31/2027 (p4); the same 1.9 boxes (p6); 60% SMI (p8); $400 / $810 (p9); the same 16.1 sentence (p30). It has no matrix
5 M (89 pp) GA_PolicyManual_2023.pdf 101.2 (p3-4); 1100.3-1100.5 (p50-52); 1100.12, 1100.14 (p56-57); 1200.1-1200.7 (p62-69); 1300.2 (p70); glossary (p75-76); application items (p81-85); energy burden table (p89). The Include/Exclude columns were read from the rendered pages
6 FY2026 and FY2025 Benefit Matrices (1 p each) FY2026, FY2025 Step 1 Level I and Level II ranges for sizes 1-16; step 2 heating amounts
7 FY2024 Benefit Matrix and FY2023 Eligibility Guidelines (1 p each) FY2024, FY2023 Not cited in the PR. FY2024: the same step 2 amounts, Level I tops of $11,687-$36,411, and the "*Important! The main fuel type is not always where the benefit is applied" note (G1, G3). FY2023: flat $450 / $350 / $500 for all fuels (G1)
8 DFCS PAMMS LIHEAP export (dated 2026-10-07) liheap.pdf Chapter 100 (effective October 2020): the three requirements and "vendor bill/statement for the main heating source" (p4); the stale "$350 ... $400" benefit text (p5). It holds chapters 100-800 only, with no income chapter
9 DFCS LIHEAP page (modified 2026-09-28) dfcs.georgia.gov FY2027 heating opens December 1 for residents 65 and older or homebound and January 2 for everyone; "U.S. citizen or legally admitted immigrant"; the $1,000 credit rule

Critical (Must Fix)

None.

Should Address

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

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

S2. Eight income sources and two smaller pieces of logic have no test that would fail if they broke

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

  1. Eight person sources. unemployment_compensation (line 13, which S1 replaces), veterans_benefits (26), disability_benefits (31), workers_compensation (32), strike_benefits (33), general_assistance (34), alimony_income (48) and child_support_received (49) in P/income/sources/person.yaml are never nonzero in any test, so deleting all eight passes.
    • Three are deliberate choices. The PR counts disability_benefits and workers_compensation per M p65 ("Disability Payment") and p68 ("Workers Compensation"), against plan 1.9's unchecked "Insurance payments made directly to the insured". general_assistance is a checked plan category. The PR body's conflict table defends the first two, but no case pins them.
    • Pin all eight with one case: an adult with $100 of unemployment compensation, $200 of veterans' benefits, $300 of disability benefits, $400 of workers' compensation, $500 of strike benefits, $600 of general assistance, $700 of alimony and $800 of child support. Reproduced at head: ga_liheap_income 3,600, and with electric heat ga_liheap $500. The same case fails under the mutation, since none of its income would count.
  2. The tenant_pays_utilities conjunct of the electric-vendor route (V/eligibility/_ga_liheap_housing.py:38). It separates that route from the all-utilities-in-rent route. For unsubsidized renters both routes make the household eligible and the direct route sets the amount, so the conjunct matters only for subsidized renters. No case has a subsidized renter with tenant_pays_utilities false and an electric bill, so replacing the conjunct with True passes all 54 cases.
    • Reproduced at head: a subsidized renter with $12,000 of wages, natural gas heat in rent, rent $3,000, tenant_pays_utilities false and a $1,200 electric bill is ineligible. That case fails under the mutation; by the formula the household becomes eligible for the natural gas Level I amount, $660 (hand-computed).
    • The input is unusual: the tenant_pays_utilities documentation says to set it false "when utilities are included in rent", yet the household reports an electric bill. Either pin the current result with that case, or drop the conjunct, since a positive electric bill already shows that "their utility bill is in their name" (M p4).
  3. The size-0 mask on the income limit (V/eligibility/ga_liheap_income_limit.py:23, where(size > 0, limit, 0)). Returning the unmasked limit passes all 54 cases. Without the mask, a unit with no qualified member gets the size-1 limit: the HHS size factor at size 0 is 0.52, so floor(66,441 x 0.52) = $34,549 (hand-computed). Eligibility still gates on size > 0, which T/eligibility/ga_liheap_eligible.yaml Case 2 pins, so only the limit variable changes. No case asserts the limit for a size-0 unit. Add ga_liheap_income_limit: 0 to T/ga_liheap_household_size.yaml Case 2 (reproduced at head: 0; that assertion fails under the mutation).

By inspection, the other branches are pinned: each energy-burden arm, each conjunct of the all-utilities-in-rent route (T/eligibility/ga_liheap_eligible.yaml Case 7 changes one at a time), the eligibility size gate, both NONE checks, the 32 Level I boundaries, the size-16 cap, the per-source floors, the Social Security net and floor, the interest disregard and mask, and the TANF read. Two control mutations confirm the method: dropping the electric route's heat-in-rent conjunct fails T/ga_liheap.yaml Case 14, and dropping heating_type != NONE fails T/eligibility/ga_liheap_eligible.yaml Cases 4 and 7. Consistency: #9967 S3 and #9972 S3 rated untested logic SHOULD, and #9745 G7 suggested the all-sources case.

S3. Six parameter descriptions fall outside the house template

All nine descriptions end with "under the Low Income Home Energy Assistance Program." with nothing after it, which is right. The template's verbs are limits, provides, sets, excludes, deducts and uses. Six descriptions use other verbs:

File:line Current Suggested
P/income/minimum_age.yaml:1 "counts household members' income starting at this age" "Georgia excludes the income of household members below this age under the Low Income Home Energy Assistance Program."
P/income/monthly_interest_disregard.yaml:1 "disregards this amount of monthly interest income" "Georgia excludes this amount of monthly interest income under the ..."
P/income/sources/household.yaml:1 "counts these household benefits once" "Georgia uses these household-level benefits as countable income under the ..."
P/income/sources/person.yaml:1 "counts these income sources of adult household members" "Georgia uses these sources as countable income of adult household members under the ..."
P/payment/lower_income_uplift.yaml:1 "increases the heating payment by this amount for households in income Level I" "Georgia provides this additional heating payment to households in income Level I under the ..."
P/payment/maximum_table_size.yaml:1 "publishes Level I income thresholds through this household size" "Georgia sets Level I income thresholds through this household size under the ..."

The other three fit: smi_rate and lower_income_limit (limits) and base_amount (provides). Consistency: #9967 S4, #9972 S4 and #9745 S6.

Suggestions

G1. Backfilled years: FY2024 is published and could be claimed; FY2023 and earlier paid a different schedule

  • Every single-dated parameter carries back to every earlier period, and the Level I cutoffs carry the FY2025 values back. The registry claims only 2025-2026 and the PR body calls other years "unverified backfilled estimates", so this is a suggestion (checklist item 3).
  • FY2024 differs only in the cutoffs:
    • The FY2024 matrix prints the same ten step 2 amounts and Level I tops of $11,687 / 15,283 / 18,879 / 21,904 / 26,072 / 29,668 / 30,342 / 31,016 / 31,691 / 32,365 / 33,039 / 33,713 / 34,388 / 35,062 / 35,736 / 36,411.
    • The FY2024 plan has the same $400 / $810 range (p9) and the lowest-benefit sentence (p30).
    • The limits reproduce from the repo's FY2024 median, $95,238: floor(floor(95,238 x 0.6) x 0.52) = 29,713, the printed "$29713".
    • Reproduced: period 2024, one adult with $12,000 of wages and electric heat gets limit 29,713 and an award of $500. FY2024's size-1 Level I range is "$0 - $11687", so FY2024 paid $400 (hand-computed).
    • Add a 2023-10-01 entry for each size and set verified_years: "2024-2026".
  • FY2023 and earlier paid a different schedule. The FY2023 guidelines pay "Level I $450", "Level II $350" and "Level III (vulnerable population) $500" (households with a member aged 60 or over), "for All Fuel Types".
    • Reproduced: period 2023, one adult with $12,000 of wages and natural gas heat gets $660 at age 40 and at age 70. FY2023 paid $450 and $500. The limit, 28,058, does match FY2023's "$28,058".
    • Either gate payments before FY2024 (merged NJ uses eligibility/in_effect.yaml), or keep the documented backfill.
  • Also cite the FY2025 documents where FY2025 values come from the 2025-10-01 entry by backward extrapolation. P/payment/base_amount.yaml, P/payment/lower_income_uplift.yaml and P/payment/maximum_table_size.yaml cite only the FY2026 matrix, and P/eligibility/smi_rate.yaml cites only the FY2026 plan. The FY2025 matrix and the FY2025 plan, p. 8 show the same values for the claimed FY2025.

G2. Fuels and routes that are eligible but paid $0

  • Reproduced at head (period 2026, $12,000 of wages and a $1,200 bill for the fuel): KEROSENE, COAL and SOLAR each give ga_liheap_eligible: true and ga_liheap: 0.
    • KEROSENE: heating_expense reads fuel_oil_expense for it, so the matrix's "OIL" row is the natural column.
    • SOLAR: heating_expense reads the electric bill ("Solar-primary homes are assumed grid-tied with electric supplemental heat"), so the ELECTRIC row fits.
  • UNSPECIFIED on the electric-vendor route is eligible but gets $0 (T/ga_liheap.yaml Case 16, unit 4). The heating_type documentation calls UNSPECIFIED "the right value when heat is included in rent and the fuel is unknown", so it is the usual input for a renter on that route. Either pay a defined amount when the fuel is unknown (for example the ELECTRIC amount, since the payment goes to the electric vendor), or make eligibility match the $0.
  • The PR documents these as coverage gaps. Add a # See #9754 note at V/payment/ga_liheap_matrix_amount.py:46 (Add New Jersey LIHEAP regular heating assistance #9745 G1, Add Alabama LIHEAP regular heating assistance #9967 G2).

G3. Cite the FY2024 matrix note and the current DFCS documents

  • The FY2024 matrix explains the asterisk on "main heating fuel type*": "*Important! The main fuel type is not always where the benefit is applied. Example: A household is in the Level 1 income range. They heat their home with Natural Gas, and bring in both a Gas and Electric bill. Since they heat their home with Natural Gas , the household is eligible for a Natural Gas benefit -- even if they opt to apply all of their benefit toward their electric bill." The FY2025 and FY2026 sheets keep the asterisk but drop the note.
    • That backs paying the main-fuel amount on the electric-vendor route (V/eligibility/_ga_liheap_housing.py:20-41, V/payment/ga_liheap_matrix_amount.py:48-58). Cite it there and in the PR body. rulespec-us#1533 interpretation 6 says neither sheet prints a footnote.
  • PAMMS chapter 100, p. 4 (export dated 2026-10-07) is the current DFCS text of M section 100.
    • "Be US citizens or lawfully admitted immigrant" supports the household-size reading over M p57's "Applicants where ALL household members are non-U.S. citizens". The DFCS LIHEAP page also says "The applicant needs to be a U.S. citizen or legally admitted immigrant."
    • "Applicants who receive a vendor bill/statement for the main heating source are eligible for assistance" supports T/eligibility/ga_liheap_eligible.yaml Case 5, where an unrelated bill does not count. M p4 says only "from their energy source".
    • The same chapter still prints "a minimum of $350 and maximum of $400", with a senior maximum (p5). Plan 16.1 (p30) says the updated matrix removed the senior rule, so the matrix governs. Say so in the PR body.

G4. Encode the printed Level I column, and consider exposing the two routes as variables

  • P/payment/base_amount.yaml stores Level II, and P/payment/lower_income_uplift.yaml adds $100 for Level I. That reproduces all ten printed cells, but the sheets print two columns, not a rule. np.minimum.reduce(base_amounts) (V/payment/ga_liheap_matrix_amount.py:56) also gives the right Level I lowest amount only while the gap is the same for every fuel. Encoding the printed Level I column (a level-by-fuel breakdown) removes both assumptions (Correct the qualified_business_income variable formula #1533 interpretation 5).
  • The two routes in V/eligibility/_ga_liheap_housing.py are helper functions, so no YAML case can assert them. Boolean variables would let the route cases assert the route directly. This is optional.

G5. PR body: other direct-pay cases, a conflict-table row and small corrections

  • Plan 16.1 pays "the lowest benefit amount" whenever "the benefit goes directly to the applicant". Besides rent that includes all utilities, M pays the applicant directly in three more cases:
    • utilities paid to "the landlord or trailer park owner" (p89 row 4);
    • subsidized tenants who pay "a landlord for utility costs" (p89 row 7, "Direct pay to applicant (999) or to electric supplier");
    • households "whose energy suppliers have not signed a vendor supplier agreement" (p4; 1300.2, p70).
      No input identifies them, and the model pays the main-fuel amount when they report a bill. Add a row to the not-modeled table; rulespec-us#1533 interpretation 7 already has it.
  • Add a conflict-table row: plan 2.3, p. 8 answers "No" for "Renters Living in subsidized housing?" and "Renters with utilities included in the rent?", while M applies energy-burden rules to both (p4, p57, p82, p89). Add Alabama LIHEAP regular heating assistance #9967 G6 and Add Rhode Island LIHEAP regular heating assistance #9972 G6 made the same point.
  • "Every case specifies heating_type" is not quite right: T/income/ga_liheap_income.yaml Case 14 (line 463) has none. rulespec-us#1533 says so correctly.
  • Plan item 1.9 continues on p7 (stipends, foster-care funds, AmeriCorps payments, reimbursements and "Other", all unchecked). The title at P/income/sources/person.yaml:57 ("#page 5-6") and the # PDF pages 5-6 comment at V/income/ga_liheap_income.py:15 could read 5-7. Every encoded category is on pp. 5-6, so this is polish.

G6. Test hygiene, FY2027 and issue housekeeping

  • hud_utility_allowance: 0 appears nine times in T/ga_liheap_household_size.yaml and T/income/ga_liheap_income.yaml, but no Georgia variable reads it. The isolated limit and income tests also set fuels and bills that those variables never read, and the matrix-amount tests set fuel bills that ga_liheap_matrix_amount never reads.
  • FY2027: the draft plan keeps 60% SMI, $400 / $810 and the 16.1 sentence, and DFCS has not published an FY2027 matrix. Period 2027 therefore carries the FY2026 cutoffs (reproduced: one-person limit $35,916 from the FFY2027 median, and $500 at $12,000 of wages). The printed cutoffs track about 23.6% of the four-person median times the size factor (see Verified correct), so the FY2027 cutoffs will probably rise; on that pattern the size-1 top would be about $14,127 (a hand projection, not a published value). Add the FY2027 matrix when DFCS publishes it.
  • rulespec-us#1533 still calls the PR "open as a draft".

Verified correct

  • Matrix (FY2026, FY2025):
    • Step 2 amounts: ELECTRIC $500 / $400, NATURAL GAS $660 / $560, OIL $810 / $710, PROPANE $680 / $580, WOOD $500 / $400. Level I is Level II plus $100 for every fuel, and plan 2.6's $400-$810 range matches.
    • Step 1: all 16 Level I tops in each year ($13,589 ... $42,336 and $12,995 ... $40,485), inclusive. Sizes above 16 use size 16, which the PR documents as provisional.
    • The printed tops track floor(four-person SMI x 0.236 x size factor), with 0.23 at size 4, in all 32 FY2025-FY2026 cells and 13 of the 16 FY2024 cells. The odd size-4 value therefore recurs every year, and keeping the printed table, with the PR's comment, is right.
  • Limits: all 16 FY2026 limits (34,549 ... 107,634) and all 16 FY2025 limits (33,038 ... 102,926) reproduce as floor(floor(0.6 x SMI) x size factor), with four-person SMIs of $110,736 and $105,893. The limit is inclusive ("at or below", M p50; T/eligibility/ga_liheap_eligible.yaml Case 1).
  • Timing: heating runs 12/01/2025-07/31/2026 (plan 1.1, p4), so period 2026 (January 1, 2026) reads FY2026 and period 2025 reads FY2025.
  • Income (plan 1.8 gross; M 1200.1-1200.7, p. 62-69):
    • Members under 18 are excluded entirely (p62), and nonqualified adults' income counts (p51, p62).
    • Every listed source has a basis in the Include column (rendered pages) or in plan 1.9: capital gains, alimony, child support, contribution/cash gift, disability payment and dividends (p65); farm income, interest, lottery winnings, pension and rental income (p66); RSDI, strike benefits, SSI, TANF, unemployment compensation, veterans' benefits and wages (p67); workers' compensation (p68); self-employment (1200.6, p64); general assistance and retirement benefits (plan 1.9). SNAP, tax refunds, HUD utility allowances and LIHEAP are excluded and not listed.
    • Social Security is counted net of Part B (plan 1.9 "Excluding MediCare deduction"; M p69 "Health Premiums") and floored at zero. Railroad retirement is gross.
    • Interest: "The first $25.00 in interest is disregarded" (p66), and interest "amounting to $25.00 or less per month" is excluded (p69). Applying it once per household is a documented reading.
    • Losses are floored per source. TANF comes through the take-up-gated tanf. financial_assistance ("Cash financial assistance from friends or relatives outside the household") matches "Contribution/ Cash Gift".
  • Household: size counts citizens and the 8 U.S.C. 1641 qualified statuses. Undocumented adults' income counts and they are left out of the size (M 1100.4, p51; 1100.5 b note, p52). DACA is not on the p51 list.
  • Eligibility:
    • Georgia residence. No asset test (plan 2.3 No).
    • Categorical eligibility (plan 1.4 Yes; M 1100.12) is not applied, which is harmless: a household whose only income is SSI, TANF or SNAP is far below 60% SMI, and plan 1.6 says the benefit is the same.
    • Energy burden:
      • the household's own obligation or a bill for the primary fuel qualifies (M p3, p50, p4);
      • unsubsidized rent that includes all utilities qualifies (p89 row 2);
      • heat in rent with an electric bill qualifies with or without a subsidy (p89 row 3; p4 "if their utility bill is in their name");
      • subsidized heat in rent with no bill fails (p57, p82, p89 row 5);
      • NONE fails.
  • Payment:
    • Direct payment pays the level's lowest amount, $500 or $400 (plan 16.1, p30; p89 row 2 "Direct pay to Applicant (999)").
    • The electric route pays the main-fuel amount (FY2024 note, G3).
    • No bill cap: plan 2.5 leaves "Individual bill" unchecked.
  • Code patterns:
    • No hard-coded values. defined_for = StateCode.GA on five variables, and ga_liheap is gated by ga_liheap_eligible.
    • Vectorized formulas. All 9 parameters are read, and the shared liheap_smi_limit helper is reused.
    • Mixed Georgia and Alabama arrays mask correctly.
  • Tests:
    • 54 of 54 pass locally at head (policyengine-core 3.32.29) and on the merged tree. Periods are plain.
    • Hand-checked against the matrices, plans and manual:
      • T/ga_liheap.yaml Cases 1, 4, 9-17 and 19;
      • income Cases 1-6, 9 and 12;
      • all 32 Level I boundary pairs and all 10 fuel cells;
      • all 16 FY2026 limits and the three FY2025 limits;
      • household size Case 1.
  • Changelog: changelog.d/ga-liheap.added.md is top level and typed added.

Checklist results (LIHEAP wave 2a)

  1. State plan and manual first: pass. I read the accepted FY2026 and FY2025 plans (rendered checkboxes), the FY2022-FY2024 plans, the FY2027 draft, M (rendered Include/Exclude columns and energy burden table), the FY2023-FY2026 matrices, the PAMMS export and the DFCS page. I verified every encoded amount, cutoff, limit and route.
  2. Income definition: pass at head. Gross income per plan 1.8 and M 1200.7; Social Security net of Part B per plan 1.9 and M p69; losses floored per source; annual income standing in for the monthly test. After rebase the list must read total_unemployment_compensation (S1).
  3. Backdating: FY2025 is claimed and correct. FY2024 is published with different cutoffs, and FY2023 used a different schedule; both are unclaimed and documented (G1). No FY2027 matrix is published (G6).
  4. Household and arrangement rules: pass on subsidized and public housing, heat in rent (both routes), renters, categorical eligibility (a harmless omission) and the elderly priority (timing only). Eligible-but-$0 fuels are in G2; the other direct-pay cases are in G5.
  5. Tests: 54 cases, more than 8 hand-checked. Limits for sizes 1-16, cutoffs for sizes 1-16 with one-cent pairs, the limit edge and plain periods are covered. Gaps are in S2.
  6. Parameter descriptions: six fall outside the template (S3). There are no trailing clauses.
  7. References: pass. Every anchor is a file page that shows the value, and multi-page titles use #page 66,69, #page 62-69,83 and #page 5-6 (item 1.9 runs onto p7, G5).
  8. Wiring: pass. The programs.yaml entry and coverage line are well formed. No aggregate wiring, which matches OR, NY, NJ and MD on main (none of them is in household_state_benefits). defined_for gating is on every variable. No take-up beyond TANF's.
  9. Axiom: valid queued line. rulespec-us#1533 is open, labelled pe-parity, dispatch-ready and current to 50aaa0096e. It needs updates for S1-S2 (see below).
  10. Branch and CI: all checks are green at head. 12 ahead and 82 behind main. No textual conflicts, but main's UI guard fails on the merged tree (S1).
  11. Integrate modeled state unemployment insurance into income flows #9558: S1. No modeled Georgia UI exists, so the effect today is the guard failure only.
  12. IIJA and FY2027: no IIJA supplement. None of the FY2022-FY2026 plans, the FY2027 draft or M mentions one, and the matrices print one amount per fuel and level. The FY2027 draft keeps 60% SMI, $400-$810 and the 16.1 sentence (G6).
  13. Mutation check: S2. Two control mutations fail as expected.

CI status

28 of 28 checks pass at 50aaa0096e (gh pr checks 9968, 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#1533 queued: valid format, and the issue meets the bar.

  • rulespec-us#1533 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-ga/ module paths with corpus status;
    • verbatim manual, plan, matrix and HHS text;
    • required outputs for all 6 variables;
    • 15 companion tests derived from the matrices, plans, manual and HHS tables ("None is taken from policyengine-us output").
  • It describes head 50aaa0096e correctly, including the electric route (interpretation 6), the $0 fuels (9), the plan-manual conflicts (10), the household-size conflict (16) and the carried-forward years (20).
  • Updates needed when the fixes land:
    • the input list and a UI case (S1);
    • the new source and branch cases (S2);
    • the FY2024 note for interpretation 6 (G3);
    • the stale "open as a draft".

Next steps

  1. S1: rebase onto main, switch P/income/sources/person.yaml:13 to total_unemployment_compensation, and add a case with unemployment compensation.
  2. S2: add the all-sources case, the subsidized electric-route case and the size-0 limit assertion.
  3. S3: align the six descriptions.
  4. Optionally address G1-G6, then refresh the PR body and rulespec-us#1533 and re-request review.

0 critical and 3 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 3 should items; details in the full report above. The FY2026 values check out: all 10 step-2 amounts, all 32 Level I cutoffs and all 32 income limits (60% SMI, floor then floor). Social Security net of Part B is right for Georgia, and the direct-pay and electric-vendor awards follow the manual and plan. All 54 tests pass and CI is green. (1) Merge blocker from main's #9558: the guard fails on the merged tree at income/sources/person.yaml:13, which lists the raw unemployment_compensation. (2) Logic that passes every test even when broken on purpose: 8 of the 24 person income sources are never set to a nonzero value (including disability, workers' comp and general assistance), along with the electric route's tenant_pays_utilities condition and the size-0 income-limit mask. (3) Six parameter descriptions are off the house template.

hua7450 and others added 2 commits October 15, 2026 15:13
- S1: Merge blocker: the person source list reads the raw unemployment_compensation, so main's #9558 guard fails
- S2: Eight income sources and two smaller pieces of logic are not pinned by any test
- S3: Six parameter descriptions fall outside the house template
- REC-C: Federal 110%-of-poverty floor (coordinator recommendation C; not raised by David for GA)

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

  • S1: I merged upstream/main (PRs 9558 and 10046), and income/sources/person.yaml now lists total_unemployment_compensation; no Georgia LIHEAP formula or parameter reads the raw input. ga_liheap.yaml Case 21 adds $5,110 of unemployment compensation (Georgia's $365 maximum weekly benefit for 14 weeks, USDOL January 2026) to $12,000 of wages: income $17,110, Level II electric, $400 (the award without it is $500).
  • S2: (1) Income Case 15 sets your eight sources to $100 through $800 and expects $3,600. (2) I took your second option and dropped the tenant_pays_utilities conjunct: a positive electric bill is the bill "in their name" (manual p. 4), and the docstring reads page 82's "rent includes utilities" as rent covering every utility. Eligibility Case 9 pins your household at $660 with the $1,200 electric bill and ineligible without it; no existing expected value changes. (3) The size-0 assertion is ga_liheap_income_limit.yaml Case 4 ($0), in the limit's own test file rather than household-size Case 2.
  • S3: The six descriptions now use your suggested wording.
  • G1: Partly done. base_amount, lower_income_uplift and maximum_table_size now cite the FY2025 matrix, and smi_rate cites FY2025 plan item 2.1 (p. 8). Claiming FY2024 and gating or encoding FY2023: history is out of scope for this PR, so verified_years stays "2025-2026" and earlier years stay documented as unverified estimates.
  • G2: Partly done. The ga_liheap_matrix_amount comment now points to Default heating_type to electricity and remove the UNSPECIFIED-gated state heating adapters #9754 for the unspecified default. Kerosene, coal and solar, and unspecified fuel on the electric route, stay eligible at $0: heating_type is a required input, no Georgia source maps those fuels to a matrix row, and the electric route pays the main fuel's amount, which an unknown fuel lacks. These households meet the manual's energy-burden test, so the model keeps them eligible and documents the $0 as a coverage gap.
  • G3: Done. The FY2024 matrix note now backs the electric route in _ga_liheap_housing.py, ga_liheap_matrix_amount and the PR body. PAMMS chapter 100 (p. 4) backs the household-size reading, together with the DFCS page, and the main-heating-source bill rule in ga_liheap_eligible. The PR body says PAMMS p. 5 still prints $350-$400 with a senior maximum and that plan 16.1 (p. 30) makes the matrix govern.
  • G4: Kept Level II plus the $100 uplift, which reproduces all ten printed cells in both claimed years. lower_income_uplift.yaml now labels it an inferred pattern, and the ga_liheap_matrix_amount comment notes that the lowest-award shortcut relies on the same uplift for every fuel. I left the routes as helpers to avoid two more variables; eligibility Cases 7-9 and ga_liheap.yaml Cases 14, 16 and 17 pin them.
  • G5: Done. The PR body adds the not-modeled row for the other direct-pay cases (p. 89 rows 4 and 7, p. 4, and 1300.2 on p. 70) and the plan item 2.3 (p. 8) conflict row, which ga_liheap_eligible also notes. The heating_type sentence now covers eligibility and payment cases, and the item 1.9 title and comment read pages 5-7.
  • G6: Partly done. The isolated size, income, limit and matrix cases no longer set hud_utility_allowance or fuels and bills their variables do not read (income Case 8 keeps heating_type for the matrix amount, and matrix Case 3 keeps its $50 gas bill). FY2027 is unchanged: DFCS has published no FY2027 matrix and the draft plan keeps 60% SMI, $400-$810 and the 16.1 sentence, so period 2027 stays a documented carried-forward estimate.
  • Federal poverty floor: Separately from your review, eligibility now applies 42 U.S.C. 8624(b)(2)(B) through the shared gov.hhs.liheap.fpg_floor (1.1) and a Georgia fpg_year_lag of 1 (the guidelines HHS makes mandatory for the fiscal year). Georgia's 60% SMI limit falls below 110% of poverty from size 16 ($102,926 against $105,336 in FY2025; $107,634 against $107,965 in FY2026), and ga_liheap_income_limit still reproduces the printed table. ga_liheap.yaml Case 22 has 17 people whose four adults earn Georgia's median wages for cashiers and for fast food and counter workers, $111,980 in total: above the $109,627 limit and below the $114,015 floor, so it receives Level II natural gas, $560.
  • LIHEAP wave 2a: encode Georgia LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1533 is refreshed to this head, including the "open as a draft" status line.

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

DTrim99 commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

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

PR #9968 (author: hua7450). This round reviews head c60610f7f7; round 1 reviewed 50aaa0096e. Four commits and one outside review came in between:

Neither merge had a hand-resolved conflict. The only Georgia-relevant file either merge touched is the programs.yaml coverage line, which comes through unchanged.

Path prefixes, as in round 1: P/ = policyengine_us/parameters/gov/states/ga/dfcs/liheap/, V/ = policyengine_us/variables/gov/states/ga/dfcs/liheap/, T/ = policyengine_us/tests/policy/baseline/gov/states/ga/dfcs/liheap/. Line numbers refer to c60610f7f7.

Summary

Ziming fixed all three round-1 should items:

  • S1. The person list reads total_unemployment_compensation. Main's guard passes at the head, and ga_liheap.yaml Case 21 adds $5,110 of UI, which moves the award from $500 to $400.
  • S2.
    • Income Case 15 sets all eight unpinned sources at $100–$800 each.
    • He took my second option for the electric route: he dropped the tenant_pays_utilities conjunct. Eligibility Case 9 pins it.
    • Income-limit Case 4 asserts $0 at size 0.
  • S3. All six descriptions use the suggested wording.

Of the six suggestions:

  • Fixed: G3 and G5.
  • Partly fixed, rest declined with reasons I accept:
  • Declined (accepted): G4. The inferred $100 uplift is now labelled as inferred.

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

There are no new critical or should findings. One new suggestion (checklist item 16): #10182 reached main after this head's last merge.

Batch checks:

Every new or changed expectation checks by hand: 8 new cases, 1 changed case, and 24 cases whose unread inputs were removed. CI is 29/29 green at the head. The branch is 16 ahead of main and 17 behind, and merges cleanly.

Prior findings status

Finding Status Evidence
S1: the person list read the raw unemployment_compensation, so main's #9558 guard failed on the merged tree Fixed The list. P/income/sources/person.yaml:13 reads total_unemployment_compensation, and no Georgia LIHEAP file reads the raw input. The guard. All four test_unemployment_compensation_readers.py tests pass at the head (Rest shard-1). The case. ga_liheap.yaml Case 21 gives 12,000 + 5,110 = 17,110, above the 13,589 Level I top, so Level II electric $400. Without the UI it would be $500. Georgia has no modeled UI, so the reported amount passes through. The issue. rulespec-us#1533's input list now names the total.
S2: eight sources, the electric route's tenant_pays_utilities conjunct and the size-0 mask had no test that would fail Fixed (1) Sources. Income Case 15 gives each source a distinct amount, $100–$800, for a total of 3,600, so dropping any one changes the total. (2) Conjunct. He took my second option and dropped it (V/eligibility/_ga_liheap_housing.py:50-54). Eligibility Case 9 gives a subsidized renter with tenant_pays_utilities false eligibility and $660 with the $1,200 bill, and ineligibility without it. Restoring the conjunct fails that case. The change opened Pavel's S4, which is now fixed (below). (3) Mask. Income-limit Case 4 asserts 0 at size 0. Unmasked, it would be floor(66,441 × 0.52) = 34,549.
S3: six descriptions used verbs outside the template Fixed All six use the suggested wording (excludes ×2, uses ×2, provides, sets). All ten Georgia descriptions end at "under the Low Income Home Energy Assistance Program."
G1: claim FY2024, gate FY2023, cite FY2025 documents Citations fixed; claim declined (accepted) Citations. base_amount, lower_income_uplift and maximum_table_size cite the FY2025 matrix, and smi_rate cites FY2025 plan 2.1 (p. 8). All four now start on 2024-10-01 (Pavel's G9), with no output change. The claim. verified_years stays "2025-2026", and the body calls other years unverified estimates. The decline matches #9967 G1.
G2: kerosene, coal, solar and unspecified fuel eligible but paid $0 Note added; kept by design (accepted) Disclosure. V/payment/ga_liheap_matrix_amount.py:70-73 cites #9754, and the body's not-modeled table lists the gap. Tests. The $0 on the electric route is now pinned by ga_liheap.yaml Case 16 household 4 and Case 17 household 3. Consistency. It matches #9967 G2.
G3: cite the FY2024 matrix note, PAMMS and the DFCS page; the body on PAMMS $350–$400 Fixed The FY2024 note. The _ga_liheap_housing.py docstring and the body quote "The main fuel type is not always where the benefit is applied". The docstring adds that the FY2025 and FY2026 sheets keep the asterisk but drop the note (Pavel's G10). PAMMS and DFCS. PAMMS ch. 100 p. 4 and the DFCS page back the household size, and PAMMS backs the main-heating-source bill rule. The body says PAMMS p. 5 still prints $350–$400 and that plan 16.1 (p. 30) makes the matrix govern.
G4: encode the printed Level I column; expose the routes as variables Declined (accepted) The uplift. P/payment/lower_income_uplift.yaml:2-4 now labels the $100 as an inferred pattern ("Encode the printed Level I column if a matrix breaks the pattern"). The matrix-amount comment states the same-uplift assumption behind the lowest award. Both reproduce all ten printed cells in both claimed years. The routes. They stay helpers, and eligibility Cases 7–9 and ga_liheap.yaml Cases 14, 16 and 17 pin them.
G5: body rows for other direct-pay cases and plan 2.3, the heating_type sentence, pp. 5–7 Fixed The rows. The body adds the other direct-pay row (p. 89 rows 4 and 7, p. 4, 1300.2 on p. 70) and the plan 2.3 conflict row. ga_liheap_eligible.py:51-54 also notes plan 2.3. The sentence now covers eligibility and payment cases only, which is accurate. Page ranges. The item 1.9 title (P/income/sources/person.yaml:57) and the V/income/ga_liheap_income.py:15 comment read 5–7.
G6: test hygiene, FY2027, issue housekeeping Hygiene and issue fixed; FY2027 declined (accepted) Hygiene. No hud_utility_allowance remains, and the isolated size, income, limit and matrix cases set no unread fuels or bills. Two exceptions are deliberate: income Case 8 keeps heating_type for its matrix assertion, and matrix Case 3 keeps the $50 gas bill. FY2027. On 2026-10-20 the Clearinghouse returns 404 for a Georgia FY2027 matrix and plan. The DFCS LIHEAP page (modified 2026-09-28) links only the draft FFY27 plan, so the carried-forward 2027 estimate stays documented. The issue. #1533 no longer says "open as a draft".

Pavel's review (between rounds). His four should items are fixed:

  • S4 (same inputs, different award by subsidy).
    • The fix. V/payment/ga_liheap_matrix_amount.py:60-63 sets direct_payment = direct_route & ~electric_vendor. A heat-in-rent renter with an electric bill is therefore paid the main-fuel amount, with or without a subsidy.
    • The tests. ga_liheap.yaml Case 17 now expects $660 and $560 (it was $500 and $400), plus an UNSPECIFIED household at $0.
    • Sources and disclosure. The docstring cites manual p. 57. The body's "with or without a subsidy and whatever tenant_pays_utilities says" sentence now holds.
    • Against the manual. Manual p. 89 row 3 ("Heat costs included in rent and applicant is billed directly for electric") reads "Paid to electric vendor because gas usage is indeterminate", which supports the fix.
  • S5 (floating-point floor). V/eligibility/ga_liheap_eligible.py:40 uses np.round(guideline * p_hhs.fpg_floor, 2) with a strict <, the same line as merged MS, NJ, OR and DC.
  • S6 (floor tests). Eligibility Cases 10 and 11 pin the rate, the strict boundary and the lag (see Verified). The Case 22 comment now points to them.
  • S7 (anchor). Both 8624 links end #b_2_B, and fpg_floor.yaml is identical to main's.

Of his suggestions:

  • Done:
    • G8: the p. 43 assurance in ga_liheap_eligible and the body.
    • G9 and G10 (above).
    • G11: the PAMMS export date beside both hrefs.
    • G13: the USDOL and BLS URLs and the 14 × WBA wording.
    • G15: the changelog names gov.hhs.liheap.fpg_floor.
    • G16: eligibility Case 12.
  • Partly done: G12. The full IM identifiers are given and IM 2026-01 is added. The IM 2025-02 main page is not added, because Attachment 2 already says "mandatory use in FY26".
  • Deferred: G7, a shared floor helper. Per-state fpg_year_lag matches how Apply the federal 110% poverty floor to state LIHEAP programs (DC, MA, MS, NJ, OR) #10279 left MS, NE and the rest.
  • Declined, correctly: G14, per-page references. CLAUDE.md "Parameter and variable references" requires one entry per source document, with multi-page titles such as #page 66,69. The three titles follow that.

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/person.yaml:21 lists military_retirement_pay (with survivor_benefits at line 25).
  • 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. Manual 1200.7 includes "Pension — Unearned payment received regularly as a retirement benefit" (p. 66) and "Annuity" (p. 65). FY2026 plan 1.9 lists "Retirement / pension benefits" (p. 6).
  • Effect on the merged tree (worked out from the code, not run). Take a surviving spouse with $36,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:
    • Merged tree: countable income is $0, so Level I natural gas, $660.
    • Counting the annuity: $36,000 is above the $34,549 limit, so $0, as in ga_liheap.yaml Case 12 household 1 for retirement pay.
    • The same amount in survivor_benefits ("Survivor benefits other than Social Security survivor benefits") would count. That narrows the gap, but Wire military retirement pay and survivors into federal and state tax (#10181) #10182 names the new input for SBP.
  • Why a suggestion, not should:
  • Fix, if taken here:
    • Replace the entry with military_retirement_income.
    • Add a military_retirement_pay_survivors amount to income Case 15, or add a separate case.
    • Update the Inputs line of rulespec-us#1533.

Verified

  • Mutation check (item 13), reasoned from the tests and code at the head:
    • New floor logic in ga_liheap_eligible:
      • The rate. Eligibility Case 10 brackets it to the cent: 107,964.99 is true and 107,965 is false.
      • The strict <. Case 10 row 3 (107,965) and Case 11 row 3 (105,336).
      • The rounding. Without it, 1.1 × 98,150 = 107,965.00000000001 admits row 3. A ceiling would give 107,966, which also admits it.
      • fpg_year_lag 1. Case 10 row 5 (lag 0 gives 117,524, so true) and Case 11 row 4 (lag 0 gives 107,965, so true).
      • The | floor arm. ga_liheap.yaml Case 22 and Case 11 row 1.
      • Georgia size, not SPM size. Eligibility Case 12, where the SPM size would give a 114,015 floor, so true.
    • Route precedence.
      • & ~electric_vendor: ga_liheap.yaml Case 17 ($660, not $500).
      • Restoring tenant_pays_utilities on the electric route: eligibility Case 9 and ga_liheap.yaml Case 17.
      • The direct route's own ~tenant_pays_utilities: still pinned by eligibility Case 7 column 2, which has no electric bill.
    • The size-0 limit mask: income-limit Case 4.
    • Each income source: income Cases 1 and 15 plus the round-1 cases.
    • Unchanged since round 1: the other branches. Round 1 confirmed them by mutation runs, and the code around them has not changed.
  • State-gated keys (item 15, NH Add New Hampshire state supplementation for 2026 #10156).
    • The pattern is present. ga_liheap_household_size is an int gated to Georgia with default 0. p.lower_income_limit[lookup_size] reads it as a key (breakdown range(1, 17)).
    • Core runs the formula on every row. policyengine-core evaluates a defined_for formula on the whole population and then applies np.where(mask, ...), so non-Georgia rows reach the lookup with size 0.
    • The guard and its test. clip(size, 1, p.maximum_table_size) covers it. ga_liheap.yaml Case 5 ([GA, GA, GA, AL], asserting ga_liheap) evaluates ga_liheap_matrix_amount on the Alabama row, so removing the lower clip would raise there.
    • The new floor. fpg(size, state_group, ...) uses size only in arithmetic, and state_group is always a valid key. Eligibility Case 6 [GA, AL] runs it.
  • Integrate modeled state unemployment insurance into income flows #9558 (item 11). The guard's four tests pass at the head, and no Georgia 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).
    • No premium deduction for wages. Manual p. 69's only premium exclusion is "Health Premiums — Premiums (amount spent on premiums paid by Social Security received by Medicare)", which the PR applies as Social Security net of medicare_part_b_premium. Georgia has no pay-stub premium deduction.
    • Gross wages. Wages come from employment_income, not ssi_earned_income, so Document disjoint health premium inputs and correct consumer treatment #10046 does not reach Georgia LIHEAP.
  • Federal 110% floor (42 U.S.C. 8624(b)(2)(B)).
    • Georgia assures it. "may not exclude a household ... if such income is less than 110 percent of the poverty level" (FY2026 plan p. 43).
    • Where it binds. The printed 60% limit falls below the floor from size 16:
      • FY2025: 102,926 against 105,336;
      • FY2026: 107,634 against 107,965;
      • size 15 does not bind: 101,020 against 99,418 (FY2025), and 105,641 against 101,915 (FY2026).
    • The carried-forward 2027 estimate binds from size 17.
    • Guidelines. The lagged guidelines (2024 for FY2025, 2025 for FY2026) are the HHS-mandatory ones (IM 2024-02 and IM 2025-02, Attachment 2).
    • Implementation. The floor line matches Apply the federal 110% poverty floor to state LIHEAP programs (DC, MA, MS, NJ, OR) #10279's MS and the merged NJ, OR and DC eligibility variables. ga_liheap_income_limit keeps the printed table, and the body has a conflict row for the printed size-16 limits.
  • IIJA and FY2027 (item 12). No IIJA supplement in any Georgia plan or matrix, as in round 1. No FY2027 matrix is published (see G6).
  • Other main commits since the head's merge base (17).
  • New and changed expectations, checked by hand.
    • FY2026: four-person 60% amount floor(110,736 × 0.6) = 66,441. Size factors 1.62 (size 16) and 1.65 (size 17).
    • 2025 guidelines: $15,650 + $5,500 per additional person.
    • 2024 guidelines: $15,060 + $5,380.
    • ga_liheap.yaml:
      • Case 17 (changed): heat in rent, rent 9,600, bill 1,200, so the electric route for all three households: eligible [true, true, true]. 12,000 ≤ 13,589 gives natural gas 560 + 100 = 660. 24,000 gives 560. UNSPECIFIED has no column, so 0. Heating expense is 0 for gas with no gas bill and for UNSPECIFIED.
      • Case 21 (new): 12,000 + 5,110 = 17,110. That is above 13,589 and within 34,549, so Level II electric 400.
      • Case 22 (new): 2 × 29,070 + 2 × 26,920 = 111,980, size 17. The limit is floor(66,441 × 1.65 = 109,627.65) = 109,627 and the floor is 1.1 × 103,650 = 114,015, so eligible. The size-16 Level I top is 42,336, so Level II natural gas 560, with heating expense 1,800.
    • ga_liheap_eligible.yaml:
      • Case 9 (new): subsidized, heat in rent, tenant_pays_utilities false.
        • With the bill: the electric route makes it eligible, and the subsidy blocks the direct route, so 560 + 100 = 660.
        • Without it: no route and no primary bill, so false and 0.
      • Case 10 (new): limits 107,634 ×4 and 109,627. Size-16 floor 1.1 × 98,150 = 107,965. That gives [107,634 ≤ limit: true; 107,964.99 < floor: true; 107,965: false; 107,966: false]. Size 17 at 115,000 is above 109,627 and at least 114,015, so false.
      • Case 11 (new): limit floor(floor(105,893 × 0.6) × 1.62) = floor(63,535 × 1.62) = 102,926. Floor 1.1 × 95,760 = 105,336. That gives [104,000: true; 105,335.99: true; 105,336: false; 106,000: false].
      • Case 12 (new): SPM size 17, Georgia size 16 (undocumented adult left out, manual 1100.4 p. 51), and income 111,980 (that adult's wages count). The limit is 107,634 and the floor 107,965, so false.
    • ga_liheap_income_limit.yaml Case 4 (new): size 0 gives 0.
    • ga_liheap_income.yaml Case 15 (new): 100 + 200 + ... + 800 = 3,600. Unemployment comes through total_unemployment_compensation, which equals the reported 100.
    • Changed inputs, unchanged outputs:
      • Removed inputs: heating inputs and hud_utility_allowance.
      • The cases: household-size Cases 1–2, income Cases 1–13, income-limit Cases 1–3, and matrix Cases 1–4, 6 and 7.
      • None of those variables reads them. Size adds is_citizen_or_legal_immigrant. Income reads the income sources. The limit reads size and state. The matrix amount reads heating_type, size, income and the route inputs, which default to no route.
      • Income Case 8 keeps heating_type, and its $500 needs no bill.
  • Inputs not checked. I didn't check the USDOL UI provisions ($365 WBA, 14 × WBA) or the BLS OEWS medians ($29,070 and $26,920). They are inputs only, and every expectation follows from them.
  • Wiring.
    • Registry. The programs.yaml entry and coverage line are unchanged since round 1 (partial, verified_years: "2025-2026").
    • Aggregates. Georgia is in no aggregate, which matches the merged LIHEAP states.
    • Gating. defined_for = StateCode.GA is on five variables, and ga_liheap is gated by ga_liheap_eligible.
    • Changelog. changelog.d/ga-liheap.added.md is top level and typed added, and now names the floor parameter.
  • 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. The new floor rests on 42 U.S.C. 8624(b)(2)(B) and plan p. 43 (re-read). Manual pp. 57, 65–69 and 89 were re-read for S4, item 14 and Suggestion 1.
  2. Income definition: pass. Gross wages; Social Security net of Part B per plan 1.9 and manual p. 69; per-source floors; the Integrate modeled state unemployment insurance into income flows #9558 total. Suggestion 1 covers the post-Wire military retirement pay and survivors into federal and state tax (#10181) #10182 SBP input.
  3. Backdating: pass for claimed years. FY2025-cited files now start 2024-10-01. FY2024 and FY2023 are unclaimed and declined. No FY2027 table is published.
  4. Household and arrangement rules: pass. Subsidized and unsubsidized heat-in-rent renters with an electric bill now get one award (Pavel's S4). Every route is pinned.
  5. Tests: pass. 62 cases in 6 files, with every new or changed expectation checked by hand. Periods are plain. The floor edges are pinned to the cent in both claimed years.
  6. Descriptions: pass. All ten Georgia descriptions follow the template.
  7. References: pass.
    • Multi-page titles use #page 66,69, #page 62-69,83 and #page 5-7.
    • Variable tuples use # PDF pages comments.
    • The 8624 links are anchored.
  8. Wiring: pass. Registry, no aggregate (as in the siblings), defined_for gating, and no take-up beyond TANF's.
  9. Axiom: valid queued line. Correct the qualified_business_income variable formula #1533 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 matrix is published; the draft plan keeps 60% SMI and $400–$810.
  13. Mutation check: pass. Every new branch is pinned, including the floor's rate, rounding, strictness, lag and household size.
  14. Document disjoint health premium inputs and correct consumer treatment #10046 health premiums: not applicable. Only the Medicare premium on Social Security is excluded; wages are gross employment_income.
  15. State-gated index defaults: guarded. The size is clipped to 1, and the GA/AL ga_liheap.yaml Case 5 pins it.
  16. Wire military retirement pay and survivors into federal and state tax (#10181) #10182 survivor annuities: Suggestion 1.

Axiom line assessment

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

  • Issue state.
    • Correct the qualified_business_income variable formula #1533 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 Georgia LIHEAP module: us-ga/policies/dfcs/ holds only medicaid, snap and tanf. So queued is still the right form.
  • Dispatch-ready. It has:
    • module paths with corpus status;
    • the verbatim manual, plan, matrix, HHS and statute text;
    • six required outputs;
    • companion tests 1–19, hand-derived from the matrices, HHS tables, plans, 42 U.S.C. 8624 and the manual, and mapped to PE cases.
  • Matches the head c60610f7f7:
    • Cases: 62 cases in 6 files, listed per file.
    • Eligibility: round(1.1 × guideline, 2) with guideline year = model year − 1 at the Georgia size, and the electric route "subsidized or not, whatever tenant_pays_utilities says".
    • Matrix amount: the electric route takes precedence over the all-utilities route (UNSPECIFIED: $0).
    • Inputs: they name total_unemployment_compensation.
    • Companion tests 16–19 match Case 22, eligibility Cases 10–12, Case 21 and income Case 15.
  • The only update it would need is the Inputs line, if Suggestion 1 is taken.

CI status

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

  • Quick Feedback ran all six Georgia LIHEAP files at the head: 12 + 4 + 22 + 2 + 15 + 7 = 62 passed. The whole Georgia tree also passed (477).
  • Rest (Python, shard-1) passed the Integrate modeled state unemployment insurance into income flows #9558 guard's four tests and test_members_are_state_gated.
  • 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 three should-address items from round 1 are fixed (#9558 reader, income and limit test coverage, descriptions), and Pavel's S4-S7 are fixed too. One open suggestion about #10182 survivor annuities. Full report in the comment above.

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

Program Review

IDs: C = critical, S = should address, G = suggestion. S1-S7 and G1-G16 carry over from the prior review at b36ba40f71 with their IDs unchanged; S8 and G17-G21 are new in this round. S8 is the S4 defect with a heating-fuel bill in place of the electric bill. It gets a new ID, not "S4 partial", because S4 as reported (the electric bill) is fixed exactly as recommended; the heating-fuel case was already present at b36ba40f71 and was not part of S4.

Source Documents

Paths: P/ = policyengine_us/parameters/gov/states/ga/dfcs/liheap/, V/ = policyengine_us/variables/gov/states/ga/dfcs/liheap/, T/ = policyengine_us/tests/policy/baseline/gov/states/ga/dfcs/liheap/. Line numbers refer to c60610f7f7.

Branch Status

  • 16 commits ahead of main and 17 behind (main at 645fcd3e52, merge base 1661d715bd, #10279). The branch merges cleanly. A scratch merge leaves the Georgia LIHEAP tree unchanged, and all 62 cases pass on it.
  • Of the 17 newer main commits, only #10182 touches a Georgia LIHEAP input (G18).
  • gov/hhs/liheap/fpg_floor.yaml now equals main (blob aeb7f8c5b0), so the PR no longer adds that file.
  • The open wave 2a siblings (#9967, #9969, #9970, #9972-#9975) conflict with this branch only on the shared LIHEAP coverage line in programs.yaml. Whichever lands first, the rest need a one-line resolution.
  • This is informational only. Staleness did not affect any finding.

Prior findings

ID Finding Status
S1 Person source list read raw unemployment_compensation RESOLVED (round 2); P/income/sources/person.yaml:13 unchanged
S2 Eight sources, the electric-route conjunct and the size-0 mask had no tests RESOLVED (round 2); no regression
S3 Six descriptions off template RESOLVED (round 2)
S4 Heat in rent, tenant_pays_utilities false and an electric bill got $500 unsubsidized but $660 subsidized RESOLVED: V/payment/ga_liheap_matrix_amount.py:60-63 uses the recommended & ~electric_vendor. Case 17 (T/ga_liheap.yaml:618) now expects [660, 560, 0], the same as the subsidized renter. Only Case 17's expected values changed. The same defect with a heating-fuel bill is S8; the effect on unpriced fuels is G17
S5 The floor admitted income of exactly 110% (float error) RESOLVED: V/eligibility/ga_liheap_eligible.py:40 uses np.round(guideline * p_hhs.fpg_floor, 2), the #10279 pattern on main. Size 16 at $107,965 (FY2026) and $105,336 (FY2025) is now ineligible
S6 Floor tests did not pin the lag, the rate or the strict boundary RESOLVED: T/eligibility/ga_liheap_eligible.yaml:219 (Case 10) and :239 (Case 11) kill lag 0 and lag 2, any rate outside [1.09999995, 1.10000005), <=, the unrounded floor and np.ceil
S7 8624 links did not go to (b)(2)(B) RESOLVED: gov/hhs/liheap/fpg_floor.yaml:11 and ga_liheap_eligible.py:23 end #b_2_B; the anchor exists on the LII page
G1 Claim FY2024, gate FY2023 STILL OPEN, declined (accepted); suggestion. FY2025-cited files are now dated (G9); the income files remain (G20)
G2 Kerosene, coal, solar and unspecified fuel eligible but paid $0 STILL OPEN, declined (accepted); suggestion. New evidence in G17
G3 Cite the FY2024 note, PAMMS and DFCS RESOLVED (round 2)
G4 Encode the Level I column; expose routes as variables STILL OPEN, declined (accepted). Level II plus $100 still reproduces all ten Level I cells in FY2025 and FY2026
G5 PR body rows, heating_type sentence, pp. 5-7 RESOLVED (round 2)
G6 Test hygiene, FY2027, rulespec status FY2027 STILL OPEN, declined (accepted): no FY2027 matrix is published on 2026-10-20
G7 Shared federal floor helper DEFERRED to a follow-up refactor (accepted). The floor block is now in six state files; the five on main still cite the bare 8624 URL
G8 Cite Georgia's floor assurance RESOLVED: ga_liheap_eligible.py:16-18,36-37; the text is on FY2025 plan p43 and FY2026 plan p43
G9 Date the FY2025-cited parameters 2024-10-01 RESOLVED: four files re-dated, with no output change (verified). Four income files remain: G20
G10 Say the FY2024 note is carried forward; add the FY2025 matrix RESOLVED: _ga_liheap_housing.py:38-42; ga_liheap_matrix_amount.py:17. Both sheets show the asterisk and no note
G11 Record the PAMMS export date RESOLVED: ga_liheap_eligible.py:21, ga_liheap_household_size.py:13
G12 Full IM identifiers; IM 2025-02 main page PARTIAL, accepted; closed. IM 2026-01 is added and its title is verified. Attachment 2 p1 alone carries the lag
G13 URLs for USDOL and BLS; "14 x WBA" wording RESOLVED: T/ga_liheap.yaml:716-720,754-756. USDOL p2 and both BLS medians ($29,070, $26,920) verified
G14 Page ranges in three titles WITHDRAWN: the decline follows CLAUDE.md:149-155 (one entry per source document, page list at the end of a quoted title)
G15 Changelog omits gov.hhs.liheap.fpg_floor RESOLVED: changelog.d/ga-liheap.added.md:1
G16 No test pins the floor's household size RESOLVED: T/eligibility/ga_liheap_eligible.yaml:260 (Case 12): SPM size 17, Georgia size 16, $111,980 gives false; an SPM-size floor ($114,015) would give true

Critical (Must Fix)

None.

Should Address

S8. A heating-fuel bill does not override the all-utilities direct route, so the S4 split remains (new ID; same defect as S4)

  • Where: V/payment/ga_liheap_matrix_amount.py:60-68 (only the electric-vendor route overrides the direct payment); V/eligibility/_ga_liheap_housing.py:14-20 (the direct route has no separate-bill test); docstring :36-38 ("which keeps renters with no separate bill").

  • Household (period 2026, reproduced at head): one adult, natural gas heat in rent, rent $9,600, tenant_pays_utilities false, a $1,200 gas_expense and no electric bill.

    Variant $12,000 wages $24,000 wages Rule
    Unsubsidized (model) $500 $400 $660 / $560
    Subsidized, rent $3,000 (model) $660 $560 $660 / $560
    Unsubsidized, tenant_pays_utilities true (model) $660 $560 $660 / $560

    With other priced fuels the gap is larger: fuel oil $500 against $810 and propane $500 against $680 (unsubsidized, $12,000). Electricity and wood are unaffected ($500 in both readings). Eligibility is true in every variant.

  • Evidence: M p57, 1100.14 bullet 2, limits the unsubsidized all-in-rent class to rent that "includes utilities with no separate bill for heating/cooling costs". M p89 row 1, "Applicant pays a vendor directly for utilities", is "Paid to vendor". Only row 2 is "Direct pay to Applicant (999)". FY2026 plan p30 gives the lowest award only "If the benefit goes directly to the applicant". The PR's own docstring says a separate bill rules out rent covering every utility.

  • Why a new ID: the S4 fix that round 2 recommended covered only the electric bill. The prior head gives the same values, so this is not a regression, and round 2 did not report it. No test covers it: a mutation that adds the heating-fuel bill to the precedence passes all 62 cases.

  • Fix (verified): in ga_liheap_matrix_amount, after base = select(...):

    electric_vendor = ga_liheap_has_electric_vendor_route(spm_unit, period)
    priced_fuel_bill = (spm_unit("heating_expense", period) > 0) & (base > 0)
    direct_payment = (
        ga_liheap_has_direct_payment_route(spm_unit, period)
        & ~electric_vendor
        & ~priced_fuel_bill
    )
    • All 62 cases still pass. Cases 9, 14 and 17 keep their values, and no ga_liheap_eligible output changes. The household above moves to $660 / $560, fuel oil to $810 and propane to $680.
    • Caveat: unpriced fuels (kerosene, coal, other) with their own bill keep the head's $500 lowest award, so their G2 split ($500 here, $0 with tenant_pays_utilities true or subsidized) stays. A full fix for them needs a G2 decision (G17).
    • Do not use the shorter direct_route & ~(electric_vendor | (heating_expense > 0)), or the same condition inside ga_liheap_has_direct_payment_route. It matches p57 more literally, but it cuts kerosene, coal and other-fuel households with their own bill from $500 to $0 (verified), unless you also take G17.
    • Add a case to T/ga_liheap.yaml (63 of 63 pass with the fix; at head it gives [500, 660]):
      - name: Case 23, a primary fuel bill takes the vendor route when rent is flagged as including all utilities.
        period: 2026
        input:
          state_code: [GA, GA]
          age: [40, 40]
          immigration_status: [CITIZEN, CITIZEN]
          employment_income: [12_000, 12_000]
          ssi: [0, 0]
          ga_tanf: [0, 0]
          rent: [9_600, 3_000]
          heating_type: [NATURAL_GAS, NATURAL_GAS]
          heat_expense_included_in_rent: [true, true]
          tenant_pays_utilities: [false, false]
          receives_housing_assistance: [false, true]
          is_in_public_housing: [false, false]
          gas_expense: [1_200, 1_200]
          pre_subsidy_electricity_expense: [0, 0]
        output:
          ga_liheap_eligible: [true, true]
          ga_liheap: [660, 660]
    • Quote M p57 bullet 2 in the _ga_liheap_housing.py:29-38 docstring and the Case 17 comment (T/ga_liheap.yaml:603-609). It supports the unsubsidized half of S4 more directly than bullet 1. p57 is already in both page lists.
  • Rated should-address, as S4 was: the same defect class and input type, $160 to $310 per household. Only an explicit tenant_pays_utilities: false triggers it (the input defaults to true, variables/household/expense/housing/tenant_pays_utilities.py:19). Household calculations only.

Suggestions

  • G17. (G2 scope; the only regression from ad147608f7.) Unpriced or unspecified fuels on the electric-vendor route now get $0. Household: period 2026, $12,000 wages, heat in rent, tenant_pays_utilities false, rent $9,600, unsubsidized, heating_type KEROSENE, COAL, SOLAR, OTHER or UNSPECIFIED. With a $1,200 electric bill the award is $0. With no bill it is $500, and at the prior head it was $500 with the bill. So reporting an extra bill cuts the award from $500 to $0. Cause: V/payment/ga_liheap_matrix_amount.py:40-50 has no arm for these fuels (default=0), and :60-63 now removes them from the direct route. M p89 row 3 ("Paid to electric vendor because gas usage is indeterminate") gives the electricity amount, $400 + $100 = $500. The plan p30 lowest award gives the same $500. No source gives $0. heating_type.py calls UNSPECIFIED "the right value when heat is included in rent and the fuel is unknown", which is this row. UNSPECIFIED is pinned on purpose (Case 16 household 4, T/ga_liheap.yaml:576; Case 17 household 3, :618); the other four fuels are not. Option (verified): on a heat-in-rent vendor route (electric_vendor | (direct_route & heating_expense > 0)) with base == 0 and a fuel other than NONE, pay the lowest award plus the uplift. This also fixes S8 without the kerosene, coal and other-fuel side effect, but it changes those two pinned values from $0 to $500. Unpriced-fuel households with only their own fuel bill and tenant_pays_utilities true, or a subsidy, stay at $0 (G2). If you keep the decline, state the $500-to-$0 step in the :69-73 comment and the PR body.
  • G18. (DTrim99's #10182 suggestion.) An SBP survivor annuity is not counted. P/income/sources/person.yaml:18-21 lists military_retirement_pay only. Household (period 2026, reproduced at head): one adult age 70, natural gas heat, a $1,200 gas bill and $36,000 in military_retirement_pay_survivors. Countable income is $0, the household is eligible, and the award is $660. The same $36,000 in military_retirement_pay or survivor_benefits gives income $36,000, above the $34,549 limit, so $0. M p65 ("Annuity") and M p66 ("Pension") count it. The input already exists at this head. After a main merge, #10182 documents military_retirement_pay as former members only and sends SBP to the uncounted input, while SSI starts to count it. Fix: now, add - military_retirement_pay_survivors after :21 (verified: $36,000 counted, $0 award, Case 12 still passes). After merging main, replace the entry with military_retirement_income (verified on a scratch merge). Do not list military_retirement_income together with either component, or the pay counts twice. Update the comment at :18-20, add a survivors amount to income Case 15 (T/income/ga_liheap_income.yaml:440), and update the Inputs line of rulespec-us#1533.
  • G19. (Follow-up for main, not this PR.) #10182 left benefit-program lists on military_retirement_pay. On main 645fcd3e52, 34 entries in 32 parameter files name it without the survivors input or military_retirement_income. These include the merged LIHEAP lists (in/ihcda/eap/income/sources.yaml:26, ky/dcbs/liheap/unearned_income_sources.yaml:17, md/dhs/meap/income/sources/unearned.yaml:15, or/ohcs/liheap/income/sources/unearned.yaml:17), 25 child-care entries in 23 jurisdictions, MO and TX TANF, MO SSP, FL SR and AR SRA. The OR comment (:15-16) and the MD comment (:12-14) about survivor payments are stale. No open issue exists (only #10181, closed). Open one issue for all benefit-program lists.
  • G20. Four income parameters still start on 2025-10-01: P/income/minimum_age.yaml:3, P/income/monthly_interest_disregard.yaml:3, P/income/sources/household.yaml:3 and P/income/sources/person.yaml:7. All other GA LIHEAP parameters now start on 2024-10-01. There is no output change: backdating returns the same values at every instant, and a household with a 17-year-old's $5,000 wages has $12,000 countable income in both 2025 and 2026 (M p62). Fix: date the four files 2024-10-01. For the source lists, add FY2025 plan item 1.9 after you check its checkboxes on pp. 5-7 (the text matches FY2026; the checkbox states were not machine-verified).
  • G21. Test comment nits:
    • T/ga_liheap.yaml:768-769: the "$331 window ($107,634 to $107,965)" is FY2026 only. Case 11 pins the FY2025 window ($102,926 to $105,336).
    • T/ga_liheap.yaml:756: the BLS route is a client-side app. Add the two series IDs (OEUS130000000000041201113, OEUS130000000000035302313) so the values can be checked through the API.
    • Optional: the S4 precedence is pinned only end to end (Case 17). A matrix-level case in T/payment/ga_liheap_matrix_amount.yaml (the Case 5 element 1 inputs at :72 plus a $1,200 electric bill, expecting 660) would pin it at the unit.

Carried suggestions still open (see the table): G1, G2, G4 and G6 (declined, accepted) and G7 (deferred).

PDF Audit Summary

Category Count
Changed references and claims confirmed correct 29 of 29 (IM 2026-01 title and BLS medians confirmed by external check)
Page anchors and page citations confirmed correct 25 of 25 (6 parameter, 12 variable, 7 test)
Re-dated values re-checked against FY2025 sources 4 files: 60% SMI (FY2025 plan p8); 400/560/710/580/400, $100 and size 16 (FY2025 matrix)
External documents matched 4 (IM 2026-01 page; USDOL January 2026 p2; BLS OEWS May 2025, two series; PAMMS export date)
Confirmed rule mismatches (code path and page) 3: S8 (M p57, p89; plan p30), G17 (M p89; plan p30), G18 (M p65-66)
Investigated and cleared 6

Investigated and cleared:

  • np.round(..., 2): the 2 is cent precision, not a legal value. The line is identical to #10279 on main.
  • G9 re-dating: no output change; the values are identical at every instant.
  • Income-file dating: cannot change any FY2025 output. Kept as a dating suggestion only (G20).
  • Case 17's new values [660, 560, 0]: correct under M p89 row 3. A sweep of all 62 cases found no other case with both routes, so no other expected value changes.
  • SOLAR as a side effect of the S8 fix: rejected. SOLAR's heating bill is the electric bill, so it is already $0 at head (part of G17), and the fix does not change it.
  • #9969's bare 8624 link: the FL diff on file was from an older round. #9969's fpg_floor.yaml is the same blob as main. Nothing to do here.

Validation Summary

Check Result
CI 29 of 29 pass at c60610f7f7
Local tests 62 of 62 pass at c60610f7f7; 62 of 62 on a scratch merge with main; 63 of 63 with the S8 fix and Case 23
Regulatory 0 critical; S8 (same defect as S4, heating-fuel bill); G17, G18, G20. Floor rounding, lag and household size correct
References None missing; 29 of 29 corroborate; G21 comment nits
Code patterns No hard-coded values; vectorized; periods and entities correct; G7 deferred
Tests 62 cases (3 new, Case 17 changed). Cases 10-12 kill the lag, rate, <=, rounding and SPM-size mutations. One surviving mutation: the heating-fuel-bill precedence (S8)
Prior findings 11 resolved this round (S4-S7, G8-G11, G13, G15, G16); G12 partial and closed; G14 withdrawn; G1, G2, G4, G6 and G7 open at suggestion level
Other reviews DTrim99 approved c60610f7f7 on 2026-10-20; his #10182 suggestion is G18. S8 is not in his review

Review Severity: REQUEST_CHANGES

Next Steps

  1. Fix S8: apply the priced_fuel_bill precedence in ga_liheap_matrix_amount, add Case 23, and quote M p57 bullet 2.
  2. Optional in this PR: G18 (one line), G20 and G21. Decide G17: take the fallback, or document the $500-to-$0 step.
  3. Open the G19 issue on main. It does not block this PR.

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

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

hua7450 commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the reviews. Fixes pushed in 94a4c9c.

Pavel

  • S1-S3: Resolved in round 2; no change.
  • S4: Resolved; S8 below extends the same precedence to a bill for the main heating fuel.
  • S5-S7: Resolved; no change.
  • G1: Still declined: the claim stays FY2025-FY2026. The last four income files now start on 2024-10-01 (G20).
  • G2: Kept as a documented coverage gap; G17 below makes the $0 the same on every vendor route.
  • G3: Resolved; no change.
  • G4: Still declined; Level II plus $100 reproduces all ten printed Level I cells in both years.
  • G5: Resolved; no change.
  • G6: FY2027 still declined: no Georgia FY2027 matrix is published.
  • G7: Deferred to the follow-up refactor PR for a shared floor helper.
  • G8-G11: Resolved; no change.
  • G12: Closed as partial; no change.
  • G13: Resolved; G21 adds the BLS series IDs.
  • G14: Withdrawn; no change.
  • G15, G16: Resolved; no change.
  • S8: Fixed. In ga_liheap_matrix_amount, a positive bill for the main heating fuel (main_fuel_bill, a positive heating_expense) now overrides the all-utilities direct payment as the electric bill does (& ~electric_vendor & ~main_fuel_bill), so your household gets $660 at $12,000 and $560 at $24,000 (fuel oil $810, propane $680), with or without a subsidy; new ga_liheap.yaml Case 23 pins five households, and no earlier expectation changes. The _ga_liheap_housing.py docstrings, the matrix-amount comment and the Case 17 comment quote manual page 57 bullet 2, and I left out the & (base > 0) guard because of the G17 decision below.
  • G17: Kept $0 for unpriced and unspecified fuels on vendor payments: step 2 prices the "main heating fuel type*", the FY2024 note ties a vendor payment to that fuel's amount, page 89 row 3 names the payee rather than a priced column, and plan page 30's lowest award applies only "If the benefit goes directly to the applicant". The rule is now the same on every vendor route: without the guard, a kerosene, coal or other-fuel renter with its own fuel bill also gets $0 (it got $500 only with tenant_pays_utilities false and no subsidy), and only the direct payment with no separate bill pays these fuels the lowest award. The matrix-amount comment, the PR body and LIHEAP wave 2a: encode Georgia LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1533 state the $500-to-$0 step, and new ga_liheap.yaml Case 24 and matrix Case 8 pin it.
  • G18: Not in this PR. It will be handled in a cross-state follow-up PR so every LIHEAP state counts survivor annuities the same way; the PR body lists SBP annuities entered in military_retirement_pay_survivors as not counted.
  • G19: Not in this PR either; it will be handled in a cross-state follow-up PR so every LIHEAP state counts survivor annuities the same way. Thanks for the inventory of the non-LIHEAP lists (child care, MO and TX TANF, MO SSP, FL SR, AR SRA).
  • G20: Fixed. income/minimum_age, income/monthly_interest_disregard, income/sources/household and income/sources/person now start on 2024-10-01 (no output change). The rendered FY2025 plan pages 5-7 match FY2026 box for box in item 1.9, so both source lists now cite FY2025 plan item 1.9.
  • G21: Fixed. The Case 22 comment gives both windows (FY2026: $331, $107,634 to $107,965; FY2025: $2,410, $102,926 to $105,336) and both BLS series IDs, and new matrix Case 8 pins the electric-bill and fuel-bill precedence at the unit level.

David

  • S1-S3: Thanks for re-verifying; no change.
  • G1: The claim stays FY2025-FY2026; the last four income files now start on 2024-10-01 (Pavel's G20).
  • G2: Still a documented coverage gap; the $0 now applies on every vendor route (Pavel's G17), and new ga_liheap.yaml Case 24 and matrix Case 8 pin it.
  • G3-G6: No further change; the new cases send heating_type and set only inputs the model reads.
  • Suggestion 1: Not in this PR. It will be handled in a cross-state follow-up PR so every LIHEAP state counts survivor annuities the same way; the PR body lists SBP annuities entered in military_retirement_pay_survivors as not counted, and LIHEAP wave 2a: encode Georgia LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1533 notes the gap.

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

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

Program Review

IDs: C = critical, S = should address, G = suggestion. S1-S8 and G1-G21 carry over from the round-3 review at c60610f7f7 with their IDs unchanged. G22-G24 are new in this round (optional wording only). No new C or S item.

Source Documents

  • Statute: 42 U.S.C. 8624(b)(2)(B) (HTML; "less than 110 percent" proviso; unchanged) and 42 U.S.C. 8622 (HTML; "household" definition in (5), fetched 2026-10-21 for the 10ff85eddb check)
  • PDF: LIHEAP poverty guideline tables, IM 2025-02 Att. 2 and IM 2024-02 Att. 2 (3 pages each; size 16 floors re-checked for the Case 22 windows)
  • HTML: LIHEAP IM 2026-01 (supports only the unclaimed 2027 lag; not re-read)
  • PDF: Georgia LIHEAP State Plan FY2026 and FY2025 (47 pages each; item 1.9 on pp. 5-7 of both plans rendered and checkbox-read; FY2026 p30 re-read)
  • PDF: Georgia LIHEAP Policy Manual, January 2022 (89 pages; "M" below, file page = printed page; pp. 4, 51, 57, 62, 66, 69, 76 and 89 re-read)
  • PDF: Georgia Benefit Matrix FY2026, FY2025, FY2024 (1 page each; size 1 and size 16 cells re-checked)
  • PDF: DFCS PAMMS LIHEAP export (31 pages; not re-read, no changed citation)
  • PDF: USDOL Significant Provisions of State UI Laws, January 2026 (not re-read, no changed citation)
  • Data: BLS OEWS May 2025, Georgia (series OEUS130000000000041201113 and OEUS130000000000035302313; IDs decoded, medians from the round-3 API read)
  • Year: FY2025 and FY2026 (test periods 2025 and 2026). Period 2027 is a documented carried-forward estimate and is not claimed.
  • Scope: Incremental. 10 PR-scope files changed since the prior review: 8 in 94a4c9c1a3, 1 in 10ff85eddb, and programs.yaml from the main merge c76de92de7 only (Georgia entry unchanged). Plus all unresolved prior findings.
  • Reviewed head SHA: 10ff85e
  • Mode: incremental from c60610f

Paths: P/ = policyengine_us/parameters/gov/states/ga/dfcs/liheap/, V/ = policyengine_us/variables/gov/states/ga/dfcs/liheap/, T/ = policyengine_us/tests/policy/baseline/gov/states/ga/dfcs/liheap/. Line numbers refer to 10ff85eddb.

Branch Status

  • 19 commits ahead of main and 5 behind (main at f45d36a7d1, merge base ce9377ee80). GitHub reports MERGEABLE. The 5 newer main commits do not touch Georgia LIHEAP or programs.yaml.
  • CI is red: 2 fail, 27 pass at 10ff85eddb. Both failures (Python Rest rollup and shard 1) are one test, policyengine_us/tests/code_health/test_source_conflicts.py::test_conflict_sounding_comments_do_not_grow.
  • Cause: the test flags 4 FL LIHEAP files (fl_liheap_eligible.py, fl_liheap_income_limit.py, fl_liheap.py, payment/base_amount.yaml) and 1 SD LIHEAP file (income/limits/table/in_effect.yaml). These came in with the earlier main merge c76de92de7 (main at ce9377ee80). main later added them to KNOWN_UNMARKED in #10334 (fec98b87c8). No Georgia file is flagged, and a regex scan of the Georgia LIHEAP variables and parameters finds 0 matching comments.
  • Fix: merge current main into the branch. No Georgia code change is needed. Verified on a scratch merge of 10ff85eddb with f45d36a7d1: it merges cleanly, test_source_conflicts.py gives 103 passed, and the Georgia LIHEAP YAML gives 65 passed.
  • The PR should not merge until CI is green. This is a merge prerequisite, not a code finding.

Prior findings

ID Finding Status
S1 Person source list read raw unemployment_compensation RESOLVED (round 2); not touched
S2 Eight sources, the electric-route conjunct and the size-0 mask had no tests RESOLVED (round 2); not touched
S3 Six descriptions off template RESOLVED (round 2); not touched
S4 Electric bill did not override the all-utilities direct route RESOLVED (round 3). Case 17 (T/ga_liheap.yaml:620) still expects [660, 560, 0]. Matrix Case 8 element 1 now also pins it at the unit
S5 The floor admitted income of exactly 110% (float error) RESOLVED (round 3); eligibility code unchanged
S6 Floor tests did not pin the lag, the rate or the strict boundary RESOLVED (round 3); not touched
S7 8624 links did not go to (b)(2)(B) RESOLVED (round 3); not touched
S8 A heating-fuel bill did not override the all-utilities direct route RESOLVED. V/payment/ga_liheap_matrix_amount.py:63-69 adds main_fuel_bill = heating_expense > 0 and & ~main_fuel_bill. The round-3 household now gets $660 / $560 (was $500 / $400); fuel oil $810 and propane $680 (were $500), in every housing variant, in 2025 and 2026. Electricity and wood stay at $500. No eligibility output changes. Pinned by Case 23 (T/ga_liheap.yaml:835) and matrix Case 8 element 2 (T/payment/ga_liheap_matrix_amount.yaml:127); both fail on the prior code. M p57 bullet 2 is quoted verbatim in the code comment, both _ga_liheap_housing.py docstrings and the Case 17 comment. The author left out the & (base > 0) guard on purpose: see G17
G1 Claim FY2024, gate FY2023 STILL OPEN, declined (accepted). Every Georgia LIHEAP parameter now starts on 2024-10-01
G2 Unpriced or unspecified fuels eligible but paid $0 STILL OPEN, declined (accepted); documented coverage gap. The $0 now applies on every vendor route (G17)
G3 Cite the FY2024 note, PAMMS and DFCS RESOLVED (round 2)
G4 Encode the Level I column; expose routes as variables STILL OPEN, declined (accepted)
G5 PR body rows, heating_type sentence, pp. 5-7 RESOLVED (round 2)
G6 Test hygiene, FY2027, rulespec status FY2027 STILL OPEN, declined (accepted): no FY2027 matrix is published
G7 Shared federal floor helper DEFERRED to a follow-up refactor (accepted)
G8 Cite Georgia's floor assurance RESOLVED (round 3)
G9 Date the FY2025-cited parameters 2024-10-01 RESOLVED (round 3); the remaining income files are G20
G10 Say the FY2024 note is carried forward; add the FY2025 matrix RESOLVED (round 3)
G11 Record the PAMMS export date RESOLVED (round 3)
G12 Full IM identifiers; IM 2025-02 main page PARTIAL, accepted; closed
G13 URLs for USDOL and BLS; "14 x WBA" wording RESOLVED (round 3); G21 adds the series IDs
G14 Page ranges in three titles WITHDRAWN (round 3)
G15 Changelog omits gov.hhs.liheap.fpg_floor RESOLVED (round 3)
G16 No test pins the floor's household size RESOLVED (round 3)
G17 Unpriced or unspecified fuels on a vendor route get $0 STILL OPEN, declined and documented (accepted); suggestion. The S8 fix widens the scope: see Suggestions
G18 SBP annuity in military_retirement_pay_survivors not counted STILL OPEN, deferred to a cross-state follow-up (accepted); suggestion. See Suggestions
G19 main benefit-program lists name only military_retirement_pay STILL OPEN on main, outside this PR. Now tracked by draft #10317, so no separate issue is needed
G20 Four income files dated 2025-10-01; FY2025 item 1.9 not cited RESOLVED. P/income/minimum_age.yaml:3, P/income/monthly_interest_disregard.yaml:3, P/income/sources/household.yaml:3 and P/income/sources/person.yaml:7 start on 2024-10-01. FY2025 plan item 1.9 is identical to FY2026 box for box (35 categories plus the two SSA Medicare sub-boxes; machine-read and visually confirmed). The new hrefs are correct: person.yaml:57-58 ("#page 5-7", #page=5) and household.yaml:12-13 (#page=6, TANF row). Outputs are identical in 2024, 2025 and 2026
G21 Case 22 window; BLS series IDs; matrix-level precedence case RESOLVED. T/ga_liheap.yaml:771-774 gives both windows (FY2026 $331, $107,634 to $107,965; FY2025 $2,410, $102,926 to $105,336; both exact). :758-760 give both series IDs. Matrix Case 8 element 1 pins the electric-bill precedence at the unit
DTrim99 suggestion 1 Same as G18 Deferred with G18

Critical (Must Fix)

None.

Should Address

None.

Suggestions

  • G17. (Declined and documented, accepted. G2 scope.)
    • Household effect: an unsubsidized renter with heat in rent, tenant_pays_utilities false and its own kerosene, coal or other-fuel bill now gets $0 instead of $500 (period 2026, $12,000 wages); with no separate bill it still gets $500.
    • Cause: the S8 fix has no base > 0 guard, so these households leave the direct route, and select(..., default=0) prices no amount for their fuel. SOLAR and UNSPECIFIED do not change.
    • This is the documented G2/G17 design choice, not a new defect. No source prints an amount for these fuels: the FY2024-FY2026 step 2 tables price only electric, natural gas, oil, propane and wood. The plan p30 lowest award applies only "If the benefit goes directly to the applicant".
    • The fix also removes the old split for these fuels: own-bill households now get $0 with tenant_pays_utilities false, true or a subsidy (at c60610f7f7: $500 / $0 / $0).
    • The author did what round 3 asked for a kept decline. The $500-to-$0 step is in V/payment/ga_liheap_matrix_amount.py:75-82, the PR body and rulespec-us#1533. Case 24 household 2 (T/ga_liheap.yaml:876) and matrix Case 8 element 3 pin it. Both fail under the round-3 guarded fix, so a silent switch is caught.
    • Reach: an explicit tenant_pays_utilities: false (the default is true), heat in rent, no subsidy, and an unpriced fuel with its own bill. Household calculations only. No action unless reviewers reopen G2.
  • G18. (Deferred, accepted.) An SBP survivor annuity is still not counted. Reproduced at head: an adult aged 70 with $36,000 in military_retirement_pay_survivors has ga_liheap_income $0, is eligible and gets $660. The same amount in military_retirement_pay gives $36,000 against the $34,549 limit, so $0 (M p65, M p66).
    • The cross-state draft #10317 ("Count military SBP annuities in state benefit income lists") changes only programs that are on main. It has no Georgia file, because Georgia LIHEAP is not on main.
    • So Georgia must make the switch itself: change P/income/sources/person.yaml:21 from military_retirement_pay to military_retirement_income, and update the comment at :18-20. Do it in this PR, or right after merge (for example, add the Georgia file to #10317 if it is still open). military_retirement_income exists at head. Do not list it together with either component, or the pay counts twice.
  • G22. (New, optional wording.) P/income/sources/person.yaml:27-30, :39-41 and :44-46 say only "FY2026 plan 1.9 (page 6)". The list now starts on 2024-10-01, and FY2025 plan p6 has the same boxes unchecked (verified). Suggested: "FY2025 and FY2026 plans 1.9 (page 6)". Also optional: FY2025 plan p6 leaves "Earned income of a child under the age of 18" unchecked, which supports P/income/minimum_age.yaml (it cites only M p62). No output effect.
  • G23. (New, optional wording.) T/payment/ga_liheap_matrix_amount.yaml:117-118 says "Manual page 57 (1100.14) limits the direct applicant payment to rent that ...". p57 1100.14 lists ineligible households and names no payment type; the payment type comes from p89 row 2. Use the Case 17 and Case 23 wording: "limits the unsubsidized all-in-rent class to rent that ...". The quote itself is verbatim. Also, "the Case 5 element 1 household" is loose for element 3, which is kerosene. No value effect.
  • G24. (New, optional wording.) V/eligibility/ga_liheap_eligible.py:67-68 says "see the manual conflict noted in ga_liheap_household_size". 10ff85eddb reworded the target (V/ga_liheap_household_size.py:21) to "The manual gives two other answers". Suggested: "see the manual note in ga_liheap_household_size". "manual conflict" does not match CONFLICT_COMMENT_RE, so CI is not affected either way.

Carried suggestions still open (see the table): G1, G2, G4 and G6 (declined, accepted), G7 (deferred), G17 (declined and documented), G18 (deferred) and G19 (on main, tracked by #10317).

Validation Summary

Check Result
CI 2 fail, 27 pass at 10ff85eddb: one source-conflict test, from FL/SD files of the earlier main snapshot. A merge of current main clears it (verified on a scratch merge). See Branch Status
Local tests 65 of 65 at head (12 + 4 + 24 + 2 + 15 + 8; was 62). The head suite on the prior code: 62 pass, 3 fail (Case 23, Case 24, matrix Case 8), so no earlier expected value changed. Round-3 guarded fix: 63 pass, 2 fail (Case 24, matrix Case 8). 65 of 65 on a scratch merge with main
Regulatory S8 resolved. Household probe (38 households, periods 2025 and 2026): 7 change from the prior head, 4 S8 corrections and 3 G17 scope rows (kerosene, coal, other: $500 to $0). Eligibility is unchanged in every row. 0 new C or S items
References 4 of 4 changed hrefs correct; 23 of 23 page citations in changed comments correct; Case 17 and Case 22 quotes exact; 4 of 4 re-dated values supported from 2024-10-01; CLAUDE.md reference-format rules met. G22 and G23 wording only
Code patterns Vectorized, no hard-coded values, entity and period correct; ruff reports the 3 changed .py files as formatted. Changelog fragment present; Georgia programs.yaml entry unchanged (verified_years: "2025-2026")
Tests 3 new cases (Case 23, Case 24, matrix Case 8); all 12 new elements hand-checked. S8 and the G17 choice are both pinned. No non-functional tests
Investigated and cleared 10ff85eddb reword: meaning kept, all three manual quotes verbatim. The disagreement is manual against manual; 42 U.S.C. 8622(5) says nothing about citizenship, so no statute-vs-source marker is needed (the case is in the main backlog as us-ga:liheap-lawful-noncitizen-household-members). G20 re-dating: no output change
Prior findings Resolved this round: S8, G20, G21. G17 declined and documented; G18 deferred; G19 tracked by #10317. G1, G2, G4, G6 and G7 unchanged
Other reviews None this round

Review Severity: APPROVE

No critical or should-address item is open. Merge only after CI is green (see Branch Status).

Next Steps

  1. Merge current main into the branch to clear the red source-conflict check. Do not merge the PR until CI is green.
  2. G18: switch P/income/sources/person.yaml:21 to military_retirement_income, in this PR or right after merge. Draft #10317 does not cover Georgia.
  3. Optional: G22, G23 and G24 (comment wording only).
  4. After merge (informational): the four Georgia entries in source_conflicts/candidates.yaml on main still say "Code not yet on main". They can link the merged code, and the floor line V/eligibility/ga_liheap_eligible.py:40 can carry its marker after rulespec-us registers that entry.

PavelMakarchuk added a commit that referenced this pull request Oct 21, 2026
…d Riverside County LIHEAP (#10281)

* Apply the federal 110% poverty floor to MS and OR LIHEAP

42 U.S.C. 8624(b)(2)(B) bars a state from excluding a household solely on
income below 110% of the poverty level. The 60% SMI limit falls below that
floor in Mississippi from household size 11 (FY2026-FY2027) and in Oregon
from size 19 (PY2025) or 20 (PY2026-PY2027). Both eligibility tests now
accept income below 110% of the poverty guideline that HHS makes mandatory
on October 1 of the program year (one-year lag).

Adds gov.hhs.liheap.fpg_floor, identical to the file in #9968 and #9969,
plus a poverty guideline year lag for each state.

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

* Apply the federal 110% poverty floor to DC, MA and NJ LIHEAP

The 60% SMI limits fall below 110% of the poverty guideline only for very
large households: DC from size 34 to 39 in 2022-2024, MA from size 30 to 34
and NJ from size 28 to 32 in 2022-2027. The eligibility tests now accept
income below the floor, using the one-year guideline lag. MA reuses
ma_liheap_fpg, which already lags the guideline; DC and NJ get their own
fpg_year_lag parameters.

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

* Anchor the LIHEAP floor reference to 42 U.S.C. 8624(b)(2)(B)

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

* Update the NC SA 2027 test for the announced 2027 COLA

#10225 replaced the projected 2027 SSA uprating index with the 2026Q3
CPI-W average and set the 2027 SSI federal benefit rate to $1,029. The
NC Special Assistance 2027 case still expected the old projections
($1,436 rate, $1,021.83 FBR), so the states-shard-1 suite fails on main
and on every PR. The uprated rate is now $1,448 and the payment $489.

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

* Address review: MS floor citation, IM link, exact limits, payment test

- Cite Rule 6.1 C, the printed 60% SMI table and FY2026 plan assurance (2)
  in the Mississippi floor comment; the printed table itself falls below
  the floor at sizes 11 to 20.
- Point the IM 2023-01 references to the acf.gov archive URL.
- Correct test comments that showed float32-rounded DC and MA limits.
- Add a Mississippi payment test for a household that qualifies only
  through the floor.

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

* Apply the federal 110% poverty floor to IN, MD and Riverside LIHEAP

The 60% SMI limits fall below 110% of the poverty guideline from
household size 15 (2025) or 16 (2026-2027) in Indiana EAP, size 29 in
Maryland MEAP (FY25-FY27), and size 20 (2025) or 21 (2026-2027) in
Riverside County LIHEAP. The eligibility tests now accept income below
the floor, with the one-year guideline lag. Maryland reuses
md_meap_fpg; Indiana and Riverside get fpg_year_lag parameters.

Stacked on #10279, which adds gov.hhs.liheap.fpg_floor.

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

* Remove the #10279 changelog fragment that main already released

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450 and others added 2 commits October 21, 2026 12:37
Cite FY2025 and FY2026 plan item 1.9 for the unchecked person sources and
the child earnings exclusion, tighten the matrix test comment, and point the
eligibility comment at the manual note.

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

hua7450 commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the reviews. The wording suggestions are in a9dae48, and the branch now includes current main.

Pavel

  • G22: Applied: the insurance, lottery and cash-gift comments in income/sources/person.yaml now cite FY2025 and FY2026 plans 1.9 (page 6). income/minimum_age.yaml also cites FY2025 plan page 6, which leaves "Earned income of a child under the age of 18" unchecked; no value changes.
  • G23: Applied: the matrix Case 8 header now says page 57 "limits the unsubsidized all-in-rent class" and names only elements 1 and 2 (natural gas) as the Case 5 element 1 household. Without a separate bill all three elements would get the $500 lowest award, which does not depend on the fuel; no input or expected value changes.
  • G24: Applied: the ga_liheap_eligible comment now reads "see the manual note in ga_liheap_household_size".
  • Main merge: The merge brings Count the FL and SD LIHEAP comments in the source-conflict ratchet baseline #10334, which adds the FL and SD LIHEAP files flagged by test_source_conflicts.py to the source-conflict baseline (KNOWN_UNMARKED). The merge changes no Georgia LIHEAP file.
  • Axiom issue: LIHEAP wave 2a: encode Georgia LIHEAP regular heating assistance TheAxiomFoundation/rulespec-us#1533 is refreshed to the new head.

@DTrim99

DTrim99 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

PR Review (round 3): Add Georgia LIHEAP regular heating assistance

Summary

PR #9968 (author: hua7450). This round reviews head a9dae48466; round 2 approved c60610f7f7. Since then there have been three author commits and two merges of main.

The behavior change follows the manual. I re-read manual page 57, 1100.14: the all-in-rent class is rent that "includes utilities with no separate bill for heating/cooling costs". Page 89 row 1 pays an applicant who "pays a vendor directly for utilities" through the vendor. So a renter whose rent includes heat, but who has a bill for the main fuel, now gets the main fuel's step 2 amount instead of the $500 lowest award. No earlier expectation changed. The new ga_liheap.yaml Cases 23 and 24 and matrix Case 8 add 12 expectations, and every one checks by hand.

The other changes.

  • The one side effect is that unpriced fuels (kerosene, coal, other) on every vendor route now pay $0. It is documented and extends the round-2 G2 gap we accepted.
  • The wording commits change no value. The four parameter files that moved their start date to 2024-10-01 keep the same values.
  • The reworded note passes the ratchet, and the conflict it describes is already on main's backlog as us-ga:liheap-lawful-noncitizen-household-members.
  • The programs.yaml resolution keeps every merged LIHEAP sibling and lists Georgia once.

There are no new findings. CI is 29/29 green on a run that started after #10334, and the merge with main is clean.

What changed since our approval

Commit Change Values changed? Check
94a4c9c1a3 (Pavel S8) ga_liheap_matrix_amount.py:62-69: direct_payment = direct_route & ~electric_vendor & ~main_fuel_bill, where main_fuel_bill = heating_expense > 0 Yes, for an unsubsidized all-in-rent renter who also has a main-fuel bill: $500/$400 becomes the main fuel's step 2 amount Correct. Page 57 and page 89 rows 1-3 (quoted above; I re-read both pages). heating_expense is the bill for heating_type (kerosene reads fuel_oil_expense), so the test is "a bill for the main fuel". Eligibility is unchanged, because it already counted heating_expense > 0 as an energy burden.
94a4c9c1a3 (Pavel G17) The $0 for unpriced and unspecified fuels now applies on every vendor route; the comment, docstrings, PR body and #1533 state the $500-to-$0 step Yes, for a kerosene, coal or other-fuel renter who has its own fuel bill and tenant_pays_utilities false: $500 becomes $0 Accepted, as for round-2 G2. Step 2 prices only electricity, gas, oil, propane and wood. The $0 is documented as an incomplete estimate, not an ineligibility finding, and #9754 tracks the default. The direct route still pays the page 30 lowest award only when there is no separate bill.
94a4c9c1a3 (Pavel G20, G21) income/minimum_age, monthly_interest_disregard, sources/household and sources/person start 2024-10-01; FY2025 plan 1.9 references added; the Case 22 comment gives both floor windows and the BLS series IDs No The values are unchanged (18, $25, the same lists), and the first value already extrapolated backward. The FY2025 plan's item 1.9 starts on p.5, and p.6 lists TANF, cash gifts, lotteries, insurance and a child's earnings. The text layer has no box states, so I rely on Pavel's rendered check for those. The new reference shapes follow CLAUDE.md: the quoted #page 5-7 title opens at p.5, single-page hrefs have no page in the title, and # PDF pages 4, 57, 89 sits above the matrix-amount href.
10ff85eddb ga_liheap_household_size.py:21: "The manual conflicts with itself" becomes "The manual gives two other answers" No Passes the ratchet. The old text matched \bconflicts?\ with\b in CONFLICT_COMMENT_RE. The new text matches no pattern. The conflict is manual against manual, with no statute involved. It is already on main's backlog as us-ga:liheap-lawful-noncitizen-household-members (code: [], "Code not yet on main"), so the reword hides nothing.
a9dae48466 (Pavel G22-G24) The person-source comments cite FY2025 and FY2026 plans 1.9; minimum_age.yaml gets a FY2025 plan p.6 reference; the matrix Case 8 header is reworded; the eligibility comment says "manual note" No Comments and one reference only. No new comment line matches the ratchet patterns ("follows the manual" and "Follow the detailed manual" are not "we follow the manual").

New expectations, checked by hand (FY2026: size 1 limit $34,549, Level I top $13,589; Level II amounts electricity 400, natural gas 560, fuel oil 710, propane 580, wood 400; Level I uplift $100):

  • ga_liheap.yaml Case 23 (heat in rent, tenant_pays_utilities false, $1,200 main-fuel bill):
    • household 1: unsubsidized gas at $12,000, Level I, 560 + 100 = 660;
    • household 2: subsidized, so no direct route anyway, 660;
    • household 3: gas at $24,000, Level II, 560;
    • household 4: fuel oil, 710 + 100 = 810;
    • household 5: propane, 580 + 100 = 680.
    • All five are eligible through heating_expense > 0, and heating_expense is 1,200 for each.
  • ga_liheap.yaml Case 24 (kerosene, unsubsidized, $12,000):
    • household 1: no bill, direct route, min(400, 560, 710, 580, 400) + 100 = 500;
    • household 2: kerosene bill (via fuel_oil_expense), so main_fuel_bill, no step 2 row, 0;
    • household 3: the flag is true, so there is no direct route, 0;
    • household 4: an electric bill puts it on the electric route at the kerosene amount, 0, and heating_expense is 0.
    • All four are eligible.
  • Matrix Case 8 (income 13,589, the inclusive Level I top):
    • electric bill: electric route, 660;
    • gas bill: main-fuel bill, 660;
    • kerosene bill: 0.

Merge-resolution check

New findings

Axiom, CI and branch

Verdict: APPROVE

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Round 3 confirmation: the follow-up commits are correct. The main-fuel bill now overrides the all-in-rent direct payment per manual pp.57/89, the wording changes alter no values, the reworded note passes the ratchet, and the programs.yaml hand-merge keeps every sibling. Full report in the comment above.

@PavelMakarchuk
PavelMakarchuk merged commit 93af522 into main Oct 22, 2026
29 checks passed
@PavelMakarchuk
PavelMakarchuk deleted the ga-liheap branch October 22, 2026 13:56
PavelMakarchuk added a commit that referenced this pull request Oct 22, 2026
Resolve the programs.yaml conflict with the Georgia LIHEAP merge (#9968):
keep both the AR and GA state_implementations entries and list both
states on the LIHEAP coverage line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk added a commit that referenced this pull request Oct 22, 2026
Switch the Georgia and Arkansas LIHEAP income lists, which merged in
#9968 and #9973, from military_retirement_pay to
military_retirement_income. Georgia manual 1200.7 includes annuities and
pensions; Arkansas manual Appendix F counts pensions paid to surviving
dependents. Add a survivor annuity case to each income test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk added a commit that referenced this pull request Oct 23, 2026
* Count military SBP annuities in state benefit income lists

#10182 moved Survivor Benefit Plan annuities into
military_retirement_pay_survivors. The benefit-program income lists
still listed only military_retirement_pay, so SBP annuities dropped out
of countable income. Replace military_retirement_pay with
military_retirement_income in 34 state child care, LIHEAP, TANF and SAB
lists, fix the OR LIHEAP and MD MEAP comments that #10182 made stale,
and add SBP cases for OR LIHEAP, MD MEAP, IN EAP, TX TANF and NY CCAP.

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

* Count SBP annuities in the FL, OH, OK, RI and SD LIHEAP lists

These LIHEAP source lists merged after the first commit and still
listed only military_retirement_pay. Switch them to
military_retirement_income, update their comments, and add SBP cases
for OH HEAP and SD LIEAP.

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

* Count SBP annuities in the GA and AR LIHEAP lists

Switch the Georgia and Arkansas LIHEAP income lists, which merged in
#9968 and #9973, from military_retirement_pay to
military_retirement_income. Georgia manual 1200.7 includes annuities and
pensions; Arkansas manual Appendix F counts pensions paid to surviving
dependents. Add a survivor annuity case to each income test.

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

* Guard benefit lists against raw military_retirement_pay

Add a code-health check, modelled on the unemployment compensation
readers check, that fails when a parameter list or Python reader outside
the tax side names military_retirement_pay without the survivor annuity
input. Address the review of #10317: add a Missouri SAB survivor annuity
case, record the Minnesota CCAP reading of 256P.06 subd. 3(2)(ix), and
update the stale source headers of the PA CCW and WV CCAP tests.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 24, 2026
… candidates

Refresh entries from code merged since the first round (#9944, #9968,
#10272), add the missing 110%-floor candidates for the District and
Riverside County, and fix the page anchors the reviews flagged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 24, 2026
…on main (#10350)

* Point the federal and AK-HI source-conflict candidates at their code on main

Candidates written while their pull requests were open said "Code not yet
on main". Each now lists the tracked files that decide it and a note on
which source that code follows. Adds candidates for conflicts the merged
code's comments record.

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

* Address review findings on the federal, Alaska-Hawaii source-conflict candidates

Refresh entries from code merged since the first round (#9944, #9968,
#10272), add the missing 110%-floor candidates for the District and
Riverside County, and fix the page anchors the reviews flagged.

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

* Refresh the SNAP candidates that #10299 settled

#10299 merged, so the Alaska and Hawaii ABAWD timing entries and the
FY2026 large-household cap entry no longer describe the change as in
flight; each note now says what the merged code does.

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

* Show the gap between readings in the Alaska and Hawaii ABAWD examples

Name the file that ends Hawaii's area waiver.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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 Georgia LIHEAP regular heating assistance

3 participants