Skip to content

Add South Carolina LIHEAP regular cooling assistance - #10754

Open
hua7450 wants to merge 18 commits into
mainfrom
sc-liheap-cooling
Open

hua7450 wants to merge 18 commits into
mainfrom
sc-liheap-cooling

Conversation

@hua7450

@hua7450 hua7450 commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

Adds South Carolina's cooling-season nonemergency benefit: a base amount plus supplements, with no fuel supplement, capped at $775 in FY2026 and $850 in FY2027. FY2027 allows one award per program year, so in 2027 cooling pays only its excess over the heating award.

Fixes #10753

Builds on the national LIHEAP total from #10730, merged on 2026-11-12: this PR adds sc_liheap_cooling to gov.hhs.liheap.regular_payments.

What and why

FY2026 plan items 3.3-3.6 (pp. 10-11) give a $200 base and say "The maximum nonemergency benefit during the cooling season is $775". The matrix notes "(no fuel benefit awarded May 1 - September 30)". The FY2027 accepted plan (Revision 2, items 3.3-3.6) sets a $300 base and an $850 maximum, with supplement changes. Eligibility is the regular LIHEAP test (plan 3.1: 60% SMI).

  • The heating supplement and proration logic move into a shared function, so sc_liheap keeps its heating award with unchanged results.
  • New cooling/amounts.yaml. FY2026: base $200; elderly $75; disabled $50; child $50; veteran $50; low income $175; burden $175; maximum $775. FY2027: base $300; elderly $50; disabled $50; child $50; veteran $50; low income $150; burden $200; maximum $850.
  • sc_liheap_cooling_eligible: heating eligibility and has_cooling_expense, with no heating-fuel condition of its own.
  • sc_liheap_cooling: base plus supplements, capped at the cooling maximum, then prorated for mixed-status households.
  • New payment/max_awards.yaml: two awards per program year in FY2026 ("A maximum of two LIHEAP services may be provided during the program year", plan item 11.5, p. 26; guides, Section 3A) and one in FY2027 ("South Carolina will offer one LIHEAP assistance (either emergency or nonemergency) during the 2027 program year", item 11.5, p. 26; item 1.1, p. 4). With one award, cooling pays only its excess over the heating award, so the household receives the larger of the two.
  • Cooling adds no heating-fuel condition. sc_liheap_eligible pays an unspecified fuel only with heat in the rent, so NONE (no heating), every known fuel and UNSPECIFIED with heat in the rent can be paid.
  • has_cooling_expense is required. This is a PolicyEngine convention of the all-state cooling work: OEO ties Direct Assistance to a home energy bill and sets no separate cooling-cost test.

Test plan

Tests were not run locally. This PR now targets main, so CI runs them.

  • YAML tests with expected values worked from the sources above. 8 cases in 2 files, covering 2026 and 2027: the base, each supplement, awards with every supplement (which sum exactly to the cooling maximum), the 2027 one-award rule with cooling above and below the heating award, the national liheap total in both years, a renter with heat in the rent and an unspecified fuel, and a mixed-status household's prorated cooling award.
  • Source-conflict register: candidates us-sc:liheap-low-income-tier-base, us-sc:liheap-energy-burden-test and us-sc:liheap-mixed-status-household now run to FFY2027 and list the cooling variable and this PR.
  • make format (ruff)
  • Changelog fragment in changelog.d/

Not modeled

  • Local frequency limits: "a subgrantee may choose to limit the frequency of assistance" (FY2027 plan item 1.1, p. 4); the guides let an agency do the same. The additional services the State "may allow" in FY2027 "Should funding allow" (item 1.1) are not modeled either.
  • The FY2027 heating amounts ($300 base, $1,000 maximum) are not on main; that is a separate heating follow-up. Until then, the 2027 one-award comparison uses the FY2026 heating amounts carried forward. The FY2027 heating award has the cooling base and supplements plus a $150 fuel supplement, up to $1,000 (item 2.5, p. 9), so once it is added it will be at least the cooling award for every household, and 2027 cooling will pay $0.

axiom: TheAxiomFoundation/rulespec-us#2181 queued

🤖 Generated with Claude Code

hua7450 and others added 12 commits November 8, 2026 22:01
Sum each state's regular LIHEAP payment in a new liheap variable, add an
Illinois regular heating payment without crisis assistance, add a Michigan
Home Heating Credit registry entry, and record each state's cooling
treatment in its registry note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add regular_payments.yaml to the aggregate-list integrity test, which checks
that each member exists, is state-gated and is not dropped between year
blocks. Say that Rhode Island plans no regular cooling payment, since its
FY2027 plan still allows a leftover-funds cooling grant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Records the FY2026 and FY2027 plan service limits, describes the age
thresholds for heating and cooling, tightens test margins, and checks
the national liheap total.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The national `liheap` total evaluates every state's formula over a
mixed-state population, which no household test does. Two patterns on main
raised errors there:

- 26 formula files passed options=[ADD] to an entity call. Core's
  Microsimulation.calculate_add rejects the keyword an entity call passes.
  The option is redundant: a plain read already sums a monthly variable over
  the year through the same Core function.
- The DC and Illinois payment formulas look up a matrix by an income level
  that is 0 for households outside the state. Add the floor Maryland and
  Kansas already use.

Also:
- Reword the North Dakota registry note: the state reserves an optional
  direct cooling payment, so its cooling component is not only equipment.
- Add a `liheap` case with Texas, DC and Illinois households in one
  simulation.
- Add a code-health check against options=[ADD] and options=[DIVIDE].
- Check that every state payment in the LIHEAP registry entry is in the
  list `liheap` sums.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a
Microsimulation accept the keyword an entity call passes with
options=[ADD] or options=[DIVIDE]. Once that is released the option works
again, so a check that bans it here would be wrong. The 26 formula files
stay without the option, which was redundant and lets `liheap` run on
today's Core.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…ogram prefix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from liheap-aggregate to main November 12, 2026 19:06
hua7450 and others added 2 commits November 12, 2026 14:08
PR 10730 was squash-merged into main as f67bb1e, so this merge uses its
final head 4625f4e, already merged here, as the merge base.

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

DTrim99 commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Add South Carolina LIHEAP regular cooling assistance

Reviewed at head b5e3dccff0 (11 files, +543/-47). Sources were read before the code: the accepted FY2026 plan, the accepted FY2027 plan (Revision 2), the 2026 Benefit Matrix, and the 2024 and draft 2026 Administrative Guides in OEO's plan-with-attachments file. No Python was run; every result below rests on reading, hand traces and the CI run at this head.

Summary

The amounts are right. Every value in cooling/amounts.yaml matches the plans for both years, the start dates put the FY2026 schedule in calendar 2026 and the FY2027 schedule in 2027, the refactor leaves sc_liheap identical to main, and all six new cases check by hand.

One thing blocks approval. The FY2027 plan gives a household one LIHEAP assistance in program year 2027 (crisis, heating or cooling), yet the PR pays the cooling award on top of the heating award in 2027, marks 2027 as verified, and adds both to the national liheap total. For 2026 paying both is backed: the FY2026 plan and both guides allow two services.

Two smaller items: the cooling gate turns away a renter with heat in the rent and an unspecified fuel whom South Carolina's own heating variable pays, and the PR body's reason for that is inaccurate; and three existing South Carolina source-conflict records are now applied to a new year without being updated.

Answers to the batch questions, briefly:

  • Separate cooling benefit, both years: yes. Plan item 1.1 lists cooling assistance 05/01/2026-09/30/2026 (5% of funds) and 05/01/2027-09/30/2027 (15% of funds); section 3 sets $200-$775 and $300-$850. HHS reports 3,994 households served by cooling assistance in FY2024 (17,420 by heating). The nonemergency benefit as a whole is funding-contingent ("reserves the option to provide nonemergency energy assistance during the heating and cooling seasons should funding be available", plan attachments p. 92); the registry note discloses that local funding decisions are out of scope.
  • Who the "heating eligibility" gate turns away: nobody for lack of a heating bill. sc_liheap_eligible asks for any counted energy bill (electricity included) with a known heating type, or heat in the rent; a home with heating_type: NONE and an electric bill passes (Case 1, household 2). This is not the Delaware problem. The only households turned away beyond the income test are those with no cooling cost, and those with an unspecified fuel (Should address 1).
  • Cap: $200+75+50+50+50+175+175 = $775 and $300+50+50+50+50+150+200 = $850, so the cap equals the sum of the parts in both years and never binds.

Critical (must fix)

1. Program year 2027 allows one assistance, but the model pays heating and cooling together and sums both in liheap

policyengine_us/variables/gov/states/sc/oeo/liheap/cooling/sc_liheap_cooling.py:31-39, policyengine_us/parameters/gov/hhs/liheap/regular_payments.yaml:46-47, policyengine_us/programs.yaml:1359-1360, cooling/amounts.yaml (the 2026-10-01 values).

Governing text, FY2027 plan, item 11.5 (p. 26):

"To extend LIHEAP services to new households, South Carolina will offer one LIHEAP assistance (either emergency or nonemergency) during the 2027 program year. Eligible households may receive a LIHEAP benefit up to: $1,000 for year-round crisis, $1,000 during the nonemergency heating season, or $850 during the nonemergency cooling season."

Item 11.4 on the same page shows this was a decision, not a slip: the community action directors asked OEO to "allow two services per year", and 11.5 is the answer. Item 1.1 (p. 4) says the same: "LIHEAP eligible households may receive one service during the calendar year. Should funding allow, the State may allow additional services during the program year." South Carolina's program year is the calendar year (2024 guide, plan attachments p. 523), so heating in January-April 2027 and cooling in May-September 2027 fall in one program year.

The FY2026 rule is different, which is why 2026 is fine: "A maximum of two LIHEAP services may be provided during the program year" (FY2026 plan, item 11.5, p. 26), and the 2024 guide (attachments p. 536) and draft 2026 guide (p. 310): "LIHEAP-eligible households may receive assistance a maximum of two times during the program year."

What the head does in 2027: sc_liheap_cooling_eligible is sc_liheap_eligible plus two more conditions, so every household that gets the cooling award also gets the heating award. liheap adds the two.

Household (the PR's own Case 4, household 1, period 2027): one person aged 67, $24,000 of Social Security retirement, electric heat, $1,800 electric bill, cooling cost.

  • Head, by hand trace: sc_liheap_cooling = 300 + 50 = $350 (tested); sc_liheap = 200 + 75 = $275 (the heating file has only 2025-10-01 values); liheap = $625.
  • Plan: one assistance, so at most $350 (the cooling award; the FY2027 heating award for this household is also 300 + 50 = $350).

The Case 5 household in 2027 gets $850 + $850 = $1,700 against a plan ceiling of $1,000 for one assistance. The overstatement is not an edge case: it applies to every 2027 cooling recipient.

The PR discloses that "the service limits are not modeled", and the code comment quotes item 1.1. But the registry entry claims verified_years: "2026-2027" and says the award is "paid alongside the heating award", the comment leaves out item 11.5 (the firmer statement in both years), and the national total double counts.

Fix, either of:

  • Model the rule. Add a dated parameter for the number of nonemergency awards a household may receive in a program year (2 from 2025-10-01, citing FY2026 plan 11.5 and the guide; 1 from 2026-10-01, citing FY2027 plan 1.1 and 11.5). When it is 1, make the two variables sum to one award, for example by paying in sc_liheap_cooling only the excess of the cooling award over the heating award, so the total is the larger of the two. Add a 2027 case that pins liheap.
  • Or take FY2027 out of this PR. Drop the 2026-10-01 values, set verified_years: "2026" and the documentation string to match, and bring FY2027 heating ($300 base, $1,000 maximum), FY2027 cooling and the one-assistance rule in together in the heating follow-up the body already plans. The registry note should then say that 2027 is unverified and that the one-assistance rule is not applied.

Either way, cite item 11.5 for both years in the comment at lines 31-36, limit "paid alongside the heating award" to FY2026 in the registry note, and update interpretation 1 in rulespec-us#2181, which calls paying both in every year a "settled modeling choice".

Should address

1. A renter with heat in the rent and an unspecified fuel gets the heating award but no cooling award; the body's reason is inaccurate

policyengine_us/variables/gov/states/sc/oeo/liheap/cooling/sc_liheap_cooling_eligible.py:22-30.

The body says "heating_type UNSPECIFIED pays $0, as in every state LIHEAP program". South Carolina's own heating variable does not: sc_liheap_eligible.py:46 is (has_energy_cost & known_fuel) | heat_in_rent, so an unspecified fuel with heat in the rent is paid. The PR's own case shows it (sc_liheap_cooling_eligible.yaml Case 1, household 2: sc_liheap 200, sc_liheap_cooling 0). The extra & known_fuel in the cooling gate removes that route.

No South Carolina source supports the exclusion. Direct Assistance asks only that the household "must not exceed 60% of the state median income and prove it has an obligation or responsibility to pay its home energy bill" (guide, p. 536), and plan item 3.3 (p. 10, rendered page checked for both years) answers No to different policies for renters, renters in subsidized housing and renters with utilities included in the rent. The HeatingType enum also documents UNSPECIFIED as "the right value when heat is included in rent and the tenant does not know the building's fuel", so this household has given a complete answer.

Household (2026): one adult aged 40, wages $20,800, renter with heat_expense_included_in_rent: true, heating_type: UNSPECIFIED, own electric bill $1,800, has_cooling_expense: true.

  • Rule: income under $31,993, a home energy bill to pay, a cooling cost: $200 cooling base.
  • Head: sc_liheap = $200 (for heat the household does not pay separately), sc_liheap_cooling = $0.

Fix: drop the extra term so the gate is sc_liheap_eligible & has_cooling_expense. The heating gate already applies the unspecified-fuel convention where it belongs (an unspecified fuel with no heat in the rent still gets nothing). Change the Case 1 expectation for household 2 to true and 200, and correct the sentence in the body and the comment at lines 22-23. If the exclusion is kept, label it in the comment and the body as a modeling convention that is narrower than the state's heating treatment, not as something every state does.

2. Three existing South Carolina source-conflict records now cover a year and a payment they do not list

source_conflicts/candidates.yaml on main: us-sc:liheap-low-income-tier-base (ruled 2026-11-03), us-sc:liheap-energy-burden-test (unreviewed) and us-sc:liheap-mixed-status-household (ruled 2026-11-02). Each has years: 2026 to 2026 and lists sc_liheap.py. The paths are still right (the deciding lines moved into sc_liheap_award in the same file), but the cooling award now applies all three readings to FFY2027, which the PR marks as verified, and the body says "Source-conflict register: not applicable". CONTRIBUTING.md (Source conflicts, step 1): "If the backlog already lists the conflict, it updates that item instead."

  • Low-income tier: the FY2027 plan again says "at or below 30% of the State's Median Income guidelines" (p. 10). The model uses 30% of the 60% limit, the 2026 ruling, whose basis was OEO's draft 2026 guide; no FY2027 guide exists. For one person in 2027 that is $9,965.40 against $16,609.32 on the full median: a person with $12,000 gets $300 or $450.
  • Energy burden: the guides measure "only the current month's home energy cost"; in the cooling season that is the summer electric bill. The annual sum includes winter fuel. In Cases 3 and 5 the burden supplement exists only because of the $600 gas bill ($2,400 >= $1,920, but $1,800 < $1,920).

Fix: extend years.to to 2027 on the three items (or state in each that FFY2027 follows the 2026 ruling by extension), add this PR under pe_us.prs, add the cooling consequence to the energy-burden item, and replace "not applicable" in the body.

Suggestions

  1. A mixed-status cooling case. By my reading the proration line in sc_liheap_award is pinned by sc_liheap.yaml Cases 8 and 9, so no single-line mutation survives. Nothing pins that the cooling award itself is prorated. rulespec-us#2181 already works one out (companion test 10); adding it to sc_liheap_cooling.yaml is one case.
  2. Label has_cooling_expense as a model input. The comment at sc_liheap_cooling_eligible.py:20-21 says the award "pays only households with cooling costs". The sources state no separate cooling-cost test: the guide ties Direct Assistance to a home energy bill and says it "may be used to pay home heating and/or cooling costs" (p. 537). The body words it correctly; the comment should too.
  3. Homes without heating now get both awards. Case 1, household 2 (heating_type: NONE) pins sc_liheap 200 and sc_liheap_cooling 200. On main the stated reason for paying the heating variable to a home without heating was that "the one regular award pays heating or cooling costs"; this PR rewrites that comment (sc_liheap_eligible.py:35-38) and adds a separate cooling award. Either say why a home with no heating receives the heating-season award as well (the guide's test is any home energy bill), or gate sc_liheap on a heating fuel in the heating follow-up.
  4. References for the shared parameters. payment/ages.yaml, burden_rate.yaml, low_income_limit_rate.yaml, energy_cost_sources.yaml and eligibility/smi_rate.yaml cite only FY2026 section 2. The cooling award reads them for section 3 and for FY2027. The values agree in both plans (60, 5, 30%, 20%, 60% of state median income); adding the section 3 and FY2027 references would back the 2027 claim.
  5. Two source notes for cooling/amounts.yaml. (a) The FY2027 "Other" row (p. 10) prints "a base nonemergency energy benefit of $200" while every other FY2027 statement and item 3.6 say $300; a one-line comment would record why 300 is used. (b) The 2026 Benefit Matrix supports FY2026 only, and no FY2027 matrix is published on the Clearinghouse (the 2027 file names tried return 404), so the FY2027 values rest on the plan alone.
  6. rulespec-us#2181 still says CI has not run at this head; it has.

Verified correct

  • Amounts, FY2026 (plan pp. 10-11, matrix p. 1, guide pp. 536 and 538): base 200, elderly 75, disabled 50, child 50, veteran 50, low income 175, burden 175, maximum 775. "The maximum nonemergency benefit during the cooling season is $775" (p. 11); "(no fuel benefit awarded May 1 – September 30)" (matrix); "(6)Fuel (not provided during cooling season)" (guide p. 538). The plan's section 3 text still lists "heats with fuel ($75)", but its own $775 maximum is the sum without it.
  • Amounts, FY2027 (plan pp. 10-11): base 300, elderly 50, disabled 50, child 50, veteran 50, low income 150, burden 200, maximum 850; "Minimum Benefit $300 Maximum Benefit $850". Cover: "Report Status: Submission Accepted by CO (Revision Run black formatting on docs #2)", period 10/01/2026 to 09/30/2027.
  • Definitions: elderly "age 60 or older" (elderly_min 60); child "age 5 and younger" (completed age 5 or less); disabled and veteran from is_disabled and is_veteran; burden "20% or more of income used for utilities"; low income at 30% of the 60% limit (the recorded 2026 ruling). Each supplement counts once per household.
  • Start dates: 2025-10-01 values are read by calendar 2026 and 2026-10-01 values by 2027, so a summer 2026 award uses the FY2026 schedule and a summer 2027 award the FY2027 schedule.
  • Income limit: 60% of state median income for cooling in both years (item 3.1), the same as heating; the 110% poverty floor carries over through sc_liheap_eligible. One person: floor(floor(102,542 x 0.6) x 0.52) = $31,993 in 2026 and floor(63,882 x 0.52) = $33,218 in 2027; two people $41,837 and $43,439.
  • Refactor, line by line: sc_liheap_award holds main's lines 21-43 and 46-64 unchanged; the fuel term is passed in and still added last, so the order of addition, the cap and the proration are identical. sc_liheap returns exactly what main returns. No existing test file is touched. Other readers of sc_liheap: the regular_payments list and the registry only. sc_liheap_eligible.py and payment/ages.yaml change only a comment and a description.
  • Hand-checked expectations (all agree):
Case Household Arithmetic Expected
1, hh 1 (2026) 40, wages 20,800, gas heat, gas 600 + electric 1,800 20,800 > 9,597.90; 2,400 < 4,160; no fuel amount cooling 200; heating 200 + 75 = 275
1, hh 2 same, NONE, electric 1,800 base only cooling 200; heating 200
2, hh 1 67, Social Security 24,000 200 + 75 275
2, hh 2 30 with a child of 3; two-person tier 12,551.10 200 + 50 250
2, hh 5 wages 9,048, electric 1,500 9,048 <= 9,597.90; 1,500 < 1,809.60; 200 + 175 375
2, hh 6 wages 10,400, electric 2,400 10,400 > 9,597.90; 2,400 >= 2,080; 200 + 175 375
3 64, disabled, veteran, SSDI 9,600, child 4, gas 600 + electric 1,800 200 + 75 + 50 + 50 + 50 + 175 + 175 cooling 775; heating 850; liheap 1,625
4, hh 1 (2027) as 2, hh 1 300 + 50 350
4, hh 5 as 2, hh 5 9,048 <= 9,965.40; 300 + 150 450
4, hh 6 as 2, hh 6 10,400 > 9,965.40; 2,400 >= 2,080; 300 + 200 500
5 (2027) as 3 9,600 <= 13,031.70; 300 + 50 + 50 + 50 + 50 + 150 + 200 850
eligible 1, hh 3 wages 32,240 32,240 > 31,993 and not below 15,650 x 1.1 = 17,215 not eligible, 0
  • Mutation rule, by my reading: income gate (eligible Case 1, hh 3), has_cooling_expense (hh 1), unspecified fuel (hh 2), the zero fuel amount (Case 1, hh 1 and Case 3), every FY2026 amount (Cases 1-3), every changed FY2027 amount (Cases 4-5), and the regular_payments line (Case 3, liheap 1,625). The cap cannot bind in either year, so no case can show it.
  • National total and registry: sc_liheap_cooling is a USD amount on the SPM unit, YEAR, gated to South Carolina through sc_liheap_cooling_eligible, and not a component of another listed variable. The second registry entry has its own name, so labels stay unique; test_liheap_total_sums_every_registered_state_payment requires both South Carolina variables in the list and both are there; LIHEAP_PAYMENT_STAND_INS needs no entry.
  • Mixed-state and keyed lookups: the cooling path has no parameter keyed by a state-gated value; all four South Carolina inputs it reads are gated to StateCode.SC and the award is gated by the eligibility flag.
  • Periods: all YEAR; no options=[ADD]; the foster-care read at period.first_month is unchanged from main.
  • Hygiene: parameter description, label, unit, period and references present; variable label, unit, references and defined_for present; tests sit in variable-named files; changelog fragment changelog.d/sc-liheap-cooling.added.md.
  • PR body quotes: each quoted sentence was found at the cited page (FY2026 plan pp. 4, 10-11; FY2027 plan p. 4; matrix p. 1).

Axiom line assessment

axiom: TheAxiomFoundation/rulespec-us#2181 queued. The issue is OPEN, labelled pe-parity, names head b5e3dccff0, and is dispatch-ready: module paths, corpus status, verbatim source text, required outputs and ten companion tests worked from the sources. It matches the head. It will need an update with the fix to Critical 1 (interpretation 1) and Should address 1 (interpretation 7 and companion test 8).

CI status

All 36 checks pass at b5e3dccff0 (run 43287800621, completed 2026-11-12), including the four Baseline state shards that run the new YAML files. Nothing pending.

Branch status

15 commits ahead of main and 12 behind (cc486336d7). git merge-tree against current main is clean. Test merges against the eight sibling heads (#10744, #10746, #10748, #10750, #10752, #10756, #10758, #10760) are all clean, including regular_payments.yaml, programs.yaml and source_conflicts/candidates.yaml.

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. The amounts are right for both years, the start dates put FY2026 in calendar 2026 and FY2027 in 2027, the cap equals the sum of the parts, and the refactor leaves sc_liheap identical to main. For 2026, paying both heating and cooling is backed: "A maximum of two LIHEAP services may be provided during the program year" (FY2026 plan item 11.5).

  1. Critical: 2027 allows one assistance, and the PR pays both. FY2027 plan item 11.5 (p. 26): "South Carolina will offer one LIHEAP assistance (either emergency or nonemergency) during the 2027 program year", and item 1.1 says households "may receive one service during the calendar year". The program year is the calendar year, so winter heating and summer cooling 2027 fall in one year. At this head every 2027 cooling recipient also gets the heating award, liheap sums both, and the registry claims verified_years: "2026-2027". Either model the one-award rule for 2027, or take the FY2027 values out of this PR and set the registry to 2026.
  2. The UNSPECIFIED exclusion. South Carolina's own heating variable pays a renter with heat in the rent and an unspecified fuel (Case 1, household 2 gets $200 heating and $0 cooling), and the description's "as in every state LIHEAP program" isn't accurate here. Drop the extra term or label it a convention.
  3. Three existing SC source-conflict records now apply to FY2027 and the cooling award without being updated (low-income tier, energy burden, mixed status). Extend their years and list this PR.

Fixes and worked households are in the report above. CI is green at b5e3dccff0.

@hua7450

hua7450 commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator Author

This push (5f487892d2) models the FY2027 one-award limit, drops the cooling gate's fuel condition and extends the three South Carolina candidates; upstream main is merged in.

  • Critical 1. Modeled, your first option.
    • New payment/max_awards.yaml: 2 from 2025-10-01 (FY2026 plan item 11.5; guides, Section 3A, pp. 310 and 536) and 1 from 2026-10-01 (FY2027 plan items 1.1 and 11.5, pp. 4 and 26).
    • When it is 1, sc_liheap_cooling returns max_(award - sc_liheap, 0), so heating plus cooling, and liheap, equal the larger award. The comment cites item 11.5 for both years and says the 2027 heating amounts are FY2026 carry-forwards.
    • sc_liheap_cooling.yaml Case 4 now also pins sc_liheap [275, 250, 250, 250, 375, 375] and expects cooling [75, 100, 100, 100, 75, 125] (was [350, 350, 350, 350, 450, 500]), so your household 1 totals $350. Case 5 pins heating $850 and cooling $0 (was $850).
    • New Case 6 (2027) pins liheap for two households eligible for both: gas heat with wages $20,800 gets 275 + 25 = $300, and a person aged 62 with $9,600 of Social Security gets 525 + 0 = $525, which pins the floor.
    • The registry note limits "paid alongside the heating award" to FY2026 and says "Local frequency limits" instead of "Service-frequency limits"; verified_years stays "2026-2027".
    • The FY2027 heating award has the cooling base and supplements plus a $150 fuel supplement, up to $1,000 (item 2.5, p. 9). Once it is added, heating will be at least cooling for every household, so 2027 cooling will pay $0. The body's "Not modeled" says so.
  • Should address 1. The gate is now sc_liheap_eligible & has_cooling_expense; sc_liheap_eligible.py is unchanged. In sc_liheap_cooling_eligible.yaml Case 1, household 2 now expects true and $200, with "Was" comments, and the case name and file header match. The comment and the body sentence are corrected, and "as in every state LIHEAP program" is gone.
  • Should address 2. us-sc:liheap-low-income-tier-base, us-sc:liheap-energy-burden-test and us-sc:liheap-mixed-status-household now have years.to: 2027 and list cooling/sc_liheap_cooling.py under pe_us.code and this PR under pe_us.prs. The energy-burden note adds the cooling consequence: winter fuel bills count toward the cooling-season burden, where the guides' current-month test would count only the summer bill. The body's register line now names the three candidates.

Suggestions:

  • 1. New Case 7 in sc_liheap_cooling.yaml (2026): an undocumented parent aged 30 with wages $20,800 and a citizen child aged 3 get (200 + 50) / 2 x 1 = $125, with sc_liheap_household_size 1. It is a smaller household than companion test 10, which stays in the issue.
  • 2. The comment in sc_liheap_cooling_eligible.py now calls has_cooling_expense a PolicyEngine convention, since OEO's texts set no separate cooling-cost test.
  • 3. Not changed here: the cooling PRs leave each state's heating eligibility variable as it is. The comment at sc_liheap_eligible.py:35-38 already gives the reason you name: OEO asks for an obligation to pay a home energy bill, and Direct Assistance may pay heating or cooling costs, so any counted bill qualifies, including in a home without heating. A heating-fuel gate on sc_liheap would belong in the heating follow-up.
  • 4. payment/ages.yaml, burden_rate.yaml, low_income_limit_rate.yaml, energy_cost_sources.yaml and eligibility/smi_rate.yaml now cite FY2026 section 3 and the FY2027 plan, one entry per plan with the pages in the title.
  • 5. cooling/amounts.yaml now notes that FY2027 items 3.3, 3.5 and 3.6 give a 300 base and only the item 3.3 "Other" row prints 200, and that the 2026 Benefit Matrix covers FY2026 only, so the FY2027 values rest on the plan.
  • 6. LIHEAP cooling: encode South Carolina LIHEAP cooling-season Direct Assistance award, paid apart from the heating award (PE-US PR 10754) TheAxiomFoundation/rulespec-us#2181 is updated: the head, the review and CI sentences, scope, policy periods, parameters, tests, required outputs, interpretations 1 (now the modeled award limit), 4 to 8, 12 and 13, companion tests 5, 6 and 8, and new companion tests 12 (Case 6) and 13 (Case 7).

CI is running at 5f487892d2.

@hua7450
hua7450 requested a review from DTrim99 November 13, 2026 20:37

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement South Carolina LIHEAP regular cooling assistance

2 participants