From 63b78688f9f3e807886b653ac44f089a677c4d58 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 23 Oct 2026 18:11:07 -0400 Subject: [PATCH 1/2] Add Tennessee LIHEAP regular energy assistance Co-Authored-By: Claude Opus 5.5 --- changelog.d/tn-liheap-wave1d.added.md | 1 + .../tn/thda/liheap/eligibility/fpg_rate.yaml | 34 ++ .../thda/liheap/eligibility/fpg_year_lag.yaml | 21 + .../tn/thda/liheap/eligibility/smi_rate.yaml | 21 + .../liheap/income/earned_income_min_age.yaml | 20 + .../liheap/income/interest_threshold.yaml | 20 + .../tn/thda/liheap/income/sources/earned.yaml | 23 + .../thda/liheap/income/sources/unearned.yaml | 49 ++ .../states/tn/thda/liheap/payment/amount.yaml | 505 ++++++++++++++++ .../tn/thda/liheap/payment/burden_column.yaml | 64 +++ .../thda/liheap/payment/burden_decimals.yaml | 16 + .../liheap/payment/energy_cost_sources.yaml | 28 + .../liheap/payment/income_group/fpg_rate.yaml | 22 + .../payment/income_group/max_table_size.yaml | 11 + .../liheap/payment/income_group/top/A.yaml | 48 ++ .../liheap/payment/income_group/top/B.yaml | 48 ++ .../liheap/payment/income_group/top/C.yaml | 48 ++ .../payment/income_group/uses_fpg_rates.yaml | 17 + .../thda/liheap/payment/propane_minimum.yaml | 18 + .../tn/thda/liheap/payment/size_group.yaml | 39 ++ policyengine_us/programs.yaml | 10 +- .../eligibility/tn_liheap_eligible.yaml | 235 ++++++++ .../eligibility/tn_liheap_income_limit.yaml | 203 +++++++ .../income/tn_liheap_countable_income.yaml | 299 ++++++++++ .../gov/states/tn/thda/liheap/tn_liheap.yaml | 544 ++++++++++++++++++ .../liheap/eligibility/tn_liheap_eligible.py | 47 ++ .../eligibility/tn_liheap_income_limit.py | 39 ++ .../income/tn_liheap_countable_income.py | 62 ++ .../gov/states/tn/thda/liheap/tn_liheap.py | 92 +++ .../thda/liheap/tn_liheap_household_size.py | 23 + 30 files changed, 2606 insertions(+), 1 deletion(-) create mode 100644 changelog.d/tn-liheap-wave1d.added.md create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/fpg_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/smi_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/income/earned_income_min_age.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/income/interest_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/earned.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/unearned.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/amount.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/burden_column.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/burden_decimals.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/energy_cost_sources.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/fpg_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/max_table_size.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/A.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/B.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/C.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/uses_fpg_rates.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/propane_minimum.yaml create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/payment/size_group.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_income_limit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/tn_liheap.yaml create mode 100644 policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.py create mode 100644 policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_income_limit.py create mode 100644 policyengine_us/variables/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.py create mode 100644 policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap.py create mode 100644 policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap_household_size.py diff --git a/changelog.d/tn-liheap-wave1d.added.md b/changelog.d/tn-liheap-wave1d.added.md new file mode 100644 index 00000000000..114292e50de --- /dev/null +++ b/changelog.d/tn-liheap-wave1d.added.md @@ -0,0 +1 @@ +Add Tennessee LIHEAP regular energy assistance. diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/fpg_rate.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/fpg_rate.yaml new file mode 100644 index 00000000000..a40723de439 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/fpg_rate.yaml @@ -0,0 +1,34 @@ +description: Tennessee sets the regular assistance income limit at this multiple of the federal poverty guideline, by household size, under the Low Income Home Energy Assistance Program. +# A zero rate means the state median income limit applies. FY2026 uses 60% of +# state median income for every size. FY2027 uses 150% of the poverty +# guideline for sizes 9 and over, with upper limits rounded down to the +# nearest dollar. The draft plan lists sizes 9-15 and the draft manual sizes +# 9-16; larger households carry the same rate. The LI-12 matrix prints size +# 13-16 ceilings of $125,910 to $150,660, below 150% of the 2026 guideline +# ($126,180 to $151,740); these sizes follow the stated 150% rule. +brackets: + - threshold: + 2025-10-01: 0 + amount: + 2025-10-01: 0 + - threshold: + 2025-10-01: 9 + amount: + 2025-10-01: 0 + 2026-10-01: 1.5 + +metadata: + type: single_amount + threshold_unit: person + amount_unit: /1 + period: year + label: Tennessee LIHEAP poverty guideline income limit rate + reference: + - title: Tennessee FY2026 LIHEAP State Plan, Section 2.1 + href: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=8 + - title: "Tennessee FY2027 LIHEAP State Plan (draft), Sections 2.1 and 2.5 #page 9,12" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DETAILED-MODEL-PLAN-LIHEAP_10_01_2026.pdf#page=9 + - title: Tennessee LIHEAP 2027 Policy Manual (draft), Section 2.10 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=27 + - title: "Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), household sizes 9-16 #page 3-4" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=3 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/fpg_year_lag.yaml new file mode 100644 index 00000000000..a4762cd3c52 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/fpg_year_lag.yaml @@ -0,0 +1,21 @@ +description: Tennessee uses the federal poverty guidelines from this many years before the model year for the poverty-based income limit, matrix income groups and federal income floor under the Low Income Home Energy Assistance Program. +# HHS made the 2025 guidelines mandatory for LIHEAP from October 1, 2025, so +# model period 2026 (FY2026) uses the 2025 guidelines and 2027 (FY2027) the +# 2026 guidelines. The FY2026 matrix income groups and the FY2027 size 9-12 +# ceilings reproduce from these guideline years. +values: + 2025-10-01: 1 + +metadata: + unit: year + period: year + label: Tennessee LIHEAP poverty guideline year lag + reference: + - title: LIHEAP IM 2025-02, Attachment 2, poverty guidelines for mandatory use in FY26 + href: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_FPGSte-Table_Att2.pdf#page=1 + - title: 42 U.S.C. 8624(b)(2)(B) + href: https://www.law.cornell.edu/uscode/text/42/8624#b_2_B + - title: Tennessee LIHEAP 2026 Benefit Matrix, income start and end + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf + - title: Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), household sizes 9-12 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=3 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/smi_rate.yaml new file mode 100644 index 00000000000..ffbe6ad854f --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/eligibility/smi_rate.yaml @@ -0,0 +1,21 @@ +description: Tennessee limits regular assistance income to this share of state median income under the Low Income Home Energy Assistance Program. +# FY2026 applies this rate to every household size. FY2027 applies it to +# sizes 1-8; fpg_rate sets 150% of the poverty guideline for sizes 9 and over. +values: + 2025-10-01: 0.6 + +metadata: + unit: /1 + period: year + label: Tennessee LIHEAP state median income rate + reference: + - title: Tennessee FY2026 LIHEAP State Plan, Section 2.1 + href: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=8 + - title: Tennessee LIHEAP 2026 Policy Manual, Section 2.10 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=24 + - title: Tennessee LIHEAP 2026 Benefit Matrix, income end + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf + - title: Tennessee FY2027 LIHEAP State Plan (draft), Section 2.1 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DETAILED-MODEL-PLAN-LIHEAP_10_01_2026.pdf#page=9 + - title: Tennessee LIHEAP 2027 Policy Manual (draft), Section 2.10 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=27 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/earned_income_min_age.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/earned_income_min_age.yaml new file mode 100644 index 00000000000..3502edebf10 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/earned_income_min_age.yaml @@ -0,0 +1,20 @@ +description: Tennessee counts the earned income of household members at least this age who are not tax-unit dependents under the Low Income Home Energy Assistance Program. +# The FY2026 plan leaves the earned income of a child under 18 unchecked, and +# the manual defines a child as any member under 18. The manual also excludes +# the earned income of a dependent 18 or older and of a dependent in school +# living with a parent or guardian; tax-unit dependency stands in for both, +# because no input records the dependency relationship the manual names. +values: + 2025-10-01: 18 + +metadata: + unit: year + period: year + label: Tennessee LIHEAP earned income minimum age + reference: + - title: "Tennessee LIHEAP 2026 Policy Manual, Sections 1.2 and 2.13 #page 8,28" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=8 + - title: Tennessee FY2026 LIHEAP State Plan, Section 1.9 + href: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=6 + - title: Tennessee LIHEAP 2027 Policy Manual (draft), Section 2.13 exclusions + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=30 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/interest_threshold.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/interest_threshold.yaml new file mode 100644 index 00000000000..7472745abdd --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/interest_threshold.yaml @@ -0,0 +1,20 @@ +description: Tennessee counts a household member's interest income only when it exceeds this annual amount under the Low Income Home Energy Assistance Program. +# Interest counts only if it exceeds $200 annually and is withdrawn. No input +# records withdrawals, so interest above the threshold is assumed withdrawn +# and counts in full; interest at or below it is not counted. The draft 2027 +# manual lists "Dividends and/or interest that $200 annually and is +# withdrawn", which may extend the threshold to dividends. The model keeps +# the 2026 manual's interest-only threshold, with dividends counted in full, +# until a final 2027 manual is posted. +values: + 2025-10-01: 200 + +metadata: + unit: currency-USD + period: year + label: Tennessee LIHEAP interest income threshold + reference: + - title: Tennessee LIHEAP 2026 Policy Manual, Section 2.13 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=27 + - title: Tennessee LIHEAP 2027 Policy Manual (draft), Section 2.13 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=29 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/earned.yaml new file mode 100644 index 00000000000..08e1df23085 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/earned.yaml @@ -0,0 +1,23 @@ +description: Tennessee counts these sources as earned income of adult members who are not tax-unit dependents under the Low Income Home Energy Assistance Program. +# Wages, commissions, salaries and tips before deductions, and net receipts +# from a person's own business or an owned or rented farm after business or +# farm expenses. The existing net business inputs get no further deduction, +# and each source is floored at zero, so a loss in one source cannot offset +# another. +values: + 2025-10-01: + - employment_income + - self_employment_income + - sstb_self_employment_income + - farm_operations_income + - partnership_s_corp_income + +metadata: + unit: list + period: year + label: Tennessee LIHEAP earned income sources + reference: + - title: Tennessee LIHEAP 2026 Policy Manual, Section 2.13 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=27 + - title: "Tennessee FY2026 LIHEAP State Plan, Sections 1.8-1.9 #page 5-7" + href: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/unearned.yaml new file mode 100644 index 00000000000..e59041d7e57 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/unearned.yaml @@ -0,0 +1,49 @@ +description: Tennessee counts these sources as unearned income of all household members under the Low Income Home Energy Assistance Program. +values: + 2025-10-01: + - ssi + - general_assistance + - railroad_benefits + - total_unemployment_compensation + # Strike benefits from union funds. + - strike_benefits + - workers_compensation + - veterans_benefits + - child_support_received + - alimony_income + # Money regularly received from an absent family member or someone not + # living in the household. + - financial_assistance + # Private and government pensions, annuities and regular insurance + # payments. + - pension_income + - military_retirement_income + - survivor_benefits + - disability_benefits + - ordinary_dividend_income + # Net rental income. + - rental_income + - farm_rent_income + # Periodic receipts from estates or trusts. + - estate_income +# Social Security net of the Medicare Part B premium, interest above the +# annual threshold, net gambling winnings and TANF (Families First) are +# counted in tn_liheap_countable_income. Capital gains, bank withdrawals, sale +# proceeds, tax refunds, gifts, loans, inheritances and SNAP are excluded. +# Retirement-account (IRA or 401(k)) withdrawals are not counted either: the +# Section 2.13 income list names pensions, annuities and regular insurance +# payments but not retirement-account withdrawals, and the exclusions name +# only bank-account withdrawals, so the model treats retirement-account +# withdrawals like bank withdrawals. Black Lung benefits with their first $20 +# monthly disregard, royalties, severance pay, adoption assistance, training +# stipends, military family allotments and irregular income have no existing +# input. +metadata: + unit: list + period: year + label: Tennessee LIHEAP unearned income sources + reference: + - title: "Tennessee LIHEAP 2026 Policy Manual, Section 2.13 #page 27-28" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=27 + - title: "Tennessee FY2026 LIHEAP State Plan, Sections 1.8-1.9 #page 5-7" + href: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/amount.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/amount.yaml new file mode 100644 index 00000000000..20bc9e36707 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/amount.yaml @@ -0,0 +1,505 @@ +description: Tennessee provides this regular benefit by household size group, income group and energy burden column under the Low Income Home Energy Assistance Program. +# Rows are identical within each size group in both matrices, so one +# representative size is transcribed per group. The FY2026 plan's $174 +# minimum and $750 maximum (Section 2.6) and the draft FY2027 plan's $300 +# and $800 equal the lowest and highest cells. FY2027 values come from the +# posted LI-12 matrix; the FY2027 plan and manual are drafts. Group 4 also +# covers households larger than the printed sizes. +# Household size 1-2. +1: + # Income group A. + 1: + 1: + 2025-10-01: 174 + 2026-10-01: 300 + 2: + 2025-10-01: 270 + 2026-10-01: 383 + 3: + 2025-10-01: 320 + 2026-10-01: 427 + 4: + 2025-10-01: 380 + 2026-10-01: 479 + 5: + 2025-10-01: 470 + 2026-10-01: 557 + 6: + 2025-10-01: 560 + 2026-10-01: 635 + 7: + 2025-10-01: 710 + 2026-10-01: 765 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group B. + 2: + 1: + 2025-10-01: 174 + 2026-10-01: 300 + 2: + 2025-10-01: 250 + 2026-10-01: 366 + 3: + 2025-10-01: 305 + 2026-10-01: 414 + 4: + 2025-10-01: 370 + 2026-10-01: 470 + 5: + 2025-10-01: 450 + 2026-10-01: 540 + 6: + 2025-10-01: 555 + 2026-10-01: 631 + 7: + 2025-10-01: 705 + 2026-10-01: 761 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group C. + 3: + 1: + 2025-10-01: 174 + 2026-10-01: 300 + 2: + 2025-10-01: 250 + 2026-10-01: 366 + 3: + 2025-10-01: 305 + 2026-10-01: 414 + 4: + 2025-10-01: 370 + 2026-10-01: 470 + 5: + 2025-10-01: 445 + 2026-10-01: 535 + 6: + 2025-10-01: 550 + 2026-10-01: 626 + 7: + 2025-10-01: 700 + 2026-10-01: 757 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group D. + 4: + 1: + 2025-10-01: 174 + 2026-10-01: 300 + 2: + 2025-10-01: 250 + 2026-10-01: 366 + 3: + 2025-10-01: 305 + 2026-10-01: 414 + 4: + 2025-10-01: 370 + 2026-10-01: 470 + 5: + 2025-10-01: 445 + 2026-10-01: 535 + 6: + 2025-10-01: 540 + 2026-10-01: 618 + 7: + 2025-10-01: 700 + 2026-10-01: 757 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 +# Household size 3-5. +2: + # Income group A. + 1: + 1: + 2025-10-01: 240 + 2026-10-01: 357 + 2: + 2025-10-01: 385 + 2026-10-01: 483 + 3: + 2025-10-01: 410 + 2026-10-01: 505 + 4: + 2025-10-01: 480 + 2026-10-01: 566 + 5: + 2025-10-01: 540 + 2026-10-01: 618 + 6: + 2025-10-01: 600 + 2026-10-01: 670 + 7: + 2025-10-01: 720 + 2026-10-01: 774 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group B. + 2: + 1: + 2025-10-01: 225 + 2026-10-01: 344 + 2: + 2025-10-01: 270 + 2026-10-01: 383 + 3: + 2025-10-01: 340 + 2026-10-01: 444 + 4: + 2025-10-01: 410 + 2026-10-01: 505 + 5: + 2025-10-01: 470 + 2026-10-01: 557 + 6: + 2025-10-01: 555 + 2026-10-01: 631 + 7: + 2025-10-01: 720 + 2026-10-01: 774 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group C. + 3: + 1: + 2025-10-01: 225 + 2026-10-01: 344 + 2: + 2025-10-01: 270 + 2026-10-01: 383 + 3: + 2025-10-01: 340 + 2026-10-01: 444 + 4: + 2025-10-01: 400 + 2026-10-01: 496 + 5: + 2025-10-01: 450 + 2026-10-01: 540 + 6: + 2025-10-01: 540 + 2026-10-01: 618 + 7: + 2025-10-01: 710 + 2026-10-01: 765 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group D. + 4: + 1: + 2025-10-01: 225 + 2026-10-01: 344 + 2: + 2025-10-01: 270 + 2026-10-01: 383 + 3: + 2025-10-01: 340 + 2026-10-01: 444 + 4: + 2025-10-01: 390 + 2026-10-01: 488 + 5: + 2025-10-01: 445 + 2026-10-01: 535 + 6: + 2025-10-01: 540 + 2026-10-01: 618 + 7: + 2025-10-01: 700 + 2026-10-01: 757 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 +# Household size 6-8. +3: + # Income group A. + 1: + 1: + 2025-10-01: 320 + 2026-10-01: 427 + 2: + 2025-10-01: 525 + 2026-10-01: 605 + 3: + 2025-10-01: 565 + 2026-10-01: 639 + 4: + 2025-10-01: 645 + 2026-10-01: 709 + 5: + 2025-10-01: 720 + 2026-10-01: 774 + 6: + 2025-10-01: 750 + 2026-10-01: 800 + 7: + 2025-10-01: 750 + 2026-10-01: 800 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group B. + 2: + 1: + 2025-10-01: 300 + 2026-10-01: 409 + 2: + 2025-10-01: 385 + 2026-10-01: 483 + 3: + 2025-10-01: 500 + 2026-10-01: 583 + 4: + 2025-10-01: 580 + 2026-10-01: 652 + 5: + 2025-10-01: 680 + 2026-10-01: 739 + 6: + 2025-10-01: 750 + 2026-10-01: 800 + 7: + 2025-10-01: 750 + 2026-10-01: 800 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group C. + 3: + 1: + 2025-10-01: 300 + 2026-10-01: 409 + 2: + 2025-10-01: 385 + 2026-10-01: 483 + 3: + 2025-10-01: 500 + 2026-10-01: 583 + 4: + 2025-10-01: 580 + 2026-10-01: 652 + 5: + 2025-10-01: 680 + 2026-10-01: 739 + 6: + 2025-10-01: 750 + 2026-10-01: 800 + 7: + 2025-10-01: 750 + 2026-10-01: 800 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group D. + 4: + 1: + 2025-10-01: 300 + 2026-10-01: 409 + 2: + 2025-10-01: 385 + 2026-10-01: 483 + 3: + 2025-10-01: 500 + 2026-10-01: 583 + 4: + 2025-10-01: 580 + 2026-10-01: 652 + 5: + 2025-10-01: 680 + 2026-10-01: 739 + 6: + 2025-10-01: 750 + 2026-10-01: 800 + 7: + 2025-10-01: 750 + 2026-10-01: 800 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 +# Household size 9 and over. +4: + # Income group A. + 1: + 1: + 2025-10-01: 480 + 2026-10-01: 566 + 2: + 2025-10-01: 525 + 2026-10-01: 605 + 3: + 2025-10-01: 625 + 2026-10-01: 691 + 4: + 2025-10-01: 670 + 2026-10-01: 731 + 5: + 2025-10-01: 750 + 2026-10-01: 800 + 6: + 2025-10-01: 750 + 2026-10-01: 800 + 7: + 2025-10-01: 750 + 2026-10-01: 800 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group B. + 2: + 1: + 2025-10-01: 450 + 2026-10-01: 540 + 2: + 2025-10-01: 525 + 2026-10-01: 605 + 3: + 2025-10-01: 530 + 2026-10-01: 609 + 4: + 2025-10-01: 630 + 2026-10-01: 696 + 5: + 2025-10-01: 750 + 2026-10-01: 800 + 6: + 2025-10-01: 750 + 2026-10-01: 800 + 7: + 2025-10-01: 750 + 2026-10-01: 800 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group C. + 3: + 1: + 2025-10-01: 450 + 2026-10-01: 540 + 2: + 2025-10-01: 500 + 2026-10-01: 583 + 3: + 2025-10-01: 530 + 2026-10-01: 609 + 4: + 2025-10-01: 630 + 2026-10-01: 696 + 5: + 2025-10-01: 750 + 2026-10-01: 800 + 6: + 2025-10-01: 750 + 2026-10-01: 800 + 7: + 2025-10-01: 750 + 2026-10-01: 800 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + # Income group D. + 4: + 1: + 2025-10-01: 450 + 2026-10-01: 540 + 2: + 2025-10-01: 500 + 2026-10-01: 583 + 3: + 2025-10-01: 530 + 2026-10-01: 609 + 4: + 2025-10-01: 630 + 2026-10-01: 696 + 5: + 2025-10-01: 750 + 2026-10-01: 800 + 6: + 2025-10-01: 750 + 2026-10-01: 800 + 7: + 2025-10-01: 750 + 2026-10-01: 800 + 8: + 2025-10-01: 750 + 2026-10-01: 800 + 9: + 2025-10-01: 750 + 2026-10-01: 800 + +metadata: + unit: currency-USD + period: year + label: Tennessee LIHEAP regular benefit amount + breakdown: + - range(1, 5) # household size group + - range(1, 5) # income group (1-4 = A-D) + - range(1, 10) # energy burden column + breakdown_labels: + - Household size group + - Income group + - Energy burden column + reference: + - title: Tennessee LIHEAP 2026 Benefit Matrix + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf + - title: "Tennessee FY2027 LIHEAP Benefit Matrix (LI-12) #page 1-4" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1 + - title: Tennessee LIHEAP 2026 Policy Manual, benefit levels + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=34 + - title: Tennessee FY2026 LIHEAP State Plan, Sections 2.5-2.6 + href: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=9 + - title: Tennessee FY2027 LIHEAP State Plan (draft), Sections 2.5-2.6 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DETAILED-MODEL-PLAN-LIHEAP_10_01_2026.pdf#page=12 + - title: Tennessee LIHEAP 2026 Workshop, Benefit Matrix Adjustments 2026 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-26-Workshop-Powerpoint-09.16.25.pdf#page=29 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/burden_column.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/burden_column.yaml new file mode 100644 index 00000000000..5a242e59eaf --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/burden_column.yaml @@ -0,0 +1,64 @@ +description: Tennessee assigns this benefit matrix energy burden column from the rounded ratio of energy cost to countable income under the Low Income Home Energy Assistance Program. +# The matrix prints each column as a four-decimal range, so lower-inclusive +# cutoffs at each column start match the rounded burden. Households with zero +# income receive column 9 in tn_liheap. +brackets: + # 0.0000 - 0.0509. + - threshold: + 2025-10-01: 0 + amount: + 2025-10-01: 1 + # 0.0510 - 0.0671. + - threshold: + 2025-10-01: 0.051 + amount: + 2025-10-01: 2 + # 0.0672 - 0.0827. + - threshold: + 2025-10-01: 0.0672 + amount: + 2025-10-01: 3 + # 0.0828 - 0.0997. + - threshold: + 2025-10-01: 0.0828 + amount: + 2025-10-01: 4 + # 0.0998 - 0.1214. + - threshold: + 2025-10-01: 0.0998 + amount: + 2025-10-01: 5 + # 0.1215 - 0.1528. + - threshold: + 2025-10-01: 0.1215 + amount: + 2025-10-01: 6 + # 0.1529 - 0.2181. + - threshold: + 2025-10-01: 0.1529 + amount: + 2025-10-01: 7 + # 0.2182 - 0.9999. + - threshold: + 2025-10-01: 0.2182 + amount: + 2025-10-01: 8 + # 1.0000 or greater. + - threshold: + 2025-10-01: 1 + amount: + 2025-10-01: 9 + +metadata: + type: single_amount + threshold_unit: /1 + amount_unit: /1 + period: year + label: Tennessee LIHEAP energy burden column + reference: + - title: Tennessee LIHEAP 2026 Benefit Matrix, energy burden columns + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf + - title: "Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), energy burden columns #page 1-4" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1 + - title: "Tennessee LIHEAP 2026 Policy Manual, Section 2.17 #page 31-32" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/burden_decimals.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/burden_decimals.yaml new file mode 100644 index 00000000000..8cd6cefe09b --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/burden_decimals.yaml @@ -0,0 +1,16 @@ +description: Tennessee rounds the energy burden ratio to this many decimal places before selecting the benefit matrix column under the Low Income Home Energy Assistance Program. +# The manual's examples divide the energy expense by countable income +# ($89.24 / $1,015.45 = 0.0878822197, or 8.79%), and the matrix prints its +# energy burden columns to four decimals (0.0000-0.0509, 0.0510-0.0671). +values: + 2025-10-01: 4 + +metadata: + unit: int + period: year + label: Tennessee LIHEAP energy burden rounding decimals + reference: + - title: "Tennessee LIHEAP 2026 Policy Manual, Section 2.17 #page 31-32" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=31 + - title: Tennessee LIHEAP 2026 Benefit Matrix, energy burden columns + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/energy_cost_sources.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/energy_cost_sources.yaml new file mode 100644 index 00000000000..505ce3bde1c --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/energy_cost_sources.yaml @@ -0,0 +1,28 @@ +description: Tennessee adds these household energy bills to compute the energy cost in the energy burden under the Low Income Home Energy Assistance Program. +# The energy burden uses the annual average of all household energy usage +# (electric, gas, propane and other fuels), preferably over 12 months, and the +# bill data includes service, usage and delivery charges and taxes. Annual +# expense inputs stand in for the 12-month usage; deposits, optional charges +# and non-energy services cannot be separated from these totals. Public +# housing and Section 8 tenants enter their overage charges as bills. Heat +# included in the rent has no landlord-cost input, so its burden counts only +# separately billed energy and is a lower bound. +values: + 2025-10-01: + - pre_subsidy_electricity_expense + - gas_expense + - bottled_gas_expense + - fuel_oil_expense + - wood_expense + - coal_expense + - other_heating_fuel_expense + +metadata: + unit: list + period: year + label: Tennessee LIHEAP energy cost sources + reference: + - title: "Tennessee LIHEAP 2026 Policy Manual, Sections 1.2 and 2.17-2.19 #page 8,32-33" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=8 + - title: Tennessee FY2026 LIHEAP State Plan, Section 2.5 + href: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=9 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/fpg_rate.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/fpg_rate.yaml new file mode 100644 index 00000000000..b6b129dbffa --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/fpg_rate.yaml @@ -0,0 +1,22 @@ +description: Tennessee sets the top of each lower benefit matrix income group at this multiple of the federal poverty guideline under the Low Income Home Energy Assistance Program. +# Inferred from the FY2026 matrix: 71%, 87% and 117% of the 2025 guideline +# reproduce all 36 printed income-end values for groups A-C, sizes 1-12 (size +# 1: $11,111.50, $13,615.50 and $18,310.50 of $15,650). The workshop labels +# the groups 0%-50%, 51%-75% and 76%-100%. Group D runs to the income limit. +# Used while uses_fpg_rates is true. +A: + 2025-10-01: 0.71 +B: + 2025-10-01: 0.87 +C: + 2025-10-01: 1.17 + +metadata: + unit: /1 + period: year + label: Tennessee LIHEAP benefit matrix income group poverty guideline rate + reference: + - title: Tennessee LIHEAP 2026 Benefit Matrix, income end + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf + - title: Tennessee LIHEAP 2026 Workshop, annualized income by family size and percentage of poverty + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-26-Workshop-Powerpoint-09.16.25.pdf#page=30 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/max_table_size.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/max_table_size.yaml new file mode 100644 index 00000000000..ac17c25d84b --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/max_table_size.yaml @@ -0,0 +1,11 @@ +description: Tennessee prints benefit matrix income group tops through this household size, with larger households using the last printed row, under the Low Income Home Energy Assistance Program. +values: + 2026-10-01: 16 + +metadata: + unit: person + period: year + label: Tennessee LIHEAP maximum tabulated income group household size + reference: + - title: Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), household sizes 13-16 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=4 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/A.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/A.yaml new file mode 100644 index 00000000000..fd6be9029c0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/A.yaml @@ -0,0 +1,48 @@ +description: Tennessee sets the top of benefit matrix income group A at this annual income, by household size, under the Low Income Home Energy Assistance Program. +# Printed LI-12 income end values. Used when uses_fpg_rates is false. +# Size 12 ($55,592.50) is $3,933 above size 11, where sizes 1-11 step by +# $4,032 or $4,033; the printed value is kept. +1: + 2026-10-01: 11_331.5 +2: + 2026-10-01: 15_364.5 +3: + 2026-10-01: 19_397.5 +4: + 2026-10-01: 23_430.5 +5: + 2026-10-01: 27_462.5 +6: + 2026-10-01: 31_495.5 +7: + 2026-10-01: 35_528.5 +8: + 2026-10-01: 39_561.5 +9: + 2026-10-01: 43_594.5 +10: + 2026-10-01: 47_626.5 +11: + 2026-10-01: 51_659.5 +12: + 2026-10-01: 55_592.5 +13: + 2026-10-01: 59_597.5 +14: + 2026-10-01: 63_502.5 +15: + 2026-10-01: 67_407.5 +16: + 2026-10-01: 71_312.5 + +metadata: + unit: currency-USD + period: year + label: Tennessee LIHEAP benefit matrix income group A top + breakdown: + - range(1, 17) + breakdown_labels: + - Household size + reference: + - title: "Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), income end #page 1-4" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/B.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/B.yaml new file mode 100644 index 00000000000..71c42cc5c9b --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/B.yaml @@ -0,0 +1,48 @@ +description: Tennessee sets the top of benefit matrix income group B at this annual income, by household size, under the Low Income Home Energy Assistance Program. +# Printed LI-12 income end values. Used when uses_fpg_rates is false. +# Size 4 is printed as $28,710.51, the same as the group C start; the +# printed value is kept, so income of exactly $28,710.51 falls in group B. +1: + 2026-10-01: 13_885.5 +2: + 2026-10-01: 18_826.5 +3: + 2026-10-01: 23_768.5 +4: + 2026-10-01: 28_710.51 +5: + 2026-10-01: 33_651.5 +6: + 2026-10-01: 38_593.5 +7: + 2026-10-01: 43_534.5 +8: + 2026-10-01: 48_476.5 +9: + 2026-10-01: 53_418.5 +10: + 2026-10-01: 58_359.5 +11: + 2026-10-01: 63_301.5 +12: + 2026-10-01: 68_242.5 +13: + 2026-10-01: 73_027.5 +14: + 2026-10-01: 77_812.5 +15: + 2026-10-01: 82_597.5 +16: + 2026-10-01: 87_382.5 + +metadata: + unit: currency-USD + period: year + label: Tennessee LIHEAP benefit matrix income group B top + breakdown: + - range(1, 17) + breakdown_labels: + - Household size + reference: + - title: "Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), income end #page 1-4" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/C.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/C.yaml new file mode 100644 index 00000000000..c8e10ee6be9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/top/C.yaml @@ -0,0 +1,48 @@ +description: Tennessee sets the top of benefit matrix income group C at this annual income, by household size, under the Low Income Home Energy Assistance Program. +# Printed LI-12 income end values. Used when uses_fpg_rates is false. +# Size 12 ($91,744.50) is $6,615 above size 11, where sizes 1-11 step by +# $6,645 or $6,646; the printed value is kept. +1: + 2026-10-01: 18_673.5 +2: + 2026-10-01: 25_318.5 +3: + 2026-10-01: 31_964.5 +4: + 2026-10-01: 38_610.5 +5: + 2026-10-01: 45_255.5 +6: + 2026-10-01: 51_901.5 +7: + 2026-10-01: 58_546.5 +8: + 2026-10-01: 65_192.5 +9: + 2026-10-01: 71_838.5 +10: + 2026-10-01: 78_483.5 +11: + 2026-10-01: 85_129.5 +12: + 2026-10-01: 91_744.5 +13: + 2026-10-01: 98_209.5 +14: + 2026-10-01: 104_644.5 +15: + 2026-10-01: 111_079.5 +16: + 2026-10-01: 117_514.5 + +metadata: + unit: currency-USD + period: year + label: Tennessee LIHEAP benefit matrix income group C top + breakdown: + - range(1, 17) + breakdown_labels: + - Household size + reference: + - title: "Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), income end #page 1-4" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/uses_fpg_rates.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/uses_fpg_rates.yaml new file mode 100644 index 00000000000..69005d67e1b --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/income_group/uses_fpg_rates.yaml @@ -0,0 +1,17 @@ +description: Tennessee derives the benefit matrix income group tops from the federal poverty guideline when this is true, and otherwise uses the printed income group tops, under the Low Income Home Energy Assistance Program. +# FY2026 tops follow fixed rates of the 2025 guideline. The FY2027 LI-12 tops +# are not a fixed rate of the 2026 guideline for every size (size 12 group A +# is $55,592.50, 70.87% of $78,440), so FY2027 uses the printed values. +values: + 2025-10-01: true + 2026-10-01: false + +metadata: + unit: bool + period: year + label: Tennessee LIHEAP income group poverty guideline rates in effect + reference: + - title: Tennessee LIHEAP 2026 Benefit Matrix, income end + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf + - title: "Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), income end #page 1-4" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/propane_minimum.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/propane_minimum.yaml new file mode 100644 index 00000000000..6e6ffc2ce31 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/propane_minimum.yaml @@ -0,0 +1,18 @@ +description: Tennessee raises the regular benefit to this minimum for households that apply it to propane under the Low Income Home Energy Assistance Program. +# FY2026 sets a $500 minimum propane payment because of utility company +# payment requirements. The draft 2027 manual's deliverable fuel rules omit +# the minimum, so FY2027 has none. A household heating primarily with propane +# is assumed to apply its benefit to propane. +values: + 2025-10-01: 500 + 2026-10-01: 0 + +metadata: + unit: currency-USD + period: year + label: Tennessee LIHEAP propane minimum payment + reference: + - title: Tennessee LIHEAP 2026 Policy Manual, utility selection for LIHEAP benefits + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=25 + - title: Tennessee LIHEAP 2027 Policy Manual (draft), deliverable fuel benefits + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=18 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/size_group.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/size_group.yaml new file mode 100644 index 00000000000..efb85d09580 --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/size_group.yaml @@ -0,0 +1,39 @@ +description: Tennessee assigns this benefit matrix household size group from the number of counted household members under the Low Income Home Energy Assistance Program. +# The FY2026 matrix prints identical benefit rows for sizes 1-2, 3-5, 6-8 and +# 9-12, and the FY2027 LI-12 matrix for sizes 1-2, 3-5, 6-8 and 9-16. Larger +# households use the last group. +brackets: + # Household size 1-2. + - threshold: + 2025-10-01: 0 + amount: + 2025-10-01: 1 + # Household size 3-5. + - threshold: + 2025-10-01: 3 + amount: + 2025-10-01: 2 + # Household size 6-8. + - threshold: + 2025-10-01: 6 + amount: + 2025-10-01: 3 + # Household size 9 and over. + - threshold: + 2025-10-01: 9 + amount: + 2025-10-01: 4 + +metadata: + type: single_amount + threshold_unit: person + amount_unit: /1 + period: year + label: Tennessee LIHEAP benefit matrix household size group + reference: + - title: Tennessee LIHEAP 2026 Benefit Matrix, household members + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf + - title: Tennessee LIHEAP 2026 Workshop, Benefit Matrix Adjustments 2026 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-26-Workshop-Powerpoint-09.16.25.pdf#page=29 + - title: "Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), household members #page 1-4" + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 43fdd714b80..0b06616bc26 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -808,7 +808,7 @@ programs: category: Benefits agency: HHS status: partial - coverage: AL, DC, Riverside County, MA, FL, IL, IN, KS, KY, MD, MS, NC, NE, NJ, NY, OH, OK, OR, SD, RI, TX + coverage: AL, DC, Riverside County, MA, FL, IL, IN, KS, KY, MD, MS, NC, NE, NJ, NY, OH, OK, OR, SD, RI, TN, TX state_implementations: - state: AL status: partial @@ -953,6 +953,14 @@ programs: variable: sd_liheap parameter_prefix: gov.states.sd.dss.liheap notes: FY2024-FY2026 regular heating only; mixed-status income is counted in full and FY2026 Mid thresholds are inferred, so no year is verified. Crisis, cooling and weatherization are out of scope. + - state: TN + status: partial + name: Tennessee LIHEAP + full_name: Tennessee Low Income Home Energy Assistance Program + variable: tn_liheap + parameter_prefix: gov.states.tn.thda.liheap + verified_years: "2026-2027" + notes: FY2026-FY2027 regular benefit from the THDA benefit matrices; FY2027 uses the posted LI-12 matrix while its plan and manual are drafts. Crisis and weatherization assistance are out of scope. - state: TX status: partial name: Texas CEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.yaml new file mode 100644 index 00000000000..b791da7bcb7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.yaml @@ -0,0 +1,235 @@ +# 2026 Policy Manual: income at or below 60% of state median income (2.10), size +# counts only citizens and qualified noncitizens (2.4), an energy cost in rent remains +# eligible (2.17) and an applicant without an energy account is ineligible (2.18). +# 42 U.S.C. 8624(b)(2)(B) protects income below 110% of the poverty guideline (2025 +# guidelines in FFY2026: 15,650 + 5,500 per additional person). +# Wages of 15,080 are full-time work (2,080 hours) at the federal 7.25 minimum wage, +# which Tennessee follows; electricity of 1,680 is about the EIA 2024 Tennessee average +# residential bill of 140 a month. + +- name: Case 1, income exactly at the FFY2026 size-one limit is eligible. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 32_053 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + tn_liheap_eligible: true + +- name: Case 2, income one dollar above the FFY2026 size-one limit is ineligible. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 32_054 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + tn_liheap_eligible: false + +- name: Case 3, a fifteen-person household above the limit but below the poverty floor is eligible. + period: 2026 + input: + people: + # Limit floor(61,641 x 1.59) = 98,009; floor (15,650 + 5,500 x 14) x 1.1 = 101,915. + person1: {age: 45, employment_income: 101_914} + person2: {age: 43} + person3: {age: 17} + person4: {age: 16} + person5: {age: 15} + person6: {age: 14} + person7: {age: 13} + person8: {age: 12} + person9: {age: 11} + person10: {age: 10} + person11: {age: 9} + person12: {age: 8} + person13: {age: 7} + person14: {age: 6} + person15: {age: 5} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_200 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15] + state_code: TN + output: + tn_liheap_eligible: true + +- name: Case 4, income equal to 110 percent of the poverty guideline is not protected. + period: 2026 + input: + people: + # The floor protects income less than 101,915 only. + person1: {age: 45, employment_income: 101_915} + person2: {age: 43} + person3: {age: 17} + person4: {age: 16} + person5: {age: 15} + person6: {age: 14} + person7: {age: 13} + person8: {age: 12} + person9: {age: 11} + person10: {age: 10} + person11: {age: 9} + person12: {age: 8} + person13: {age: 7} + person14: {age: 6} + person15: {age: 5} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_200 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15] + state_code: TN + output: + tn_liheap_eligible: false + +- name: Case 5, a home with no heating is ineligible even when a heating expense is set directly. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: NONE + pre_subsidy_electricity_expense: 1_680 + # Set directly so the energy-account test passes and the no-heating + # fuel rule alone decides. + has_heating_expense: true + households: + household: + members: [person1] + state_code: TN + output: + tn_liheap_eligible: false + +- name: Case 6, an unknown heating fuel with heat included in rent is eligible. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + heat_expense_included_in_rent: true + households: + household: + members: [person1] + state_code: TN + output: + tn_liheap_eligible: true + +- name: Case 7, an unknown heating fuel without heat in rent is ineligible even when a heating expense is set directly. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + pre_subsidy_electricity_expense: 1_680 + heat_expense_included_in_rent: false + # Set directly so the energy-account test passes and the + # unknown-fuel rule alone decides. + has_heating_expense: true + households: + household: + members: [person1] + state_code: TN + output: + tn_liheap_eligible: false + +- name: Case 8, a household with no heating bill and no heat in rent is ineligible. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 0 + heat_expense_included_in_rent: false + households: + household: + members: [person1] + state_code: TN + output: + tn_liheap_eligible: false + +- name: Case 9, a household of only undocumented members is ineligible. + period: 2026 + input: + people: + person1: + age: 40 + immigration_status: UNDOCUMENTED + employment_income: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + tn_liheap_eligible: false + +- name: Case 10, a household outside Tennessee is ineligible. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: KY + output: + tn_liheap_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_income_limit.yaml new file mode 100644 index 00000000000..3f8f37b4854 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_income_limit.yaml @@ -0,0 +1,203 @@ +# FFY2026 limit is 60% of the Tennessee state median income for every size (2026 +# Policy Manual 2.10; FFY2026 plan 2.1): four-person limit floor(102,735 x 0.6) = +# 61,641, and each size uses floor(61,641 x factor), with factors 0.52 + 0.16 per +# person through six and 0.03 for each person above six. +# FFY2027 (draft 2027 manual 2.10; FFY2027 plan 2.1) keeps 60% SMI for one to eight +# members, floor(105,327 x 0.6) = 63,196 for four, and uses 150% of the 2026 poverty +# guideline (15,960 + 5,680 per additional person) for nine or more. +# Household size counts only citizens and qualified noncitizens (2026 Policy Manual 2.4). +# Electricity of 1,680 is about the EIA 2024 Tennessee average residential bill of +# 140 a month. + +- name: Case 1, an undocumented member is excluded from household size so the FFY2026 size-one limit applies. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person2: + age: 42 + immigration_status: UNDOCUMENTED + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + tn_liheap_household_size: 1 + # floor(61,641 x 0.52) = floor(32,053.32) + tn_liheap_income_limit: 32_053 + +- name: Case 2, an FFY2026 eight-person household uses the rule value rather than the printed 85,064.50. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 40} + person2: {age: 38} + person3: {age: 16} + person4: {age: 14} + person5: {age: 12} + person6: {age: 10} + person7: {age: 8} + person8: {age: 6} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 900 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: TN + output: + tn_liheap_household_size: 8 + # floor(61,641 x 1.38) = floor(85,064.58) + tn_liheap_income_limit: 85_064 + +- name: Case 3, an FFY2026 thirteen-person household extends the federal size adjustment. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 45} + person2: {age: 43} + person3: {age: 17} + person4: {age: 16} + person5: {age: 15} + person6: {age: 14} + person7: {age: 13} + person8: {age: 12} + person9: {age: 11} + person10: {age: 10} + person11: {age: 9} + person12: {age: 8} + person13: {age: 7} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 900 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13] + state_code: TN + output: + tn_liheap_household_size: 13 + # floor(61,641 x 1.53) = floor(94,310.73) + tn_liheap_income_limit: 94_310 + +- name: Case 4, an FFY2027 eight-person household keeps the 60 percent state median income limit. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 40} + person2: {age: 38} + person3: {age: 16} + person4: {age: 14} + person5: {age: 12} + person6: {age: 10} + person7: {age: 8} + person8: {age: 6} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 900 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: TN + output: + # floor(63,196 x 1.38) = floor(87,210.48) + tn_liheap_income_limit: 87_210 + +- name: Case 5, an FFY2027 nine-person household switches to 150 percent of the poverty guideline. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 40} + person2: {age: 38} + person3: {age: 17} + person4: {age: 16} + person5: {age: 14} + person6: {age: 12} + person7: {age: 10} + person8: {age: 8} + person9: {age: 6} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 900 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: TN + output: + # floor(1.5 x (15,960 + 5,680 x 8)) = floor(1.5 x 61,400); 60% SMI would be 89,106 + tn_liheap_income_limit: 92_100 + +- name: Case 6, an FFY2027 thirteen-person household uses the rule value rather than the printed 125,910. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 45} + person2: {age: 43} + person3: {age: 17} + person4: {age: 16} + person5: {age: 15} + person6: {age: 14} + person7: {age: 13} + person8: {age: 12} + person9: {age: 11} + person10: {age: 10} + person11: {age: 9} + person12: {age: 8} + person13: {age: 7} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 900 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13] + state_code: TN + output: + # floor(1.5 x (15,960 + 5,680 x 12)) = floor(1.5 x 84,120) + tn_liheap_income_limit: 126_180 + +- name: Case 7, a household of only undocumented members has no counted members and no limit. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: UNDOCUMENTED + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + tn_liheap_household_size: 0 + tn_liheap_income_limit: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.yaml new file mode 100644 index 00000000000..a5ebaf8a35d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.yaml @@ -0,0 +1,299 @@ +# 2026 Policy Manual 2.13: gross wages, net self-employment and farm income, regular +# payments (Social Security net of Medicare premiums, TANF, child support, money +# regularly received from outside the household), interest only above 200 a year, +# net rental income and net gambling winnings are counted; capital gains, bank +# withdrawals and dependents' earnings are not. A child is under 18 (1.2); earnings of +# children under 18 are not counted (FFY2026 plan 1.9). An ineligible member's income +# counts in full (2.4). Wages of 15,080 are full-time work (2,080 hours) at the federal +# 7.25 minimum wage, which Tennessee follows. Electricity of 1,680 is about the EIA +# 2024 Tennessee average residential bill of 140 a month. + +- name: Case 1, gross wages and business income count while business and rental losses are floored at zero. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 15_080 + self_employment_income: 3_000 + partnership_s_corp_income: -1_500 + rental_income: -1_800 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # 15,080 + 3,000 + max(-1,500, 0) + max(-1,800, 0) = 18,080 + tn_liheap_countable_income: 18_080 + +- name: Case 2, a married 17-year-old who is not a tax dependent has wages excluded by age. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 19 + is_tax_unit_dependent: false + employment_income: 15_080 + person2: + # Marriage emancipates a minor in Tennessee (2026 Policy Manual 1.2). + age: 17 + is_tax_unit_dependent: false + employment_income: 4_000 + spm_units: + spm_unit: + members: [person1, person2] + tanf: 0 + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # 15,080; the 17-year-old's 4,000 is excluded + tn_liheap_countable_income: 15_080 + +- name: Case 3, an 18-year-old who is not a tax dependent has wages counted. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + is_tax_unit_dependent: false + employment_income: 30_000 + person2: + age: 18 + is_tax_unit_dependent: false + employment_income: 6_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # 30,000 + 6,000 = 36,000 + tn_liheap_countable_income: 36_000 + +- name: Case 4, an adult tax dependent living with a parent has wages excluded. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + is_tax_unit_dependent: false + employment_income: 30_000 + person2: + # A college student claimed by the parent. + age: 20 + is_tax_unit_dependent: true + employment_income: 6_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # 30,000; the dependent's 6,000 is excluded (2026 Policy Manual 2.13 exclusions) + tn_liheap_countable_income: 30_000 + +- name: Case 5, Social Security is counted net of the Medicare Part B premium and floors at zero for each person. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 67 + ssi: 0 + social_security_retirement: 24_000 + # 2026 standard Part B premium of 202.90 a month. + medicare_part_b_premium: 2_434.80 + person2: + age: 66 + ssi: 0 + social_security_retirement: 1_800 + medicare_part_b_premium: 2_434.80 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 900 + households: + household: + members: [person1, person2] + state_code: TN + output: + # (24,000 - 2,434.80) + max(1,800 - 2,434.80, 0) = 21,565.20 + 0 + tn_liheap_countable_income: 21_565.20 + +- name: Case 6, interest of 200 a year is not counted while interest of 201 is counted in full. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 15_080 + interest_income: 200 + person2: + age: 41 + interest_income: 201 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # 15,080 + 0 (200 does not exceed 200) + 201 = 15,281 + tn_liheap_countable_income: 15_281 + +- name: Case 7, child support is counted while capital gains and retirement-account withdrawals are not. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 15_080 + # Child support of 400 a month. + child_support_received: 4_800 + long_term_capital_gains: 1_000 + taxable_ira_distributions: 2_000 + person2: + age: 8 + spm_units: + spm_unit: + members: [person1, person2] + tanf: 0 + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # 15,080 + 4,800 = 19,880 + tn_liheap_countable_income: 19_880 + +- name: Case 8, net gambling winnings count and one member's excess losses do not offset income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + employment_income: 20_000 + gambling_winnings: 2_000 + gambling_losses: 500 + person2: + age: 48 + gambling_winnings: 300 + gambling_losses: 1_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # 20,000 + max(2,000 - 500, 0) + max(300 - 1,000, 0) = 20,000 + 1,500 + 0 + tn_liheap_countable_income: 21_500 + +- name: Case 9, Families First cash assistance received by the household is counted. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + # Families First three-person standard payment of 387 a month. + tanf: 4_644 + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2, person3] + state_code: TN + output: + # 387 x 12 = 4,644 + tn_liheap_countable_income: 4_644 + +- name: Case 10, an undocumented member's income counts in full. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 15_080 + person2: + age: 42 + immigration_status: UNDOCUMENTED + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # 15,080 + 20,000 (2026 Policy Manual 2.4) + tn_liheap_countable_income: 35_080 + +- name: Case 11, SSI and regular contributions from outside the household count as unearned income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + is_disabled: true + # 2026 federal SSI benefit rate of 994 a month. + ssi: 11_928 + # Regular support of 100 a month from a relative. + financial_assistance: 1_200 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # 994 x 12 + 1,200 = 11,928 + 1,200 + tn_liheap_countable_income: 13_128 diff --git a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/tn_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/tn_liheap.yaml new file mode 100644 index 00000000000..636a202328e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/tn_liheap.yaml @@ -0,0 +1,544 @@ +# The award is the benefit matrix cell for the size group (1-2, 3-5, 6-8, 9 or more), +# the income group (A-D) and the energy burden column; burden is annual energy cost +# over income rounded half up to four decimals (2026 Policy Manual 2.17), with columns starting +# at 0, 0.0510, 0.0672, 0.0828, 0.0998, 0.1215, 0.1529, 0.2182 and 1.0000, and zero +# income takes column 9. FFY2026 (2026 Benefit Matrix): income groups A-C end at 71%, +# 87% and 117% of the 2025 poverty guideline (15,650 + 5,500 per additional person), +# and a propane benefit is at least 500 (2026 Policy Manual 2.10). FFY2027 (LI-12 +# matrix): income groups end at the printed amounts and propane has no minimum. +# Wages of 15,080 are full-time work (2,080 hours) at the federal 7.25 minimum wage, +# which Tennessee follows; electricity of 1,680 is about the EIA 2024 Tennessee average +# residential bill of 140 a month. + +- name: Case 1, income exactly at the size-one group A top in FFY2026 receives the group A amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + # Part-time work at 7.25 an hour. + employment_income: 11_111.50 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # Group A top 15,650 x 0.71 = 11,111.50; 1,680 / 11,111.50 = 0.1512 -> column 6 + tn_liheap: 560 + +- name: Case 2, income one cent above the size-one group A top in FFY2026 receives the group B amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 11_111.51 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # Group B top 15,650 x 0.87 = 13,615.50; 1,680 / 11,111.51 = 0.1512 -> column 6 + tn_liheap: 555 + +- name: Case 3, income exactly at the size-one group C top in FFY2026 receives the group C amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 18_310.50 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + # Gas of 75 a month. + gas_expense: 900 + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # Group C top 15,650 x 1.17 = 18,310.50; (900 + 1,680) / 18,310.50 = 0.1409 -> column 6 + tn_liheap: 550 + +- name: Case 4, income one cent above the size-one group C top in FFY2026 receives the group D amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 18_310.51 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 900 + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # Group D up to the 32,053 limit; 2,580 / 18,310.51 = 0.1409 -> column 6 + tn_liheap: 540 + +- name: Case 5, a raw burden of exactly 0.12145 rounds half up to 0.1215 and starts the sixth column. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + # Gas of about 62 a month. + gas_expense: 749 + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # Group D (20,000 above the 18,310.50 group C top); + # (749 + 1,680) / 20,000 = 0.12145 -> half up 0.1215 -> column 6 + # (half to even would give 0.1214, column 5, 445) + tn_liheap: 540 + +- name: Case 6, a raw burden of 0.05094 rounds down to 0.0509 and stays in the first column. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_018.80 + households: + household: + members: [person1] + state_code: TN + output: + # 1,018.80 / 20,000 = 0.05094 -> 0.0509 -> column 1, group D + tn_liheap: 174 + +- name: Case 7, zero income receives the highest burden column. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # Zero income -> column 9, group A, sizes 1-2 + tn_liheap: 750 + +- name: Case 8, a two-person household uses the sizes one-to-two group. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # Part-time work at 7.25 an hour. + employment_income: 12_000 + person2: + age: 6 + spm_units: + spm_unit: + members: [person1, person2] + tanf: 0 + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # Group A top (15,650 + 5,500) x 0.71 = 15,016.50; 1,680 / 12,000 = 0.14 -> column 6 + tn_liheap: 560 + +- name: Case 9, a three-person household uses the sizes three-to-five group. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 12_000 + person2: + age: 6 + person3: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3] + tanf: 0 + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2, person3] + state_code: TN + output: + # Group A top (15,650 + 5,500 x 2) x 0.71 = 18,921.50; 0.14 -> column 6 + tn_liheap: 600 + +- name: Case 10, a six-person household adds all energy bills and uses the sizes six-to-eight group. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 15_080 + person2: + age: 34 + employment_income: 15_080 + person3: + age: 12 + person4: + age: 10 + person5: + age: 7 + person6: + age: 4 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + tanf: 0 + heating_type: NATURAL_GAS + # Gas of 50 a month. + gas_expense: 600 + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: TN + output: + # Group A top (15,650 + 5,500 x 5) x 0.71 = 30,636.50; + # (600 + 1,680) / 30,160 = 0.0756 -> column 3 + tn_liheap: 565 + +- name: Case 11, a thirteen-person household in FFY2026 extends the nine-or-more group with its own poverty guideline. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 45, employment_income: 40_000} + person2: {age: 43, employment_income: 28_000} + person3: {age: 17} + person4: {age: 16} + person5: {age: 15} + person6: {age: 14} + person7: {age: 13} + person8: {age: 12} + person9: {age: 11} + person10: {age: 10} + person11: {age: 9} + person12: {age: 8} + person13: {age: 7} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_080 + pre_subsidy_electricity_expense: 3_000 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13] + state_code: TN + output: + # Guideline 15,650 + 5,500 x 12 = 81,650: group A top 57,971.50, group B top 71,035.50; + # 68,000 is group B (the size-twelve B top of 66,250.50 would give group C); + # 4,080 / 68,000 = 0.06 -> column 2 + tn_liheap: 525 + +- name: Case 12, a propane benefit below 500 in FFY2026 is raised to 500. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: PROPANE + # Propane of 100 a month. + bottled_gas_expense: 1_200 + households: + household: + members: [person1] + state_code: TN + output: + # 1,200 / 20,000 = 0.06 -> column 2, group D: max(250, 500) + tn_liheap: 500 + +- name: Case 13, a propane benefit above 500 in FFY2026 is unchanged. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: PROPANE + bottled_gas_expense: 1_200 + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # (1,200 + 1,680) / 15,080 = 0.1910 -> column 7, group C: max(700, 500) + tn_liheap: 700 + +- name: Case 14, heat included in rent with no separate energy bills receives the first column. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + heat_expense_included_in_rent: true + households: + household: + members: [person1] + state_code: TN + output: + # 0 / 15,080 = 0 -> column 1, sizes 1-2 + tn_liheap: 174 + +- name: Case 15, income above the limit receives nothing. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 32_054 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # 32,054 > 32,053 limit + tn_liheap: 0 + +- name: Case 16, income one cent above the printed FFY2027 size-one group A top receives the group B amount. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 11_331.51 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # Printed group A top 11,331.50 (71% of 15,960 would be 11,331.60); + # 1,680 / 11,331.51 = 0.1483 -> column 6 + tn_liheap: 631 + +- name: Case 17, income at the printed FFY2027 four-person group B top receives the group B amount. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 28_710.51 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 920 + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2, person3, person4] + state_code: TN + output: + # Printed group B top 28,710.51 (87% of 33,000 would be 28,710); + # (920 + 1,680) / 28,710.51 = 0.0906 -> column 4 + tn_liheap: 505 + +- name: Case 18, a thirteen-person household in FFY2027 uses the printed size-thirteen income groups. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 45, employment_income: 42_000} + person2: {age: 43, employment_income: 28_000} + person3: {age: 17} + person4: {age: 16} + person5: {age: 15} + person6: {age: 14} + person7: {age: 13} + person8: {age: 12} + person9: {age: 11} + person10: {age: 10} + person11: {age: 9} + person12: {age: 8} + person13: {age: 7} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_200 + pre_subsidy_electricity_expense: 3_000 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13] + state_code: TN + output: + # Size-thirteen group B runs 59,597.51 to 73,027.50 (the size-twelve B top is + # 68,242.50); 4,200 / 70,000 = 0.06 -> column 2 + tn_liheap: 605 + +- name: Case 19, a propane benefit in FFY2027 has no minimum. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: PROPANE + bottled_gas_expense: 1_200 + households: + household: + members: [person1] + state_code: TN + output: + # 1,200 / 20,000 = 0.06 -> column 2, group D (above 18,673.50) + tn_liheap: 366 + +- name: Case 20, income exactly at the printed FFY2026 three-person group C top receives the group C amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 34 + employment_income: 31_180.50 + person2: + age: 32 + person3: + age: 6 + spm_units: + spm_unit: + members: [person1, person2, person3] + tanf: 0 + heating_type: NATURAL_GAS + # Gas of 100 a month. + gas_expense: 1_200 + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2, person3] + state_code: TN + output: + # Group C top (15,650 + 5,500 x 2) x 1.17 = 26,650 x 1.17 = 31,180.50, rounded to cents; + # (1,200 + 1,680) / 31,180.50 = 0.092365 -> 0.0924 -> column 4; + # sizes 3-5 group C column 4 = 400 (group D would be 390) + tn_liheap: 400 + +- name: Case 21, a nine-person household in FFY2027 above 60 percent of state median income is eligible under the poverty-guideline limit and uses the nine-or-more group. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 42, employment_income: 90_000} + person2: {age: 40} + person3: {age: 16} + person4: {age: 14} + person5: {age: 12} + person6: {age: 10} + person7: {age: 8} + person8: {age: 6} + person9: {age: 3} + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_200 + pre_subsidy_electricity_expense: 3_000 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: TN + output: + # floor(1.5 x (15,960 + 5,680 x 8)) = floor(1.5 x 61,400) = 92,100; + # 60% SMI would be floor(63,196 x 1.41) = 89,106, below the 90,000 income + tn_liheap_income_limit: 92_100 + # Printed size-nine group C top 71,838.50, so group D; + # (1,200 + 3,000) / 90,000 = 0.046667 -> 0.0467 -> column 1; + # nine-or-more group D column 1 = 540 (the sizes 6-8 group would give 409) + tn_liheap: 540 diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.py b/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.py new file mode 100644 index 00000000000..ab08104f83a --- /dev/null +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.py @@ -0,0 +1,47 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class tn_liheap_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Tennessee LIHEAP regular assistance eligibility" + defined_for = StateCode.TN + reference = ( + # PDF pages 24, 32-33 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=24", + "https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=8", + "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.tn.thda.liheap.eligibility + p_hhs = parameters(period).gov.hhs.liheap + size = spm_unit("tn_liheap_household_size", period) + income = spm_unit("tn_liheap_countable_income", period) + limit = spm_unit("tn_liheap_income_limit", period) + # 42 U.S.C. 8624(b)(2)(B) bars excluding a household on income below + # 110% of the poverty guideline. The 60% SMI limit falls below that + # floor from household size 15 in FY2026 (98,009 against 101,915). + state_group = spm_unit.household("state_group_str", period) + guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + floor = np.round(guideline * p_hhs.fpg_floor, 2) + income_eligible = (income <= limit) | (income < floor) + # Applicants need an active energy account, or energy included in the + # rent under a landlord/tenant agreement. + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + responsible = spm_unit("has_heating_expense", period) | heat_in_rent + heating_type = spm_unit("heating_type", period) + types = heating_type.possible_values + # The matrix has no fuel column, so an unspecified fuel qualifies only + # when heat is included in the rent; otherwise UNSPECIFIED pays $0. + # The derived has_heating_expense is already false for an unspecified + # fuel, but the clause keeps that rule when a caller sets + # has_heating_expense directly. Subsidized tenants with a bill in their + # name are processed without adjustment, so housing assistance is no + # condition here. + fuel_qualifies = (heating_type != types.NONE) & ( + heat_in_rent | (heating_type != types.UNSPECIFIED) + ) + return (size > 0) & income_eligible & responsible & fuel_qualifies diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_income_limit.py b/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_income_limit.py new file mode 100644 index 00000000000..40145ea91b9 --- /dev/null +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_income_limit.py @@ -0,0 +1,39 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import liheap_smi_limit +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class tn_liheap_income_limit(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Tennessee LIHEAP income limit" + defined_for = StateCode.TN + reference = ( + "https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=8", + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=24", + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf", + # PDF pages 9, 12 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DETAILED-MODEL-PLAN-LIHEAP_10_01_2026.pdf#page=9", + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=27", + # PDF pages 1-4 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.tn.thda.liheap.eligibility + size = spm_unit("tn_liheap_household_size", period) + state = spm_unit.household("state_code_str", period) + state_group = spm_unit.household("state_group_str", period) + # The HHS floor order reproduces the FY2026 matrix ceilings for sizes + # 1-12 (size 8 is printed as $85,064.50) and the FY2027 ceilings for + # sizes 1-8. FY2027 sizes 9 and over use 150% of the 2026 guideline, + # rounded down to the nearest dollar; the printed size 13-16 ceilings + # are below that amount and are not used. + smi_limit = liheap_smi_limit(size, state, p.smi_rate, period, parameters) + fpg_rate = p.fpg_rate.calc(size) + guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + fpg_limit = np.floor(guideline * fpg_rate) + limit = where(fpg_rate > 0, fpg_limit, smi_limit) + return where(size > 0, limit, 0) diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.py b/policyengine_us/variables/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.py new file mode 100644 index 00000000000..dec4dc44183 --- /dev/null +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.py @@ -0,0 +1,62 @@ +from policyengine_us.model_api import * + + +class tn_liheap_countable_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Tennessee LIHEAP countable income" + defined_for = StateCode.TN + reference = ( + # PDF pages 8-9, 27-30 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=8", + # PDF pages 5-7 + "https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=5", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.tn.thda.liheap.income + person = spm_unit.members + # Annual inputs stand in for the income received in the 30 days before + # application. Earned income counts for members 18 and over who are + # not tax-unit dependents; unearned income counts for every member. + earned_counted = (person("age", period) >= p.earned_income_min_age) & ~person( + "is_tax_unit_dependent", period + ) + # Income is gross cash receipts unless a source is listed as net, so + # each source is floored at zero and a loss in one source cannot + # offset another. + earned = 0 + for source in p.sources.earned: + earned = earned + max_(person(source, period), 0) + unearned = 0 + for source in p.sources.unearned: + unearned = unearned + max_(person(source, period, options=[ADD]), 0) + # Net Social Security excludes Medicare premiums, and FY2026 plan + # Section 1.9 counts benefits excluding the Medicare deduction, so the + # Part B premium the person pays is subtracted. + social_security = max_( + person("social_security", period) + - person("medicare_part_b_premium", period), + 0, + ) + # Interest counts only above the annual threshold and when withdrawn; + # withdrawal has no input and is assumed. + interest = max_(person("interest_income", period), 0) + counted_interest = where(interest > p.interest_threshold, interest, 0) + gambling = max_( + person("gambling_winnings", period) - person("gambling_losses", period), + 0, + ) + # Members excluded from household size keep all their income. TANF + # (Families First) is counted once at the SPM level through the + # take-up-gated tanf total. + person_income = ( + earned * earned_counted + + unearned + + social_security + + counted_interest + + gambling + ) + return spm_unit.sum(person_income) + spm_unit("tanf", period) diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap.py b/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap.py new file mode 100644 index 00000000000..91f840cc41a --- /dev/null +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap.py @@ -0,0 +1,92 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class tn_liheap(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Tennessee LIHEAP regular assistance" + documentation = ( + "Tennessee's single annual regular award from the statewide benefit " + "matrix, by household size group, income group and energy burden, " + "applied as heating assistance from October through May and as " + "cooling assistance from June through September. Verified for FY2026 " + "and FY2027 (the posted LI-12 matrix, with the FY2027 plan and manual " + "in draft); earlier years are unverified estimates through parameter " + "backfilling. Crisis assistance and weatherization are out of scope." + ) + defined_for = "tn_liheap_eligible" + reference = ( + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf", + # PDF pages 1-4 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1", + # PDF pages 12, 25, 31-32, 34-35 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=12", + "https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=9", + # PDF pages 28-31 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-26-Workshop-Powerpoint-09.16.25.pdf#page=28", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.tn.thda.liheap + income = spm_unit("tn_liheap_countable_income", period) + energy_cost = add(spm_unit, period, p.payment.energy_cost_sources) + # Annual cost over annual income stands in for the 12-month average + # energy cost over 30-day income. Heat included in the rent counts + # only separately billed energy, so its column is a lower bound. The + # ratio is computed in float64 so a burden printed at a column start + # rounds onto that start. + has_income = income > 0 + income_64 = income.astype(np.float64) + burden = np.divide( + energy_cost.astype(np.float64), + income_64, + out=np.zeros_like(income_64), + where=has_income, + ) + # Ordinary half-up rounding (the manual's example rounds 0.0878822197 + # to 8.79%), so a tie such as 0.12145 reaches the 0.1215 column start; + # np.round would round it half to even, to 0.1214. + scale = 10**p.payment.burden_decimals + rounded_burden = np.floor(burden * scale + 0.5) / scale + burden_column = p.payment.burden_column + # Households with zero income receive the highest burden column. + column = where( + has_income, + burden_column.calc(rounded_burden), + burden_column.amounts[-1], + ) + size = spm_unit("tn_liheap_household_size", period) + size_group = p.payment.size_group.calc(size) + p_group = p.payment.income_group + if p_group.uses_fpg_rates: + state_group = spm_unit.household("state_group_str", period) + guideline = fpg( + size, + state_group, + period, + parameters, + year_lag=p.eligibility.fpg_year_lag, + ) + # The matrix prints the tops in cents. Rounding the rate-derived + # tops to cents keeps an income at a printed top in that group + # (size 3 group C: 26,650 x 1.17 is 31,180.4999... in floating + # point, printed $31,180.50). + tops = [np.round(guideline * p_group.fpg_rate[group], 2) for group in "ABC"] + else: + table_size = clip(size, 1, p_group.max_table_size) + tops = [p_group.top[group][table_size] for group in "ABC"] + # Income groups A-D are numbered 1-4; group D runs to the income + # limit. + income_group = 1 + for top in tops: + income_group = income_group + (income > top) + amount = p.payment.amount[size_group][income_group][column] + # The FY2026 manual sets a $500 minimum when a benefit is applied to + # propane; a household heating with propane is assumed to apply it + # there. No supplement or bill cap applies. + heating_type = spm_unit("heating_type", period) + propane = heating_type == heating_type.possible_values.PROPANE + return where(propane, max_(amount, p.payment.propane_minimum), amount) diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap_household_size.py b/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap_household_size.py new file mode 100644 index 00000000000..8ea786b6e01 --- /dev/null +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap_household_size.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class tn_liheap_household_size(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "Tennessee LIHEAP household size" + defined_for = StateCode.TN + # PDF pages 9, 17-18 + reference = "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=9" + + # Citizens and qualified noncitizens count in household size. Other + # members are excluded from size, but their income counts in full in + # tn_liheap_countable_income. Page 18 asks that benefits which can + # reasonably be prorated be prorated by the number of eligible members, + # and continues: "However, ineligible household members must be excluded + # from the total household count when determining the benefit." The + # matrix lookup at the reduced size is the method applied; prorating on + # top of the size exclusion would reduce the benefit twice. SPM + # membership approximates the LIHEAP household; Social Security number + # refusal has no input. + adds = ["is_citizen_or_legal_immigrant"] From fef2e3f259a0bd18bbdb3e19b3ceefee096ce6f2 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 28 Oct 2026 20:10:29 -0400 Subject: [PATCH 2/2] Address review round 1 for Tennessee LIHEAP Apply DTrim99's round 1 review: tests that pin every income source, the rule and documentation fixes, and source-conflict candidates. Co-Authored-By: Claude Opus 5.5 --- .../liheap/income/interest_threshold.yaml | 11 +- .../income/sources/net_of_medicare.yaml | 29 ++++ .../thda/liheap/income/sources/unearned.yaml | 31 ++-- .../liheap/payment/energy_cost_sources.yaml | 5 +- .../thda/liheap/payment/propane_minimum.yaml | 14 +- .../eligibility/tn_liheap_eligible.yaml | 17 +- .../income/tn_liheap_countable_income.yaml | 98 +++++++++++ .../gov/states/tn/thda/liheap/tn_liheap.yaml | 155 ++++++++++++++++++ .../liheap/eligibility/tn_liheap_eligible.py | 35 ++-- .../income/tn_liheap_countable_income.py | 23 ++- .../gov/states/tn/thda/liheap/tn_liheap.py | 31 ++-- .../tn/thda/liheap/tn_liheap_energy_cost.py | 21 +++ source_conflicts/candidates.yaml | 98 +++++++++++ 13 files changed, 494 insertions(+), 74 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/net_of_medicare.yaml create mode 100644 policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap_energy_cost.py diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/interest_threshold.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/interest_threshold.yaml index 7472745abdd..6e03948c65a 100644 --- a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/interest_threshold.yaml +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/interest_threshold.yaml @@ -1,11 +1,12 @@ description: Tennessee counts a household member's interest income only when it exceeds this annual amount under the Low Income Home Energy Assistance Program. # Interest counts only if it exceeds $200 annually and is withdrawn. No input # records withdrawals, so interest above the threshold is assumed withdrawn -# and counts in full; interest at or below it is not counted. The draft 2027 -# manual lists "Dividends and/or interest that $200 annually and is -# withdrawn", which may extend the threshold to dividends. The model keeps -# the 2026 manual's interest-only threshold, with dividends counted in full, -# until a final 2027 manual is posted. +# and counts in full; interest at or below it is not counted. Section 2.13 +# names no unit for the $200 threshold; the model applies it to each member's +# interest. The draft 2027 manual lists "Dividends and/or interest that $200 +# annually and is withdrawn", which may extend the threshold to dividends. The +# model keeps the 2026 manual's interest-only threshold, with dividends +# counted in full, until a final 2027 manual is posted. values: 2025-10-01: 200 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/net_of_medicare.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/net_of_medicare.yaml new file mode 100644 index 00000000000..69745941b7b --- /dev/null +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/net_of_medicare.yaml @@ -0,0 +1,29 @@ +description: Tennessee deducts Medicare premiums from Social Security and these benefit sources under the Low Income Home Energy Assistance Program. +# Section 2.13 counts net income from Social Security, pensions (private and +# government, including military retirement pay) and VA benefits, excluding +# Medicare premiums. Railroad retirement annuities are government pensions, +# and the Railroad Retirement Board withholds Part B premiums from them. +# Military retirement income includes survivor benefit plan annuities. +# tn_liheap_countable_income adds each member's Social Security to these +# sources, each floored at zero, and subtracts the member's Medicare Part A +# and Part B premiums, flooring the result at zero. +values: + 2025-10-01: + - railroad_benefits + - veterans_benefits + # Private and government pensions, annuities and regular insurance + # payments. + - pension_income + - military_retirement_income + +metadata: + unit: list + period: year + label: Tennessee LIHEAP benefit sources net of Medicare premiums + reference: + - title: Tennessee LIHEAP 2026 Policy Manual, Section 2.13 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=27 + - title: Tennessee LIHEAP 2027 Policy Manual (draft), Section 2.13 + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=29 + - title: Tennessee FY2026 LIHEAP State Plan, Section 1.9 + href: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/unearned.yaml index e59041d7e57..d8e1968db14 100644 --- a/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/income/sources/unearned.yaml @@ -3,21 +3,15 @@ values: 2025-10-01: - ssi - general_assistance - - railroad_benefits - total_unemployment_compensation # Strike benefits from union funds. - strike_benefits - workers_compensation - - veterans_benefits - child_support_received - alimony_income # Money regularly received from an absent family member or someone not # living in the household. - financial_assistance - # Private and government pensions, annuities and regular insurance - # payments. - - pension_income - - military_retirement_income - survivor_benefits - disability_benefits - ordinary_dividend_income @@ -26,18 +20,19 @@ values: - farm_rent_income # Periodic receipts from estates or trusts. - estate_income -# Social Security net of the Medicare Part B premium, interest above the -# annual threshold, net gambling winnings and TANF (Families First) are -# counted in tn_liheap_countable_income. Capital gains, bank withdrawals, sale -# proceeds, tax refunds, gifts, loans, inheritances and SNAP are excluded. -# Retirement-account (IRA or 401(k)) withdrawals are not counted either: the -# Section 2.13 income list names pensions, annuities and regular insurance -# payments but not retirement-account withdrawals, and the exclusions name -# only bank-account withdrawals, so the model treats retirement-account -# withdrawals like bank withdrawals. Black Lung benefits with their first $20 -# monthly disregard, royalties, severance pay, adoption assistance, training -# stipends, military family allotments and irregular income have no existing -# input. +# Social Security, railroad retirement, pensions, military retirement and VA +# benefits are counted net of Medicare premiums through net_of_medicare. +# Interest above the annual threshold, net gambling winnings and TANF +# (Families First) are counted in tn_liheap_countable_income. Capital gains, +# bank withdrawals, sale proceeds, tax refunds, gifts, loans, inheritances and +# SNAP are excluded. Retirement-account (IRA or 401(k)) withdrawals are not +# counted either: the Section 2.13 income list names pensions, annuities and +# regular insurance payments but not retirement-account withdrawals, and the +# exclusions name only bank-account withdrawals, so the model treats +# retirement-account withdrawals like bank withdrawals. Black Lung benefits +# with their first $20 monthly disregard, royalties, severance pay, adoption +# assistance, training stipends, military family allotments and irregular +# income have no existing input. metadata: unit: list period: year diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/energy_cost_sources.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/energy_cost_sources.yaml index 505ce3bde1c..c851ac53a79 100644 --- a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/energy_cost_sources.yaml +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/energy_cost_sources.yaml @@ -1,4 +1,7 @@ -description: Tennessee adds these household energy bills to compute the energy cost in the energy burden under the Low Income Home Energy Assistance Program. +description: Tennessee uses these household energy bills for the active energy account test and the energy burden under the Low Income Home Energy Assistance Program. +# Applicants without an active energy account are not eligible, so a positive +# bill of any fuel with a reported heating type, or energy included in the +# rent, meets the account test (tn_liheap_eligible). # The energy burden uses the annual average of all household energy usage # (electric, gas, propane and other fuels), preferably over 12 months, and the # bill data includes service, usage and delivery charges and taxes. Annual diff --git a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/propane_minimum.yaml b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/propane_minimum.yaml index 6e6ffc2ce31..e2fff82332b 100644 --- a/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/propane_minimum.yaml +++ b/policyengine_us/parameters/gov/states/tn/thda/liheap/payment/propane_minimum.yaml @@ -1,8 +1,12 @@ description: Tennessee raises the regular benefit to this minimum for households that apply it to propane under the Low Income Home Energy Assistance Program. # FY2026 sets a $500 minimum propane payment because of utility company -# payment requirements. The draft 2027 manual's deliverable fuel rules omit -# the minimum, so FY2027 has none. A household heating primarily with propane -# is assumed to apply its benefit to propane. +# payment requirements, for an applicant whose home uses propane as a +# deliverable fuel and who applies a smaller benefit to propane. The draft +# 2027 manual's deliverable fuel rules omit the minimum, so FY2027 has none. +# A household with propane heat or a propane bill is assumed to apply its +# benefit to propane. A heat-in-rent benefit is paid on the landlord's energy +# vendor account named on the LI-05 agreement, so a rental heated with propane +# included in the rent is treated the same way. values: 2025-10-01: 500 2026-10-01: 0 @@ -12,7 +16,9 @@ metadata: period: year label: Tennessee LIHEAP propane minimum payment reference: - - title: Tennessee LIHEAP 2026 Policy Manual, utility selection for LIHEAP benefits + - title: "Tennessee LIHEAP 2026 Policy Manual, utility selection for LIHEAP benefits and Section 2.17 #page 25,32" href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=25 - title: Tennessee LIHEAP 2027 Policy Manual (draft), deliverable fuel benefits href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=18 + - title: Tennessee LIHEAP Landlord Tenant Energy Assistance Agreement (LI-05) + href: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-05-Landlord-Tenant-Agreement-English.pdf diff --git a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.yaml index b791da7bcb7..daf56b30358 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.yaml @@ -111,8 +111,9 @@ output: tn_liheap_eligible: false -- name: Case 5, a home with no heating is ineligible even when a heating expense is set directly. +- name: Case 5, a home with no heating that pays an electric bill is eligible. period: 2026 + absolute_error_margin: 0.01 input: people: person1: @@ -123,15 +124,16 @@ members: [person1] heating_type: NONE pre_subsidy_electricity_expense: 1_680 - # Set directly so the energy-account test passes and the no-heating - # fuel rule alone decides. - has_heating_expense: true households: household: members: [person1] state_code: TN output: - tn_liheap_eligible: false + # The electric account meets the active energy account test. + tn_liheap_eligible: true + # 1,680 / 15,080 = 0.111406 -> 0.1114 -> column 5; group C + # (13,615.50 < 15,080 <= 18,310.50); sizes 1-2 group C column 5 + tn_liheap: 445 - name: Case 6, an unknown heating fuel with heat included in rent is eligible. period: 2026 @@ -152,7 +154,7 @@ output: tn_liheap_eligible: true -- name: Case 7, an unknown heating fuel without heat in rent is ineligible even when a heating expense is set directly. +- name: Case 7, an unknown heating fuel without heat in rent is ineligible even with an electric bill. period: 2026 input: people: @@ -165,9 +167,6 @@ heating_type: UNSPECIFIED pre_subsidy_electricity_expense: 1_680 heat_expense_included_in_rent: false - # Set directly so the energy-account test passes and the - # unknown-fuel rule alone decides. - has_heating_expense: true households: household: members: [person1] diff --git a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.yaml index a5ebaf8a35d..928f9a1bc6f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.yaml @@ -297,3 +297,101 @@ output: # 994 x 12 + 1,200 = 11,928 + 1,200 tn_liheap_countable_income: 13_128 + +- name: Case 12, every earned income source counts. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + employment_income_before_lsr: 10_000 + self_employment_income_before_lsr: 1_000 + sstb_self_employment_income_before_lsr: 2_000 + farm_operations_income: 3_000 + partnership_income: 4_000 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # Wages 10,000 + self-employment 1,000 + SSTB self-employment 2,000 + # + farm operations 3,000 + partnership 4,000 = 20,000 + tn_liheap_countable_income: 20_000 + +- name: Case 13, every listed unearned income source counts. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + general_assistance: 1_000 + unemployment_compensation: 2_000 + strike_benefits: 3_000 + workers_compensation: 4_000 + alimony_income: 5_000 + survivor_benefits: 6_000 + disability_benefits: 7_000 + qualified_dividend_income: 8_000 + rental_income: 9_000 + farm_rent_income: 10_000 + estate_income: 11_000 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1] + state_code: TN + output: + # General assistance 1,000 + unemployment 2,000 + strike 3,000 + # + workers' compensation 4,000 + alimony 5,000 + survivor 6,000 + # + disability 7,000 + dividends 8,000 + rental 9,000 + farm rent 10,000 + # + estate 11,000 = 66,000 + tn_liheap_countable_income: 66_000 + +- name: Case 14, railroad, pension, military retirement and VA benefits are counted net of Medicare Part A and Part B premiums. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + ssi: 0 + railroad_benefits: 16_000 + taxable_private_pension_income: 4_000 + # Premium-free Part A at the default 40 quarters; 2026 standard + # Part B premium of 202.90 a month. + medicare_part_b_premium: 2_434.80 + person2: + age: 68 + ssi: 0 + military_retirement_pay: 8_000 + # Survivor benefit plan annuity. + military_retirement_pay_survivors: 2_000 + veterans_benefits: 1_000 + # 2026 reduced Part A premium of 311 a month (30-39 quarters). + medicare_part_a_premium: 3_732 + medicare_part_b_premium: 2_434.80 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household: + members: [person1, person2] + state_code: TN + output: + # person1: 16,000 + 4,000 - (0 + 2,434.80) = 17,565.20 + # person2: (8,000 + 2,000) + 1,000 - (3,732 + 2,434.80) = 4,833.20 + # 17,565.20 + 4,833.20 = 22,398.40 + tn_liheap_countable_income: 22_398.40 diff --git a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/tn_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/tn_liheap.yaml index 636a202328e..08113274a4e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/tn_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/tn/thda/liheap/tn_liheap.yaml @@ -542,3 +542,158 @@ # (1,200 + 3,000) / 90,000 = 0.046667 -> 0.0467 -> column 1; # nine-or-more group D column 1 = 540 (the sizes 6-8 group would give 409) tn_liheap: 540 + +- name: Case 22, fuel oil, wood, coal and other fuel bills add to electricity in the energy cost. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: FUEL_OIL + pre_subsidy_electricity_expense: 1_200 + fuel_oil_expense: 800 + wood_expense: 400 + coal_expense: 200 + other_heating_fuel_expense: 100 + households: + household: + members: [person1] + state_code: TN + output: + # 1,200 + 800 + 400 + 200 + 100 = 2,700 + tn_liheap_energy_cost: 2_700 + # 2,700 / 15,080 = 0.179045 -> 0.1790 -> column 7; group C + # (13,615.50 < 15,080 <= 18,310.50); sizes 1-2 group C column 7 + tn_liheap: 700 + +- name: Case 23, a seventeen-person household in FFY2027 uses the size-sixteen income groups beside a household outside Tennessee. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: {age: 45, employment_income_before_lsr: 50_000} + person2: {age: 43, employment_income_before_lsr: 30_000} + person3: {age: 17} + person4: {age: 16} + person5: {age: 15} + person6: {age: 14} + person7: {age: 13} + person8: {age: 12} + person9: {age: 11} + person10: {age: 10} + person11: {age: 9} + person12: {age: 8} + person13: {age: 7} + person14: {age: 6} + person15: {age: 5} + person16: {age: 4} + person17: {age: 3} + person18: {age: 40, employment_income_before_lsr: 15_080} + tax_units: + tax_unit1: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15, person16, person17] + tax_unit2: + members: [person18] + families: + family1: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15, person16, person17] + family2: + members: [person18] + marital_units: + marital_unit1: {members: [person1, person2]} + marital_unit2: {members: [person3]} + marital_unit3: {members: [person4]} + marital_unit4: {members: [person5]} + marital_unit5: {members: [person6]} + marital_unit6: {members: [person7]} + marital_unit7: {members: [person8]} + marital_unit8: {members: [person9]} + marital_unit9: {members: [person10]} + marital_unit10: {members: [person11]} + marital_unit11: {members: [person12]} + marital_unit12: {members: [person13]} + marital_unit13: {members: [person14]} + marital_unit14: {members: [person15]} + marital_unit15: {members: [person16]} + marital_unit16: {members: [person17]} + marital_unit17: {members: [person18]} + spm_units: + spm_unit1: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15, person16, person17] + tanf: 0 + heating_type: NATURAL_GAS + gas_expense: 1_800 + pre_subsidy_electricity_expense: 3_000 + spm_unit2: + members: [person18] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_680 + households: + household1: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14, person15, person16, person17] + state_code: TN + household2: + members: [person18] + state_code: KY + output: + tn_liheap_household_size: [17, 0] + # floor(1.5 x (15,960 + 5,680 x 16)) = floor(1.5 x 106,840) = 160,260 + tn_liheap_income_limit: [160_260, 0] + # 1,800 + 3,000 = 4,800; the Kentucky household has no Tennessee cost + tn_liheap_energy_cost: [4_800, 0] + # 50,000 + 30,000 = 80,000; size 17 uses the printed size-16 tops + # (group A 71,312.50, group B 87,382.50), so group B; + # 4,800 / 80,000 = 0.06 -> column 2; nine-or-more group B column 2. + # The Kentucky household runs the formula at size 0 and receives nothing. + tn_liheap: [605, 0] + +- name: Case 24, a propane bill in a home heated by electricity raises an FFY2026 benefit to the propane minimum. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 20_000 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_000 + # Propane for cooking and water heating. + bottled_gas_expense: 200 + households: + household: + members: [person1] + state_code: TN + output: + # (1,000 + 200) / 20,000 = 0.06 -> column 2, group D (above 18,310.50): + # max(250, 500) + tn_liheap: 500 + +- name: Case 25, propane heat included in rent receives the FFY2026 propane minimum. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 15_080 + spm_units: + spm_unit: + members: [person1] + heating_type: PROPANE + heat_expense_included_in_rent: true + bottled_gas_expense: 0 + households: + household: + members: [person1] + state_code: TN + output: + # 0 / 15,080 = 0 -> column 1, group C: max(174, 500) + tn_liheap: 500 diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.py b/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.py index ab08104f83a..a048e993367 100644 --- a/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/eligibility/tn_liheap_eligible.py @@ -9,8 +9,8 @@ class tn_liheap_eligible(Variable): label = "Tennessee LIHEAP regular assistance eligibility" defined_for = StateCode.TN reference = ( - # PDF pages 24, 32-33 - "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=24", + # PDF pages 8, 24, 32-33 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=8", "https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=8", "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", ) @@ -28,20 +28,19 @@ def formula(spm_unit, period, parameters): guideline = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) floor = np.round(guideline * p_hhs.fpg_floor, 2) income_eligible = (income <= limit) | (income < floor) - # Applicants need an active energy account, or energy included in the - # rent under a landlord/tenant agreement. - heat_in_rent = spm_unit("heat_expense_included_in_rent", period) - responsible = spm_unit("has_heating_expense", period) | heat_in_rent + # Section 2.18 bars applicants "who do not have an active energy + # account", and Section 1.2 defines one as a current utility account + # that reflects billing and usage. The one regular award is applied as + # heating or cooling assistance, so a counted bill of any fuel meets + # the test, including in a home without heating. Energy included in + # the rent under a landlord/tenant agreement also qualifies (Section + # 2.17). heating_type is a required input, so an unspecified fuel + # qualifies only through heat in the rent. Subsidized tenants with a + # bill in their name are processed without adjustment, so housing + # assistance is no condition here. + has_energy_cost = spm_unit("tn_liheap_energy_cost", period) > 0 heating_type = spm_unit("heating_type", period) - types = heating_type.possible_values - # The matrix has no fuel column, so an unspecified fuel qualifies only - # when heat is included in the rent; otherwise UNSPECIFIED pays $0. - # The derived has_heating_expense is already false for an unspecified - # fuel, but the clause keeps that rule when a caller sets - # has_heating_expense directly. Subsidized tenants with a bill in their - # name are processed without adjustment, so housing assistance is no - # condition here. - fuel_qualifies = (heating_type != types.NONE) & ( - heat_in_rent | (heating_type != types.UNSPECIFIED) - ) - return (size > 0) & income_eligible & responsible & fuel_qualifies + known_fuel = heating_type != heating_type.possible_values.UNSPECIFIED + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + responsible = (has_energy_cost & known_fuel) | heat_in_rent + return (size > 0) & income_eligible & responsible diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.py b/policyengine_us/variables/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.py index dec4dc44183..bb871b4808b 100644 --- a/policyengine_us/variables/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.py +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/income/tn_liheap_countable_income.py @@ -33,16 +33,21 @@ def formula(spm_unit, period, parameters): unearned = 0 for source in p.sources.unearned: unearned = unearned + max_(person(source, period, options=[ADD]), 0) - # Net Social Security excludes Medicare premiums, and FY2026 plan - # Section 1.9 counts benefits excluding the Medicare deduction, so the - # Part B premium the person pays is subtracted. - social_security = max_( - person("social_security", period) - - person("medicare_part_b_premium", period), - 0, + # Section 2.13 counts net income from Social Security, pensions + # (including military retirement pay) and VA benefits excluding + # Medicare premiums, and FY2026 plan Section 1.9 counts benefits + # excluding the Medicare deduction. Each member's Part A and Part B + # premiums are subtracted from those benefits, floored at zero. + benefits = max_(person("social_security", period), 0) + for source in p.sources.net_of_medicare: + benefits = benefits + max_(person(source, period), 0) + medicare_premiums = add( + person, period, ["medicare_part_a_premium", "medicare_part_b_premium"] ) + net_benefits = max_(benefits - medicare_premiums, 0) # Interest counts only above the annual threshold and when withdrawn; - # withdrawal has no input and is assumed. + # withdrawal has no input and is assumed. Section 2.13 names no unit + # for the threshold; the model applies it to each member's interest. interest = max_(person("interest_income", period), 0) counted_interest = where(interest > p.interest_threshold, interest, 0) gambling = max_( @@ -55,7 +60,7 @@ def formula(spm_unit, period, parameters): person_income = ( earned * earned_counted + unearned - + social_security + + net_benefits + counted_interest + gambling ) diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap.py b/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap.py index 91f840cc41a..7ee04897cdb 100644 --- a/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap.py +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap.py @@ -12,10 +12,14 @@ class tn_liheap(Variable): "Tennessee's single annual regular award from the statewide benefit " "matrix, by household size group, income group and energy burden, " "applied as heating assistance from October through May and as " - "cooling assistance from June through September. Verified for FY2026 " - "and FY2027 (the posted LI-12 matrix, with the FY2027 plan and manual " - "in draft); earlier years are unverified estimates through parameter " - "backfilling. Crisis assistance and weatherization are out of scope." + "cooling assistance from June through September (2026 Policy Manual " + "page 35; the FY2026 plan's component dates are October 1 to April 30 " + "for heating and May 1 to September 30 for cooling). Verified for " + "FY2026 and FY2027 (the posted LI-12 matrix, with the FY2027 plan and " + "manual in draft). Earlier years are unverified estimates: they " + "backfill the FY2026 values and do not reproduce the priority-points " + "matrix Tennessee used before FY2026. Crisis assistance and " + "weatherization are out of scope." ) defined_for = "tn_liheap_eligible" reference = ( @@ -24,7 +28,8 @@ class tn_liheap(Variable): "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=1", # PDF pages 12, 25, 31-32, 34-35 "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=12", - "https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=9", + # PDF pages 4, 9 + "https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=4", # PDF pages 28-31 "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-26-Workshop-Powerpoint-09.16.25.pdf#page=28", ) @@ -32,7 +37,7 @@ class tn_liheap(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.tn.thda.liheap income = spm_unit("tn_liheap_countable_income", period) - energy_cost = add(spm_unit, period, p.payment.energy_cost_sources) + energy_cost = spm_unit("tn_liheap_energy_cost", period) # Annual cost over annual income stands in for the 12-month average # energy cost over 30-day income. Heat included in the rent counts # only separately billed energy, so its column is a lower bound. The @@ -84,9 +89,15 @@ def formula(spm_unit, period, parameters): for top in tops: income_group = income_group + (income > top) amount = p.payment.amount[size_group][income_group][column] - # The FY2026 manual sets a $500 minimum when a benefit is applied to - # propane; a household heating with propane is assumed to apply it - # there. No supplement or bill cap applies. + # The FY2026 manual lets an applicant whose home uses propane as a + # deliverable fuel apply a smaller benefit to propane at the minimum + # payment (page 25). A household with propane heat or a propane bill + # is assumed to take that option. A heat-in-rent benefit is paid on + # the landlord's energy vendor account named on the LI-05 agreement, + # so a rental heated with propane included in the rent takes it too. + # No supplement or bill cap applies. heating_type = spm_unit("heating_type", period) - propane = heating_type == heating_type.possible_values.PROPANE + propane_heat = heating_type == heating_type.possible_values.PROPANE + propane_bill = spm_unit("bottled_gas_expense", period) > 0 + propane = propane_heat | propane_bill return where(propane, max_(amount, p.payment.propane_minimum), amount) diff --git a/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap_energy_cost.py b/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap_energy_cost.py new file mode 100644 index 00000000000..13d46b87172 --- /dev/null +++ b/policyengine_us/variables/gov/states/tn/thda/liheap/tn_liheap_energy_cost.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class tn_liheap_energy_cost(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Tennessee LIHEAP annual energy cost" + documentation = ( + "Annual household energy bills of every fuel, used for the active " + "energy account test and as the numerator of the energy burden." + ) + defined_for = StateCode.TN + reference = ( + # PDF pages 8, 32-33 + "https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=8", + "https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=9", + ) + + adds = "gov.states.tn.thda.liheap.payment.energy_cost_sources" diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 843ddcbe21c..b1ce20a083f 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -5231,6 +5231,104 @@ candidates: - https://github.com/PolicyEngine/policyengine-us/pull/9974 state: unreviewed note: 'PE-US follows the plan and rules, not the 2018 manual: only wood and coal are paid in full, so kerosene is capped at unpaid charges like fuel oil (sd_liheap.py). Confirm the recipient and whether unpaid charges cap the award.' +- id: us-tn:liheap-fy2026-printed-income-ceilings + program: liheap + years: + from: 2026 + to: 2026 + type: federal-fiscal + question: Are Tennessee's FY2026 LIHEAP income ceilings 60% of state median income, as the plan and manual state, or + the amounts printed in the benefit matrix and workshop deck where they differ? + sources: + - kind: plan + citation: Tennessee FY2026 LIHEAP State Plan, Section 2.1, page 8 + url: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=8 + - kind: manual + citation: Tennessee LIHEAP 2026 Policy Manual, Section 2.10, page 24 + url: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=24 + - kind: guidance + citation: Tennessee LIHEAP 2026 Benefit Matrix, income end column + url: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2026-LIHEAP-Eligible-Income-Household-Size-Benefits.pdf + - kind: guidance + citation: Tennessee LIHEAP 26 Workshop, Benefit Matrix Adjustments 2026, page 30 + url: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-26-Workshop-Powerpoint-09.16.25.pdf#page=30 + readings: + statute: No statute is supplied; the plan and manual set the limit at 60% of state median income, $85,064 for a + household of eight and $81,366 for a household of six. + other: The benefit matrix prints $85,064.50 for a household of eight, and the workshop deck prints $81,336 for a + household of six. + example: In FY2026, a household of eight with income of $85,064.50 and energy bills of $4,000 receives $300 under the + printed matrix ceiling (group D, burden 0.0470, column 1) and $0 under the 60% state median income limit. + pe_us: + follows: gap-fill + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10430 + state: unreviewed + note: 'PE-US applies 60% of state median income, which reproduces every other printed FY2026 ceiling for sizes 1-12. + Code not yet on main: tn_liheap_income_limit, gov.states.tn.thda.liheap.eligibility.smi_rate.' +- id: us-tn:liheap-fy2027-large-household-limits + program: liheap + years: + from: 2027 + to: 2027 + type: federal-fiscal + question: Are Tennessee's FY2027 LIHEAP income limits for households of 13 to 16 members 150% of the poverty guideline, + as the draft plan and manual state, or the lower ceilings printed in the LI-12 matrix? + sources: + - kind: plan + citation: Tennessee FY2027 LIHEAP State Plan (draft), Section 2.1, page 9 + url: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DETAILED-MODEL-PLAN-LIHEAP_10_01_2026.pdf#page=9 + - kind: manual + citation: Tennessee LIHEAP 2027 Policy Manual (draft), Section 2.10, page 27 + url: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/DRAFT-LIHEAP-2027-Policy-Manual-7-11-2026.pdf#page=27 + - kind: guidance + citation: Tennessee FY2027 LIHEAP Benefit Matrix (LI-12), page 4 + url: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/2027-LIHEAP-LI-12-Eligible-Income-Benefit-Matrix.pdf#page=4 + readings: + statute: No statute is supplied; the draft plan (sizes 9-15) and draft manual (sizes 9-16) set the limit at 150% of + the poverty guideline, $126,180 to $151,740 for sizes 13-16. + other: The LI-12 matrix prints ceilings of $125,910 to $150,660 for sizes 13-16. + example: In FY2027, a household of 13 with income of $126,000 and energy bills of $4,200 receives $540 under the 150% + rule (group D, burden 0.0333, column 1) and $0 under the printed $125,910 ceiling. + pe_us: + follows: gap-fill + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10430 + state: unreviewed + note: 'PE-US applies the stated 150% rule to every size from 9. Code not yet on main: tn_liheap_income_limit, + gov.states.tn.thda.liheap.eligibility.fpg_rate.' +- id: us-tn:liheap-retirement-account-withdrawals + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Does Tennessee LIHEAP count IRA and 401(k) withdrawals as income, as the plan's checked "Retirement / pension + benefits" box suggests, or exclude them, as the manual's income list does by naming none? + sources: + - kind: manual + citation: Tennessee LIHEAP 2026 Policy Manual, Section 2.13, pages 27-28 + url: https://dogvxws799i6n.cloudfront.net/wp-content/uploads/LIHEAP-2026-Policy-Manual-for-Tennessee.pdf#page=27 + - kind: plan + citation: Tennessee FY2026 LIHEAP State Plan, Section 1.9, page 6 + url: https://liheapch.acf.gov/docs/2026/state-plans/TN_Plan_2026.pdf#page=6 + readings: + statute: No statute is supplied; the manual counts pensions, annuities and regular insurance payments, names no + retirement-account withdrawals and excludes withdrawals from a bank account. + other: Plan 1.9 checks "Retirement / pension benefits" as countable income. + example: In FY2026, a single retiree aged 70 with Social Security of $12,000, a Part B premium of $2,434.80, IRA + withdrawals of $20,000 and an electric bill of $1,680 receives $710 with the withdrawals excluded (income $9,565.20, + group A, column 7) and $250 with them counted (income $29,565.20, group D, column 2). + pe_us: + follows: gap-fill + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10430 + state: ruled + note: 'Ruled 2026-10-23: exclude IRA/401(k) withdrawals as the manual does. Code not yet on main: + tn_liheap_countable_income, gov.states.tn.thda.liheap.income.sources.unearned.' - id: us-tx:family-planning-unearned-income-exclusions program: family-planning-program years: