From 8b463c379d4267af55d7265d5068b27ed67dfcfb Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 23 Oct 2026 18:11:13 -0400 Subject: [PATCH 1/5] Add Missouri LIHEAP Energy Assistance Co-Authored-By: Claude Opus 5.5 --- changelog.d/mo-liheap-wave1d.added.md | 1 + .../gov/states/mo/dss/liheap/amount.yaml | 55 ++++ .../dss/liheap/eligibility/fpg_year_lag.yaml | 17 ++ .../liheap/eligibility/resource_limit.yaml | 21 ++ .../mo/dss/liheap/eligibility/smi_rate.yaml | 25 ++ .../mo/dss/liheap/income/adult_age.yaml | 22 ++ .../liheap/income/adult_unearned_sources.yaml | 19 ++ .../income/disability_benefit_sources.yaml | 35 +++ .../income/earned_income_deduction_rate.yaml | 11 + .../mo/dss/liheap/income/earned_sources.yaml | 21 ++ .../mo/dss/liheap/income/elderly_age.yaml | 13 + .../dss/liheap/income/medical_deduction.yaml | 13 + .../dss/liheap/income/unearned_sources.yaml | 53 ++++ .../gov/states/mo/dss/liheap/rent_share.yaml | 30 ++ policyengine_us/programs.yaml | 10 +- .../eligibility/mo_liheap_eligible.yaml | 263 +++++++++++++++++ .../eligibility/mo_liheap_income_limit.yaml | 37 +++ .../income/mo_liheap_countable_income.yaml | 124 ++++++++ .../mo_liheap_countable_income_person.yaml | 268 ++++++++++++++++++ .../income/mo_liheap_medical_deduction.yaml | 235 +++++++++++++++ .../gov/states/mo/dss/liheap/integration.yaml | 130 +++++++++ .../gov/states/mo/dss/liheap/mo_liheap.yaml | 145 ++++++++++ .../dss/liheap/mo_liheap_household_size.yaml | 99 +++++++ .../liheap/eligibility/mo_liheap_eligible.py | 52 ++++ .../eligibility/mo_liheap_income_limit.py | 27 ++ .../income/mo_liheap_countable_income.py | 34 +++ .../mo_liheap_countable_income_person.py | 41 +++ .../income/mo_liheap_medical_deduction.py | 39 +++ .../gov/states/mo/dss/liheap/mo_liheap.py | 29 ++ .../mo/dss/liheap/mo_liheap_household_size.py | 18 ++ source_conflicts/candidates.yaml | 70 +++++ 31 files changed, 1956 insertions(+), 1 deletion(-) create mode 100644 changelog.d/mo-liheap-wave1d.added.md create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/resource_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/smi_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/income/adult_age.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/income/adult_unearned_sources.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/income/disability_benefit_sources.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/income/earned_income_deduction_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/income/earned_sources.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/income/elderly_age.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/income/medical_deduction.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/integration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap_household_size.yaml create mode 100644 policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py create mode 100644 policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.py create mode 100644 policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.py create mode 100644 policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py create mode 100644 policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.py create mode 100644 policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py create mode 100644 policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py diff --git a/changelog.d/mo-liheap-wave1d.added.md b/changelog.d/mo-liheap-wave1d.added.md new file mode 100644 index 00000000000..5a78d2cf416 --- /dev/null +++ b/changelog.d/mo-liheap-wave1d.added.md @@ -0,0 +1 @@ +Add Missouri LIHEAP Energy Assistance for regular heating (FY2026-FY2027). diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml new file mode 100644 index 00000000000..1d980453293 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml @@ -0,0 +1,55 @@ +description: Missouri provides this one-time Energy Assistance payment by primary heating fuel under the Low Income Home Energy Assistance Program. +# The same amounts appear in the October 2025 manual (its Appendix K), the +# FFY2026 Appendix K matrix and the FFY2027 application. 13 CSR 40-19.020(14) +# bases payments on household size, income range and fuel source, using +# metrics established by the division, and prints a 2017 table of payments +# that decline across income ranges from 0 to 135 percent of the poverty level. +# The FFY2026 plan, the Appendix K matrix, the October 2025 manual and the +# 8-2026 application set one amount per fuel for incomes up to 60 percent of +# state median income; the model applies those amounts. +NATURAL_GAS: + 2023-10-01: 326 +# Tank propane. The schedule also pays $177 for cylinder propane, which is not +# reachable because heating_type has a single propane value. +PROPANE: + 2023-10-01: 495 +ELECTRICITY: + 2023-10-01: 318 +FUEL_OIL: + 2023-10-01: 326 +WOOD: + 2023-10-01: 219 +KEROSENE: + 2023-10-01: 153 +# Solar-heated homes are paid on their electric account at the electric amount. +SOLAR: + 2023-10-01: 318 +# Households that heat with coal are denied (October 2025 manual Appendix E, +# denial code O); mo_liheap_eligible applies that denial. +COAL: + 2023-10-01: 0 +# The schedule has no row for other fuels. +OTHER: + 2023-10-01: 0 +NONE: + 2023-10-01: 0 +UNSPECIFIED: + 2023-10-01: 0 + +metadata: + unit: currency-USD + period: year + label: Missouri LIHEAP Energy Assistance amount by heating fuel + breakdown: + - heating_type + reference: + - title: "13 CSR 40-19.020(3)(A) and (4) #page 2-3" + href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + - title: Missouri LIHEAP FFY2026 State Plan, Sections 2.5 and 2.6 + href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=9 + - title: Missouri LIHEAP FFY2026 Appendix K, Income Ranges and Benefit Amounts + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/MO_BenefitMatrix_2026.docx + - title: Missouri LIHEAP application MO 886-4576 (8-2026), Program Description + href: https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=1 + - title: "Missouri LIHEAP Policy and Procedure Manual (October 2025), Appendix E and Appendix K #page 122,129" + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=122 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/fpg_year_lag.yaml new file mode 100644 index 00000000000..e29cf5e154b --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/fpg_year_lag.yaml @@ -0,0 +1,17 @@ +description: Missouri uses the federal poverty guidelines from this many years before the model year for the 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 (FFY2026) uses the 2025 guidelines and 2027 (FFY2027) the +# 2026 guidelines. Backfilled years use their lagged guidelines and are +# unverified. +values: + 2025-10-01: 1 + +metadata: + unit: year + period: year + label: Missouri 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: LIHEAP IM 2026-01, poverty guidelines for optional use in FY26 and mandatory use in FY27 + href: https://acf.gov/ocs/policy-guidance/liheap-im2026-01-federal-poverty-guidelines-fpg-and-state-median-income-smi diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/resource_limit.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/resource_limit.yaml new file mode 100644 index 00000000000..2069a8d678d --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/resource_limit.yaml @@ -0,0 +1,21 @@ +description: Missouri limits household resources to this amount under the Low Income Home Energy Assistance Program. +# Applied to spm_unit_cash_assets. Individual retirement accounts, Keogh plans, +# deferred compensation plans and annuities (13 CSR 40-19.020(2)(N); the +# October 2025 manual's list omits annuities) count as resources but lack +# asset inputs. +values: + 2017-05-30: 3_000 + +metadata: + unit: currency-USD + period: year + label: Missouri LIHEAP resource limit + reference: + - title: "13 CSR 40-19.020(2)(N) and (6)(B) #page 2-3" + href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + - title: Missouri LIHEAP FFY2026 State Plan, Section 2.3 + href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8 + - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Resources + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=40 + - title: Missouri DSS draft FFY2027 LIHEAP State Plan (report status Saved with Errors), Section 2.3 + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=8 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/smi_rate.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/smi_rate.yaml new file mode 100644 index 00000000000..017049e473e --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/smi_rate.yaml @@ -0,0 +1,25 @@ +description: Missouri limits household income to this share of the state median income under the Low Income Home Energy Assistance Program. +# The published monthly limits equal the HHS LIHEAP limit for the household +# size divided by twelve and rounded to the nearest dollar (FFY2026 sizes 1-20, +# FFY2027 sizes 1-10). 13 CSR 40-19.020(6)(D) refers to the income ranges of +# section (14), a 2017 table that runs from 0 to 135 percent of the poverty +# level; the FFY2026 plan, Appendix K, the October 2025 manual and the 8-2026 +# application set this share of state median income. +values: + 2023-10-01: 0.6 + +metadata: + unit: /1 + period: year + label: Missouri LIHEAP state median income rate + reference: + - title: Missouri LIHEAP FFY2026 State Plan, Section 2.1 + href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8 + - title: Missouri LIHEAP FFY2026 Appendix K, Income Ranges and Benefit Amounts + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/MO_BenefitMatrix_2026.docx + - title: Missouri LIHEAP application MO 886-4576 (8-2026), Program Description + href: https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=1 + - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Appendix K + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=129 + - title: Missouri DSS draft FFY2027 LIHEAP State Plan (report status Saved with Errors), Section 2.1 + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=8 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/adult_age.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/adult_age.yaml new file mode 100644 index 00000000000..1777fc462ce --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/adult_age.yaml @@ -0,0 +1,22 @@ +description: Missouri excludes the earned income and the disability income of household members below this age under the Low Income Home Energy Assistance Program. +# The October 2025 manual leaves out the earned income and the disability +# income of a household member under 18 but counts the member's SSA income +# (adult_unearned_sources lists the disability payments). The FFY2026 plan does +# not count the earned income of a child under 18, and the 8-2026 application +# asks for job income only from members 18 or older. +values: + 2023-10-01: 18 + +metadata: + unit: year + period: year + label: Missouri LIHEAP adult age + reference: + - title: Missouri LIHEAP FFY2026 State Plan, Section 1.9 + href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=6 + - title: Missouri LIHEAP application MO 886-4576 (8-2026), Part 5 Household Income + href: https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=4 + - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Earnings of Children + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=38 + - title: Missouri DSS draft FFY2027 LIHEAP State Plan (report status Saved with Errors), Section 1.9 + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/adult_unearned_sources.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/adult_unearned_sources.yaml new file mode 100644 index 00000000000..8d64b06c09f --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/adult_unearned_sources.yaml @@ -0,0 +1,19 @@ +description: Missouri counts these unearned income sources only for household members at or above the adult age under the Low Income Home Energy Assistance Program. +# The October 2025 manual does not count the unearned income from disability +# of a household member under 18 but counts the member's SSA income. Social +# Security and SSI are read as SSA income and count at any age. +# disability_benefits (employment-based disability payments other than Social +# Security and workers' compensation) stands in for the manual's short- and +# long-term disability payments; workers' compensation and veterans benefits +# count at any age (unearned_sources). +values: + 2025-10-01: + - disability_benefits + +metadata: + unit: list + period: year + label: Missouri LIHEAP adult-only unearned income sources + reference: + - title: "Missouri LIHEAP Policy and Procedure Manual (October 2025), Unearned Income and Earnings of Children #page 34,38" + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=34 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/disability_benefit_sources.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/disability_benefit_sources.yaml new file mode 100644 index 00000000000..aece6789354 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/disability_benefit_sources.yaml @@ -0,0 +1,35 @@ +description: Missouri treats a totally and permanently disabled or blind individual as disabled for the medical deduction when the individual receives one of these benefits under the Low Income Home Energy Assistance Program. +# The medical deduction also requires the member to be disabled or blind. With +# that requirement, the general veterans and railroad benefit inputs stand in +# for Veterans Administration and Railroad Retirement disability benefits, and +# the general Social Security dependents and survivors inputs stand in for +# disabled adult child and disabled widow(er) benefits. These four inputs also +# include benefits a disabled member receives for reasons other than +# disability, such as Social Security spousal, aged survivor or child-in-care +# benefits or a railroad age-and-service annuity, since no input separates +# them. Civil Service Disability and Black Lung benefits have no separate +# inputs. +values: + 2017-05-30: + - ssi + - social_security_disability + # General dependents and survivors benefits; see the note above. + - social_security_dependents + - social_security_survivors + - veterans_benefits + - railroad_benefits + # Medical Assistance (MO HealthNet). + - medicaid + # State Supplemental Payments, State Aid to the Blind and State Blind + # Pension. + - mo_ssp + +metadata: + unit: list + period: year + label: Missouri LIHEAP disability benefit sources + reference: + - title: 13 CSR 40-19.020(2)(C) + href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + - title: "Missouri LIHEAP Policy and Procedure Manual (October 2025), Medical Deduction for Elderly-Disabled and Disability #page 36,48" + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/earned_income_deduction_rate.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/earned_income_deduction_rate.yaml new file mode 100644 index 00000000000..1c1cf974dcd --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/earned_income_deduction_rate.yaml @@ -0,0 +1,11 @@ +description: Missouri deducts this share of earned income in determining countable income under the Low Income Home Energy Assistance Program. +values: + 2023-10-01: 0.2 + +metadata: + unit: /1 + period: year + label: Missouri LIHEAP earned income deduction rate + reference: + - title: "Missouri LIHEAP Policy and Procedure Manual (October 2025), Self-Employment-Partnership Income and Income Deductions #page 32,36" + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=32 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/earned_sources.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/earned_sources.yaml new file mode 100644 index 00000000000..5ecfa754439 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/earned_sources.yaml @@ -0,0 +1,21 @@ +description: Missouri counts these earned income sources, after the earned income deduction, under the Low Income Home Energy Assistance Program. +# Each source is floored at zero: business and farm losses do not offset other +# income. Net business income inputs stand in for the Form 1040 business lines. +# Roomer and boarder income is also earned income but has no input. +values: + 2023-10-01: + - employment_income + - self_employment_income + - sstb_self_employment_income + - farm_operations_income + - partnership_s_corp_income + +metadata: + unit: list + period: year + label: Missouri LIHEAP earned income sources + reference: + - title: "Missouri LIHEAP FFY2026 State Plan, Sections 1.8 and 1.9 #page 5-7" + href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=5 + - title: "Missouri LIHEAP Policy and Procedure Manual (October 2025), Self-Employment-Partnership Income and Income Deductions #page 32,36" + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=32 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/elderly_age.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/elderly_age.yaml new file mode 100644 index 00000000000..45b26a8f352 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/elderly_age.yaml @@ -0,0 +1,13 @@ +description: Missouri treats applicants and spouses at or above this age as elderly for the medical deduction under the Low Income Home Energy Assistance Program. +values: + 2017-05-30: 65 + +metadata: + unit: year + period: year + label: Missouri LIHEAP elderly age + reference: + - title: 13 CSR 40-19.020(2)(D) + href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Medical Deduction for Elderly-Disabled + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/medical_deduction.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/medical_deduction.yaml new file mode 100644 index 00000000000..207908e8844 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/medical_deduction.yaml @@ -0,0 +1,13 @@ +description: Missouri deducts this amount for medical expenses, once per household, when the applicant or spouse is elderly or disabled under the Low Income Home Energy Assistance Program. +values: + 2017-05-30: 100 + +metadata: + unit: currency-USD + period: month + label: Missouri LIHEAP medical deduction + reference: + - title: "13 CSR 40-19.020(2)(C), (2)(D) and (6)(D)1 #page 2-3" + href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Medical Deduction for Elderly-Disabled + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml new file mode 100644 index 00000000000..351df33790e --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml @@ -0,0 +1,53 @@ +description: Missouri counts these unearned income sources under the Low Income Home Energy Assistance Program. +# Social Security counts net of the Medicare Part B premium in +# mo_liheap_countable_income_person, and Missouri TANF is added at the +# household level in mo_liheap_countable_income. Short- and long-term +# disability payments count only for members 18 or older +# (adult_unearned_sources). +# Interest and dividends are excluded (October 2025 manual, page 38), as are +# capital gains, which page 38 treats as lump sums; page 32 lists the Form 1040 +# capital gains line among self-employment documents. Foster care payments, +# royalties, roomer and boarder payments, armed forces allotments and +# installment income have no inputs. +# Retirement-account (IRA, Keogh or 401(k)) withdrawals are not counted: the +# income lists name pensions but not account withdrawals, and IRA and Keogh +# balances count as resources (manual page 40; 13 CSR 40-19.020(2)(N)), so +# the model treats a withdrawal as a change in resources, not income. +values: + 2023-10-01: + - total_unemployment_compensation + # Union funds or strike benefits. + - strike_benefits + - ssi + # Supplemental Aid to the Blind, Blind Pension and Supplemental State + # Payments. + - mo_ssp + - pension_income + - military_retirement_income + - railroad_benefits + # Rent received from land or buildings, including farm rent and + # Conservation Reserve Program payments. + - rental_income + - farm_rent_income + - alimony_income + - child_support_received + - veterans_benefits + - workers_compensation + # Contributions: money received from friends, family or organizations. + - financial_assistance + +metadata: + unit: list + period: year + label: Missouri LIHEAP unearned income sources + reference: + - title: "Missouri LIHEAP FFY2026 State Plan, Section 1.9 #page 5-7" + href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=5 + - title: Missouri LIHEAP application MO 886-4576 (8-2026), Part 7 Other Income + href: https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=5 + - title: "Missouri LIHEAP Policy and Procedure Manual (October 2025), Unearned Income, Income Exclusions and Resources #page 32-34,38,40" + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=32 + - title: 13 CSR 40-19.020(2)(N), Low-Income Home Energy Assistance Program + href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + - title: "Missouri DSS draft FFY2027 LIHEAP State Plan (report status Saved with Errors), Section 1.9 #page 5-7" + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml new file mode 100644 index 00000000000..ae4e181ec0d --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml @@ -0,0 +1,30 @@ +description: Missouri pays a renter household whose heating costs are included in the rent this share of its annual rent, up to the Energy Assistance amount for its heating fuel, under the Low Income Home Energy Assistance Program. +# 13 CSR 40-19.020(13) sets a payment of no more than eight percent of annual +# rent, applied here. The October 2025 manual (page 63), the FFY2024-FFY2026 +# plans and the DSS draft FFY2027 plan (section 2.3) describe 16 percent; the +# manual caps the payment at the Energy Assistance amount for the household's +# energy source. RSMo 660.115.2 separately limits renter payments from the +# state Utilicare stabilization fund to the lesser of eight percent of annual +# rent or $100; Energy Assistance is paid from federal LIHEAP funds. +values: + 2017-05-30: 0.08 + +metadata: + unit: /1 + period: year + label: Missouri LIHEAP renter annual rent share + reference: + - title: 13 CSR 40-19.020(13) + href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=4 + - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Renter Household Payment + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=63 + - title: Missouri LIHEAP FFY2026 State Plan, Section 2.3 + href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8 + - title: Missouri DSS draft FFY2027 LIHEAP State Plan (report status Saved with Errors), Section 2.3 + href: https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=8 + - title: Missouri LIHEAP FFY2025 State Plan, Section 2.3 + href: https://liheapch.acf.gov/docs/2025/state-plans/MO_Plan_2025.pdf#page=8 + - title: Missouri LIHEAP FFY2024 State Plan, Section 2.3 + href: https://liheapch.acf.gov/docs/2024/state-plans/MO_Plan_2024.pdf#page=8 + - title: RSMo 660.115 + href: https://revisor.mo.gov/main/OneSection.aspx?section=660.115 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 43fdd714b80..d4af6426928 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, MO, MS, NC, NE, NJ, NY, OH, OK, OR, SD, RI, TX state_implementations: - state: AL status: partial @@ -898,6 +898,14 @@ programs: parameter_prefix: gov.states.md.dhs.meap verified_years: "2025-2027" notes: FY25-FY27 regular heating only, with the fuel tables, the Garrett County multiplier and the subsidized and nominal levels. The SNAP nominal payment, cooling, EUSP, arrearage, crisis and equipment benefits are out of scope. + - state: MO + status: partial + name: Missouri LIHEAP + full_name: Missouri Low Income Home Energy Assistance Program + variable: mo_liheap + parameter_prefix: gov.states.mo.dss.liheap + verified_years: "2026-2027" + notes: FY2026-FY2027 regular Energy Assistance only, including the heat-in-rent payment. Crisis (ECIP), cooling and weatherization assistance are out of scope. - state: MS status: partial name: Mississippi LIHEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.yaml new file mode 100644 index 00000000000..50e87a60c05 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.yaml @@ -0,0 +1,263 @@ +# Missouri LIHEAP Energy Assistance eligibility: at least one qualifying +# member; countable income at or below the 60% SMI limit, or below the +# federal 110% poverty floor; cash resources of at most $3,000; heating costs +# paid through the household's own fuel bill or through unsubsidized rent +# that includes heat; and a heating fuel other than coal. + +- name: Case 1, countable income exactly at the size one limit is eligible. + period: 2026 + input: + people: + person1: + age: 40 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_100 + mo_liheap_countable_income: 34_080 + households: + household: + members: [person1] + state_code: MO + output: + # Boundary case: FFY2026 size 1 limit 2,840 x 12 = 34,080. + mo_liheap_eligible: true + +- name: Case 2, countable income one dollar above the size one limit is ineligible. + period: 2026 + input: + people: + person1: + age: 40 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_100 + mo_liheap_countable_income: 34_081 + households: + household: + members: [person1] + state_code: MO + output: + # Boundary case: 34,081 > 34,080, and the 110% poverty floor for one + # person, 1.1 x 15,650 = 17,215, is far below the limit. + mo_liheap_eligible: false + +- name: Case 3, FFY2026 federal poverty floor admits a sixteen-person household above the state limit. + period: 2026 + input: + state_code: [MO, MO] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_800, 1_800] + mo_liheap_household_size: [16, 16] + mo_liheap_countable_income: [107_000, 107_965] + output: + # Size 16 limit: 8,847 x 12 = 106,164. Floor with the 2025 guidelines: + # 1.1 x (15,650 + 5,500 x 15) = 1.1 x 98,150 = 107,965. + # Unit 1: 107,000 is above the limit but below the floor -> eligible. + # Unit 2 (boundary case): income exactly at the floor is not below it + # -> ineligible. + mo_liheap_eligible: [true, false] + +- name: Case 4, FFY2027 federal poverty floor uses the 2026 guidelines at size sixteen. + period: 2027 + input: + state_code: MO + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 2_400 + mo_liheap_household_size: 16 + mo_liheap_countable_income: 110_500 + output: + # Size 16 limit: 9,164 x 12 = 109,968. Floor: 1.1 x (15,960 + 5,680 x 15) + # = 1.1 x 101,160 = 111,276. 110,500 is between them -> eligible. + mo_liheap_eligible: true + +- name: Case 5, cash assets exactly at the 3,000 resource limit are eligible. + period: 2026 + input: + people: + person1: + age: 58 + bank_account_assets: 3_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_100 + mo_liheap_countable_income: 24_000 + households: + household: + members: [person1] + state_code: MO + output: + # Boundary case: 3,000 <= 3,000. + mo_liheap_eligible: true + +- name: Case 6, cash assets of 3,001 exceed the resource limit. + period: 2026 + input: + people: + person1: + age: 58 + bank_account_assets: 3_001 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_100 + mo_liheap_countable_income: 24_000 + households: + household: + members: [person1] + state_code: MO + output: + # Boundary case: 3,001 > 3,000. + mo_liheap_eligible: false + +- name: Case 7, household with no citizen or qualified noncitizen is ineligible. + period: 2026 + input: + people: + person1: + age: 30 + immigration_status: UNDOCUMENTED + employment_income: 31_200 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + households: + household: + members: [person1] + state_code: MO + output: + # Household size 0, so the household fails the size test even though the + # member's countable income (31,200 x 0.8 = 24,960) is below the size one + # limit. + mo_liheap_eligible: false + +- name: Case 8, housing assistance recipient with heat included in the rent is ineligible. + period: 2026 + input: + people: + person1: + age: 33 + pre_subsidy_rent: 9_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + heat_expense_included_in_rent: true + receives_housing_assistance: true + mo_liheap_countable_income: 14_000 + households: + household: + members: [person1] + state_code: MO + output: + mo_liheap_eligible: false + +- name: Case 9, public housing tenant with heat included in the rent is ineligible. + period: 2026 + input: + people: + person1: + age: 33 + pre_subsidy_rent: 6_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + heat_expense_included_in_rent: true + mo_liheap_countable_income: 14_000 + households: + household: + members: [person1] + state_code: MO + is_in_public_housing: true + output: + mo_liheap_eligible: false + +- name: Case 10, housing assistance recipient paying its own electric heating bill is eligible. + period: 2026 + input: + people: + person1: + age: 33 + pre_subsidy_rent: 6_000 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + pre_subsidy_electricity_expense: 1_400 + receives_housing_assistance: true + mo_liheap_countable_income: 14_000 + households: + household: + members: [person1] + state_code: MO + output: + mo_liheap_eligible: true + +- name: Case 11, home with no heating has no heating cost and is ineligible. + period: 2026 + input: + people: + person1: + age: 45 + spm_units: + spm_unit: + members: [person1] + heating_type: NONE + mo_liheap_countable_income: 18_000 + households: + household: + members: [person1] + state_code: MO + output: + mo_liheap_eligible: false + +- name: Case 12, household that heats with coal is denied. + period: 2026 + input: + people: + person1: + age: 61 + spm_units: + spm_unit: + members: [person1] + heating_type: COAL + coal_expense: 800 + mo_liheap_countable_income: 18_000 + households: + household: + members: [person1] + state_code: MO + output: + # The coal bill is a heating cost, but manual denial code O ("Heats with + # Coal") applies. + mo_liheap_eligible: false + +- name: Case 13, household heating with another fuel is eligible. + period: 2026 + input: + people: + person1: + age: 61 + spm_units: + spm_unit: + members: [person1] + heating_type: OTHER + other_heating_fuel_expense: 600 + mo_liheap_countable_income: 18_000 + households: + household: + members: [person1] + state_code: MO + output: + # Eligible; the payment schedule has no row for other fuels (see + # mo_liheap.yaml). + mo_liheap_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.yaml new file mode 100644 index 00000000000..80492c73a60 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.yaml @@ -0,0 +1,37 @@ +# Missouri LIHEAP annual income limit: 12 x the published monthly 60% state +# median income limit, which equals the HHS LIHEAP 60% SMI amount for the +# household size divided by 12 and rounded to the nearest dollar. +# FFY2026 (model year 2026) uses Missouri SMI 109,229: floor(109,229 x 0.6) = +# 65,537 for four people. FFY2027 (model year 2027) uses SMI 113,137: +# floor(113,137 x 0.6) = 67,882. + +- name: Case 1, FFY2026 published limits for household sizes 1, 4, 16 and 20. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [MO, MO, MO, MO] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + mo_liheap_household_size: [1, 4, 16, 20] + output: + # Size 1: floor(65,537 x 0.52) = 34,079; 34,079 / 12 = 2,839.92 -> 2,840 + # monthly (Appendix K) -> 34,080. + # Size 4: 65,537 / 12 = 5,461.42 -> 5,461 -> 65,532. + # Size 16: floor(65,537 x 1.62) = 106,169; / 12 = 8,847.42 -> 8,847 + # -> 106,164. + # Size 20: floor(65,537 x 1.74) = 114,034; / 12 = 9,502.83 -> 9,503 + # -> 114,036. + mo_liheap_income_limit: [34_080, 65_532, 106_164, 114_036] + +- name: Case 2, FFY2027 published limits for household sizes 1 and 10. + period: 2027 + absolute_error_margin: 0.01 + input: + state_code: [MO, MO] + heating_type: [ELECTRICITY, ELECTRICITY] + mo_liheap_household_size: [1, 10] + output: + # Size 1: floor(67,882 x 0.52) = 35,298; 35,298 / 12 = 2,941.50 -> 2,942 + # monthly (MO 886-4576) -> 35,304. + # Size 10: floor(67,882 x 1.44) = 97,750; / 12 = 8,145.83 -> 8,146 + # -> 97,752. + mo_liheap_income_limit: [35_304, 97_752] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml new file mode 100644 index 00000000000..5db7f57d810 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml @@ -0,0 +1,124 @@ +# Missouri LIHEAP countable household income: all members' countable income +# plus Missouri TANF, less child support paid by any member and the medical +# deduction, floored at zero. + +- name: Case 1, Missouri TANF counts as income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 27 + child_support_received: 2_400 + person2: + age: 6 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + mo_tanf: 3_504 + households: + household: + members: [person1, person2, person3] + state_code: MO + output: + # TANF of 292 a month = 3,504 + child support received 2,400 = 5,904. + mo_liheap_countable_income: 5_904 + +- name: Case 2, child support paid outside the household is deducted. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 31_200 + child_support_expense: 4_800 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + households: + household: + members: [person1] + state_code: MO + output: + # 31,200 x 0.8 = 24,960 - child support paid of 400 a month (4,800) + # = 20,160. + mo_liheap_countable_income: 20_160 + +- name: Case 3, medical deduction for a retiree is subtracted. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 68 + social_security_retirement: 23_400 + medicare_part_b_premium: 2_434.80 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + households: + household: + members: [person1] + state_code: MO + output: + # 23,400 - 2,434.80 = 20,965.20 - medical deduction 1,200 = 19,765.20. + mo_liheap_countable_income: 19_765.20 + +- name: Case 4, child support paid above countable earnings floors income at zero. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 24 + employment_income: 6_240 + child_support_expense: 6_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + households: + household: + members: [person1] + state_code: MO + output: + # 8 hours a week at $15.00 = 6,240 x 0.8 = 4,992; + # max(4,992 - 6,000, 0) = 0. + mo_liheap_countable_income: 0 + +- name: Case 5, an undocumented member is left out of the household size but that member's earnings count and child support paid is deducted. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 34 + immigration_status: CITIZEN + employment_income: 31_200 + person2: + age: 32 + immigration_status: UNDOCUMENTED + employment_income: 31_200 + child_support_expense: 3_600 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + # The undocumented member is left out of the household size (2 - 1 = 1) + # but the 2025 manual counts that member's income: 31,200 x 0.8 = 24,960 + # for each member = 49,920. The 300 a month (3,600) of child support that + # member pays to someone outside the household is deducted: + # 49,920 - 3,600 = 46,320. + mo_liheap_household_size: 1 + mo_liheap_countable_income: 46_320 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml new file mode 100644 index 00000000000..0e387add86b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml @@ -0,0 +1,268 @@ +# Missouri LIHEAP countable income per member: earned income less the 20% +# earned income deduction (each earned source floored at zero; none for +# members under 18), plus unearned income (without short- and long-term +# disability payments for members under 18), plus Social Security net of the +# Medicare Part B premium. Members left out of the household size as +# non-citizens have their income counted. + +- name: Case 1, full-time minimum wage earnings after the 20 percent deduction. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 31_200 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + households: + household: + members: [person1] + state_code: MO + output: + # $15.00 an hour x 2,080 hours = 31,200 x (1 - 0.2) = 24,960. + mo_liheap_countable_income_person: [24_960] + +- name: Case 2, a seventeen-year-old's wages are excluded but survivor benefits count. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 31_200 + person2: + age: 17 + employment_income: 6_000 + social_security_survivors: 9_600 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + # Parent: 31,200 x 0.8 = 24,960. Teenager: wages excluded under age 18; + # survivor benefits of 800 a month = 9,600 count (no Part B premium). + mo_liheap_countable_income_person: [24_960, 9_600] + +- name: Case 3, an eighteen-year-old in high school has wages counted. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 46 + person2: + age: 18 + is_in_secondary_school: true + is_tax_unit_dependent: true + employment_income: 7_800 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + households: + household: + members: [person1, person2] + state_code: MO + output: + # A high school senior and tax dependent working 10 hours a week at + # $15.00: 7,800. The 2025 manual excludes earnings only under age 18 + # (boundary case: 18 is not under 18) and no longer excludes students: + # 7,800 x 0.8 = 6,240. + mo_liheap_countable_income_person: [0, 6_240] + +- name: Case 4, self-employment counts after the deduction and a farm loss is floored at zero. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + self_employment_income: 24_000 + farm_operations_income: -3_000 + spm_units: + spm_unit: + members: [person1] + heating_type: PROPANE + households: + household: + members: [person1] + state_code: MO + output: + # Each earned source is floored: max(24,000, 0) + max(-3,000, 0) = 24,000; + # 24,000 x 0.8 = 19,200. Netting the loss would give 21,000 x 0.8 = 16,800. + mo_liheap_countable_income_person: [19_200] + +- name: Case 5, Social Security counts net of the Medicare Part B premium. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + social_security_retirement: 23_400 + medicare_part_b_premium: 2_434.80 + person2: + age: 66 + social_security_retirement: 1_800 + medicare_part_b_premium: 2_434.80 + taxable_pension_income: 6_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + # 2026 Part B premium 202.90 x 12 = 2,434.80. + # Person 1: 1,950 a month = 23,400 - 2,434.80 = 20,965.20. + # Person 2: max(1,800 - 2,434.80, 0) = 0, plus a 500 a month pension + # of 6,000 = 6,000. + mo_liheap_countable_income_person: [20_965.20, 6_000] + +- name: Case 6, unearned sources count in full and interest is excluded. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + unemployment_compensation: 6_000 + child_support_received: 4_800 + financial_assistance: 1_200 + taxable_interest_income: 300 + person2: + age: 41 + military_retirement_pay: 24_000 + veterans_benefits: 6_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + # Person 1: unemployment 6,000 + child support 4,800 + money from family + # 1,200 = 12,000; interest of 300 is not counted. + # Person 2: military retirement 24,000 + VA benefits 6,000 = 30,000. + mo_liheap_countable_income_person: [12_000, 30_000] + +- name: Case 7, monthly SSI payments count as their annual total. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + is_disabled: true + ssi: 11_928 + spm_units: + spm_unit: + members: [person1] + heating_type: ELECTRICITY + households: + household: + members: [person1] + state_code: MO + output: + # 994 a month x 12 = 11,928. + mo_liheap_countable_income_person: [11_928] + +- name: Case 8, an undocumented member's earnings count. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 34 + immigration_status: CITIZEN + employment_income: 31_200 + person2: + age: 32 + immigration_status: UNDOCUMENTED + employment_income: 31_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + # Both: 31,200 x 0.8 = 24,960. The 2025 manual counts the income of a + # member left out of the household as a non-citizen. + mo_liheap_countable_income_person: [24_960, 24_960] + +- name: Case 9, earnings of a parent attending GED classes count. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 25 + is_in_secondary_school: true + employment_income_before_lsr: 58_240 + person2: + age: 6 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_100 + households: + household: + members: [person1, person2] + state_code: MO + output: + # The parent is 25, so the earnings count whether or not the parent + # attends GED classes. + # $28.00 an hour x 2,080 hours = 58,240 x (1 - 0.2) = 46,592. + # Missouri TANF: 58,240 / 12 = 4,853.33 a month, above the gross limit + # of 678 x 1.85 = 1,254.30 for two, so TANF is 0. + # Size 2 limit (FFY2026): 3,714 x 12 = 44,568. 46,592 > 44,568, and the + # 110% poverty floor 1.1 x (15,650 + 5,500) = 23,265 does not bind. + mo_liheap_countable_income_person: [46_592, 0] + mo_tanf: 0 + mo_liheap_countable_income: 46_592 + mo_liheap_income_limit: 44_568 + mo_liheap_eligible: false + mo_liheap: 0 + +- name: Case 10, a minor's disability payments are excluded while the minor's Social Security counts. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 44 + disability_benefits: 18_000 + person2: + age: 17 + disability_benefits: 1_440 + social_security_survivors: 9_600 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + # Parent: private long-term disability of 1,500 a month = 18,000 counts. + # Teenager: short-term disability from a part-time job (60% of 300 a week + # for 8 weeks = 1,440) is excluded under age 18; the Social Security + # child's survivor benefit of 800 a month = 9,600 counts as SSA income + # (no Part B premium). + mo_liheap_countable_income_person: [18_000, 9_600] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.yaml new file mode 100644 index 00000000000..c5b2e1622a7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.yaml @@ -0,0 +1,235 @@ +# Missouri LIHEAP medical deduction: $100 a month ($1,200 a year), once per +# household, when the applicant or spouse (modeled as a tax-unit head or +# spouse who is a citizen or qualified noncitizen) is 65 or older, or is +# disabled or blind and receives SSI, Social Security disability, dependent +# or survivor benefits, veterans or railroad benefits, Medicaid or a Missouri +# state supplementary payment. + +- name: Case 1, applicant who just turned 65 qualifies. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MO + output: + # Boundary case: 65 >= 65 -> 100 x 12 = 1,200. + mo_liheap_medical_deduction: 1_200 + +- name: Case 2, applicant aged 64 without a disability does not qualify. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 64 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MO + output: + mo_liheap_medical_deduction: 0 + +- name: Case 3, disabled spouse receiving SSI qualifies the household. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 52 + person2: + age: 48 + is_disabled: true + ssi: 11_928 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: ELECTRICITY + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MO + output: + mo_liheap_medical_deduction: 1_200 + +- name: Case 4, disabled applicant with only private disability insurance does not qualify. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_disabled: true + disability_benefits: 18_000 + ssi: 0 + social_security_disability: 0 + medicaid: 0 + mo_ssp: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MO + output: + # Private long-term disability is not a listed benefit, and no listed + # benefit is received. + mo_liheap_medical_deduction: 0 + +- name: Case 5, blind applicant receiving Social Security disability qualifies. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 52 + is_blind: true + social_security_disability: 18_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MO + output: + mo_liheap_medical_deduction: 1_200 + +- name: Case 6, elderly grandparent who is a dependent does not qualify the household. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + person2: + age: 43 + person3: + age: 74 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MO + output: + # The 74-year-old is neither the applicant nor the spouse. + mo_liheap_medical_deduction: 0 + +- name: Case 7, elderly couple receives a single deduction. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + person2: + age: 67 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: PROPANE + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MO + output: + # One deduction per household: 1,200, not 2,400. + mo_liheap_medical_deduction: 1_200 + +- name: Case 8, elderly undocumented spouse does not qualify the household. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + immigration_status: CITIZEN + person2: + age: 67 + immigration_status: UNDOCUMENTED + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MO + output: + # The 67-year-old is undocumented and left out of the household count; + # the 2025 manual does not say that such a spouse qualifies the + # household, and the 60-year-old citizen is neither elderly nor disabled. + mo_liheap_medical_deduction: 0 + +- name: Case 9, disabled applicant whose only listed benefit is Medicaid qualifies. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + is_disabled: true + medicaid: 21_297 + ssi: 0 + social_security_disability: 0 + mo_ssp: 0 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MO + output: + # MO HealthNet coverage valued at the model's per-capita Medicaid cost + # for the aged and disabled group (21,297); no SSI, Social Security + # disability or state supplementary payment. Medicaid is a listed + # benefit: 100 x 12 = 1,200. + mo_liheap_medical_deduction: 1_200 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/integration.yaml new file mode 100644 index 00000000000..4212cb070f3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/integration.yaml @@ -0,0 +1,130 @@ +# Missouri LIHEAP Energy Assistance end to end, from household inputs to the +# payment. FFY2026 is model year 2026 and FFY2027 is model year 2027. + +- name: Case 1, FFY2026 working family of four heating with natural gas. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + employment_income_before_lsr: 31_200 + bank_account_assets: 1_200 + person2: + age: 36 + employment_income_before_lsr: 18_720 + person3: + age: 9 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + heating_type: NATURAL_GAS + gas_expense: 1_100 + households: + household: + members: [person1, person2, person3, person4] + state_code: MO + output: + # Full time at $15.00: 31,200 x 0.8 = 24,960. + # 24 hours a week at $15.00: 18,720 x 0.8 = 14,976. + # Missouri TANF: (31,200 + 18,720) / 12 = 4,160 a month, above the gross + # limit of 990 x 1.85 = 1,831.50 for four, so TANF is 0. + # Total 39,936; no medical deduction. + # Size 4 limit: 5,461 x 12 = 65,532. Assets 1,200 <= 3,000. + # Natural gas pays 326. + mo_liheap_household_size: 4 + mo_liheap_countable_income_person: [24_960, 14_976, 0, 0] + mo_tanf: 0 + mo_liheap_medical_deduction: 0 + mo_liheap_countable_income: 39_936 + mo_liheap_income_limit: 65_532 + has_heating_expense: true + mo_liheap_eligible: true + mo_liheap: 326 + +- name: Case 2, FFY2026 retired couple heating with tank propane. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + social_security_retirement: 25_200 + taxable_pension_income: 4_800 + medicare_part_b_premium: 2_434.80 + bank_account_assets: 2_500 + person2: + age: 69 + social_security_retirement: 13_200 + medicare_part_b_premium: 2_434.80 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: PROPANE + bottled_gas_expense: 1_800 + households: + household: + members: [person1, person2] + state_code: MO + output: + # 2026 Part B premium 202.90 x 12 = 2,434.80 each. + # Person 1: 2,100 a month = 25,200 - 2,434.80 + pension 4,800 = 27,565.20. + # Person 2: 1,100 a month = 13,200 - 2,434.80 = 10,765.20. + # Total 38,330.40 - one medical deduction 1,200 = 37,130.40. + # Size 2 limit: 3,714 x 12 = 44,568. Assets 2,500 <= 3,000. + # Tank propane pays 495. + mo_liheap_household_size: 2 + mo_liheap_countable_income_person: [27_565.20, 10_765.20] + mo_liheap_medical_deduction: 1_200 + mo_liheap_countable_income: 37_130.40 + mo_liheap_income_limit: 44_568 + mo_liheap_eligible: true + mo_liheap: 495 + +- name: Case 3, FFY2027 mixed-status renter family with heat included in the rent. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + employment_income_before_lsr: 31_200 + pre_subsidy_rent: 10_200 + person2: + age: 29 + immigration_status: UNDOCUMENTED + employment_income_before_lsr: 26_000 + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + heat_expense_included_in_rent: true + households: + household: + members: [person1, person2, person3] + state_code: MO + output: + # The undocumented parent is left out of the household size (3 - 1 = 2), + # but the 2025 manual counts that parent's income. + # Citizen parent: 31,200 x 0.8 = 24,960. + # Undocumented parent: $12.50 an hour x 2,080 hours = 26,000 x 0.8 + # = 20,800. Total 45,760; no medical deduction or child support paid. + # Missouri TANF: 31,200 / 12 = 2,600 a month from the citizen parent alone + # is above the gross limit even for three (846 x 1.85 = 1,565.10), so TANF + # is 0. + # Size 2 limit (FFY2027): 3,847 x 12 = 46,164; 45,760 <= 46,164. + # No own fuel bill, but heat is in unsubsidized rent. + # Rent 850 a month = 10,200 x 0.08 = 816, capped at natural gas 326. + mo_liheap_household_size: 2 + mo_liheap_countable_income_person: [24_960, 20_800, 0] + mo_liheap_countable_income: 45_760 + mo_liheap_income_limit: 46_164 + has_heating_expense: false + mo_liheap_eligible: true + mo_liheap: 326 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml new file mode 100644 index 00000000000..0b97f29349c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml @@ -0,0 +1,145 @@ +# Missouri LIHEAP Energy Assistance: a one-time payment by primary heating +# fuel (FFY2026 Appendix K; FFY2027 application MO 886-4576). A renter whose +# heat is included in the rent receives 8% of annual rent, capped at the +# amount for the household's fuel (13 CSR 40-19.020(13)). Zero when +# ineligible. + +- name: Case 1, payment for every heating fuel. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [MO, MO, MO, MO, MO, MO, MO, MO, MO, MO, MO] + heating_type: [NATURAL_GAS, PROPANE, ELECTRICITY, FUEL_OIL, WOOD, KEROSENE, SOLAR, OTHER, UNSPECIFIED, NONE, COAL] + has_heating_expense: [true, true, true, true, true, true, true, true, true, false, true] + mo_liheap_countable_income: [18_000, 18_000, 18_000, 18_000, 18_000, 18_000, 18_000, 18_000, 18_000, 18_000, 18_000] + output: + # Natural gas 326, tank propane 495, electric 318, fuel oil 326, wood 219, + # kerosene 153; solar is paid on the electric account (318). Other fuels + # have no schedule row and an unspecified fuel matches no row, so both are + # eligible for 0. A home with no heating has no heating cost, and coal is + # denied (manual denial code O). + mo_liheap_eligible: [true, true, true, true, true, true, true, true, true, false, false] + mo_liheap: [326, 495, 318, 326, 219, 153, 318, 0, 0, 0, 0] + +- name: Case 2, renter share of rent split between two partners is below the propane amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 27 + pre_subsidy_rent: 3_000 + person2: + age: 26 + pre_subsidy_rent: 3_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: PROPANE + heat_expense_included_in_rent: true + mo_liheap_countable_income: 20_000 + households: + household: + members: [person1, person2] + state_code: MO + output: + # Annual rent 3,000 + 3,000 = 6,000 ($500 a month); + # 6,000 x 0.08 = 480 < 495 -> 480. + mo_liheap: 480 + +- name: Case 3, renter share of rent above the natural gas amount is capped. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 33 + pre_subsidy_rent: 9_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + heat_expense_included_in_rent: true + mo_liheap_countable_income: 22_000 + households: + household: + members: [person1] + state_code: MO + output: + # 750 x 12 = 9,000 x 0.08 = 720 > 326 -> 326. + mo_liheap: 326 + +- name: Case 4, renter with heat in the rent and an unspecified fuel receives nothing. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 33 + pre_subsidy_rent: 9_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + heat_expense_included_in_rent: true + mo_liheap_countable_income: 22_000 + households: + household: + members: [person1] + state_code: MO + output: + # Eligible, but the cap is the amount for an unspecified fuel: + # min(9,000 x 0.08 = 720, 0) = 0. + mo_liheap_eligible: true + mo_liheap: 0 + +- name: Case 5, Kansas household is outside the Missouri program. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 20_800 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_000 + households: + household: + members: [person1] + state_code: KS + output: + mo_liheap: 0 + +- name: Case 6, FFY2027 single parent heating with kerosene, teenager's wages excluded. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 41 + employment_income_before_lsr: 41_600 + bank_account_assets: 900 + person2: + age: 16 + employment_income_before_lsr: 5_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: KEROSENE + fuel_oil_expense: 1_500 + households: + household: + members: [person1, person2] + state_code: MO + output: + # Parent: $20 an hour x 2,080 hours = 41,600 x (1 - 0.2) = 33,280. + # The 16-year-old's 5,200 is excluded. Size 2 limit (FFY2027): + # 3,847 x 12 = 46,164. Counting the teenager's wages without the 20% + # deduction (46,800) would exceed it. Kerosene pays 153. + mo_liheap_countable_income: 33_280 + mo_liheap_income_limit: 46_164 + mo_liheap_eligible: true + mo_liheap: 153 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap_household_size.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap_household_size.yaml new file mode 100644 index 00000000000..3266ae322ed --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap_household_size.yaml @@ -0,0 +1,99 @@ +# Missouri LIHEAP household size: SPM unit members who are U.S. citizens or +# qualified noncitizens. Other members are left out of the household count +# (13 CSR 40-19.020(6)(A) and (8)(A)). + +- name: Case 1, family of four citizens counts four. + period: 2026 + input: + people: + person1: + age: 36 + person2: + age: 34 + person3: + age: 9 + person4: + age: 6 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2, person3, person4] + state_code: MO + output: + mo_liheap_household_size: 4 + +- name: Case 2, lawful permanent resident and refugee parents count with their citizen child. + period: 2026 + input: + people: + person1: + age: 44 + immigration_status: LEGAL_PERMANENT_RESIDENT + person2: + age: 40 + immigration_status: REFUGEE + person3: + age: 8 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: ELECTRICITY + households: + household: + members: [person1, person2, person3] + state_code: MO + output: + mo_liheap_household_size: 3 + +- name: Case 3, undocumented parent is left out of the household count. + period: 2026 + input: + people: + person1: + age: 35 + immigration_status: CITIZEN + person2: + age: 33 + immigration_status: UNDOCUMENTED + person3: + age: 10 + immigration_status: CITIZEN + person4: + age: 7 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2, person3, person4] + state_code: MO + output: + # 4 members - 1 undocumented = 3. + mo_liheap_household_size: 3 + +- name: Case 4, household with no citizen or qualified noncitizen counts zero. + period: 2026 + input: + people: + person1: + age: 30 + immigration_status: UNDOCUMENTED + person2: + age: 28 + immigration_status: UNDOCUMENTED + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + mo_liheap_household_size: 0 diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py b/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py new file mode 100644 index 00000000000..8bf0cb2fabd --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py @@ -0,0 +1,52 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class mo_liheap_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Eligible for Missouri LIHEAP Energy Assistance" + documentation = "A Missouri household with at least one citizen or legal immigrant member that meets the income limit or the federal 110 percent poverty floor, has resources within the resource limit, pays for heat either through its own fuel bill or through unsubsidized rent that includes heat, and does not heat with coal. Not modeled: the exclusions in 13 CSR 40-19.020(7)(B), (C) and (E)-(H) (nursing or boarding homes, hotels and shelters, Department of Mental Health transitional living, fuel credit balances over $500, self-cut wood and shared-meter dwellings) and the limit of one Energy Assistance payment per household per year." + reference = ( + # PDF pages 2-3 + "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8", + # PDF pages 40, 42-43, 122 + "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=40", + "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", + ) + defined_for = StateCode.MO + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.mo.dss.liheap.eligibility + size = spm_unit("mo_liheap_household_size", period) + income = spm_unit("mo_liheap_countable_income", period) + limit = spm_unit("mo_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 16 in FFY2026 and FFY2027. + 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 * parameters(period).gov.hhs.liheap.fpg_floor, 2) + income_eligible = (income <= limit) | (income < floor) + resource_eligible = spm_unit("spm_unit_cash_assets", period) <= p.resource_limit + # 13 CSR 40-19.020(7)(D): subsidized housing is ineligible unless the + # household pays an energy supplier or is billed for heating costs. + subsidized = spm_unit("receives_housing_assistance", period) | ( + spm_unit.household("is_in_public_housing", period) + ) + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + pays_for_heat = spm_unit("has_heating_expense", period) | ( + heat_in_rent & ~subsidized + ) + # 2025 manual Appendix E, denial code O: "Heats with Coal". + heating_type = spm_unit("heating_type", period) + heats_with_coal = heating_type == heating_type.possible_values.COAL + return ( + (size > 0) + & income_eligible + & resource_eligible + & pays_for_heat + & ~heats_with_coal + ) diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.py b/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.py new file mode 100644 index 00000000000..691d633c5f9 --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import liheap_smi_limit + + +class mo_liheap_income_limit(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Missouri LIHEAP annual income limit" + documentation = "Twelve times Missouri's monthly income limit, a share of state median income. The HHS LIHEAP limit for the household size, divided by twelve and rounded to the nearest dollar, reproduces the published monthly limits for FFY2026 (sizes 1-20) and FFY2027 (sizes 1-10). For households above ten members, the FFY2027 application adds a rounded $170 a month per additional member; that shorthand runs $1 to $2 a month above the 60% SMI amount for twelve to fifteen members (the federal poverty floor governs from sixteen), and the model keeps the 60% SMI amount of the plan." + reference = ( + "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8", + "https://liheapch.acf.gov/docs/2026/benefits-matricies/MO_BenefitMatrix_2026.docx", + "https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=1", + # DSS draft FFY2027 plan (report status "Saved -- with Errors"). + "https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=8", + ) + defined_for = StateCode.MO + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.mo.dss.liheap.eligibility + size = spm_unit("mo_liheap_household_size", period) + state = spm_unit.household("state_code_str", period) + annual_limit = liheap_smi_limit(size, state, p.smi_rate, period, parameters) + monthly_limit = np.floor(annual_limit / MONTHS_IN_YEAR + 0.5) + return monthly_limit * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.py b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.py new file mode 100644 index 00000000000..88046f23d18 --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class mo_liheap_countable_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Missouri LIHEAP countable income" + documentation = "Countable income of all members, including members left out of the household size as non-citizens, plus Missouri TANF, less court-ordered child support members pay to someone outside the household and the medical deduction. The child support input does not identify court orders, so all child support paid is deducted." + reference = ( + # PDF pages 5-7 + "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=5", + "https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=5", + # PDF pages 2-3 + "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + # PDF pages 36, 42-43 + "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36", + ) + defined_for = StateCode.MO + + def formula(spm_unit, period, parameters): + income = add(spm_unit, period, ["mo_liheap_countable_income_person", "mo_tanf"]) + # The 2025 manual deducts child support "paid by any household member + # to someone not included in the LIHEAP household" (page 36) and calls + # members left out as non-citizens "ineligible household members" + # (page 42), so their child support paid is deducted like that of + # other members. + deductions = add( + spm_unit, + period, + ["child_support_expense", "mo_liheap_medical_deduction"], + ) + return max_(income - deductions, 0) diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py new file mode 100644 index 00000000000..1c2c1048a09 --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * + + +class mo_liheap_countable_income_person(Variable): + value_type = float + entity = Person + definition_period = YEAR + unit = USD + label = "Missouri LIHEAP countable income per person" + documentation = "Gross income Missouri counts for a household member, including a member left out of the household size as a non-citizen: earned income after the earned income deduction, unearned income, and Social Security net of the Medicare Part B premium. Each earned source is floored at zero, so business and farm losses do not offset other income. Members under 18 have their earned income and their non-Social Security disability payments excluded; their Social Security and SSI count. Not modeled: a Part B premium paid by a member without Social Security (for example a Railroad Retirement beneficiary) and Medicare Part D premiums. Annual income stands in for twelve times the income of the month before application." + reference = ( + # PDF pages 5-7 + "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=5", + # PDF pages 4-5 + "https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=4", + # DSS draft FFY2027 plan (report status "Saved -- with Errors"). + # PDF pages 5-7 + "https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=5", + # PDF pages 32, 36, 38, 42-43 + "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=32", + ) + defined_for = StateCode.MO + + def formula(person, period, parameters): + p = parameters(period).gov.states.mo.dss.liheap.income + earned = sum(max_(person(source, period), 0) for source in p.earned_sources) + countable_earned = earned * (1 - p.earned_income_deduction_rate) + # The 2025 manual (Earnings of Children) leaves out the earned income + # and the disability income of members under 18 but counts their SSA + # income, read here as Social Security and SSI. + adult_income = countable_earned + add(person, period, p.adult_unearned_sources) + adult = person("age", period) >= p.adult_age + unearned = add(person, period, p.unearned_sources) + # Plan section 1.9 counts Social Security excluding the Medicare + # deduction. + social_security = max_( + person("social_security", period) + - person("medicare_part_b_premium", period), + 0, + ) + return unearned + social_security + where(adult, adult_income, 0) diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.py b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.py new file mode 100644 index 00000000000..2b4a77e0284 --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.py @@ -0,0 +1,39 @@ +from policyengine_us.model_api import * + + +class mo_liheap_medical_deduction(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Missouri LIHEAP medical deduction" + documentation = "Missouri's monthly medical deduction, annualized and given once per household when the applicant or spouse is elderly or disabled. Disabled means totally and permanently disabled or blind and receiving a listed disability benefit. Tax-unit heads and spouses who are citizens or legal immigrants stand in for the applicant and spouse." + reference = ( + # PDF pages 2-3 + "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + # PDF pages 36, 48 + "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36", + ) + defined_for = StateCode.MO + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.mo.dss.liheap.income + person = spm_unit.members + applicant_or_spouse = person("is_tax_unit_head", period) | person( + "is_tax_unit_spouse", period + ) + # The 2025 manual (page 36) is silent on a spouse left out of the + # household as a non-citizen, and a non-citizen applicant makes the case + # ineligible (page 43); the model keeps the citizenship requirement. + qualified = person("is_citizen_or_legal_immigrant", period) + elderly = person("age", period) >= p.elderly_age + disabled_or_blind = person("is_disabled", period) | person("is_blind", period) + receives_disability_benefit = ( + add(person, period, p.disability_benefit_sources) > 0 + ) + qualifies = ( + applicant_or_spouse + & qualified + & (elderly | (disabled_or_blind & receives_disability_benefit)) + ) + return spm_unit.any(qualifies) * p.medical_deduction * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py b/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py new file mode 100644 index 00000000000..6b1380d189f --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class mo_liheap(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Missouri LIHEAP Energy Assistance" + documentation = "Missouri's one-time regular heating Energy Assistance payment: the amount for the household's primary heating fuel, or for a renter household whose heat is included in the rent, the rent share of annual rent up to that amount. The regular monthly rental charge is pre_subsidy_rent, since only unsubsidized renters with heat in rent are eligible. Verified for FY2026-FY2027; earlier years use model parameter backfilling and are unverified historical estimates. Energy Crisis Intervention Program (ECIP) crisis payments are excluded." + reference = ( + # PDF pages 2-4 + "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=9", + "https://liheapch.acf.gov/docs/2026/benefits-matricies/MO_BenefitMatrix_2026.docx", + "https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=1", + # PDF pages 62-63, 129 + "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=62", + ) + defined_for = "mo_liheap_eligible" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.mo.dss.liheap + heating_type = spm_unit("heating_type", period) + fuel_amount = p.amount[heating_type] + annual_rent = add(spm_unit, period, ["pre_subsidy_rent"]) + renter_amount = min_(annual_rent * p.rent_share, fuel_amount) + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + return where(heat_in_rent, renter_amount, fuel_amount) diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py b/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py new file mode 100644 index 00000000000..aa118c64c4e --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class mo_liheap_household_size(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "Missouri LIHEAP household size" + documentation = "Number of SPM unit members who are U.S. citizens or legal immigrants. Missouri leaves members who are not citizens or legal permanent residents out of the household count but counts their income (mo_liheap_countable_income_person). The SPM unit approximates the household living in private quarters that purchases residential heat in common; roomers, boarders and live-in attendants have no inputs and are not excluded." + reference = ( + # PDF pages 2-3 + "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + # PDF pages 40-43 + "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=40", + ) + defined_for = StateCode.MO + + adds = ["is_citizen_or_legal_immigrant"] diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 7d8c41658c6..da2bc02907e 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -3210,6 +3210,76 @@ candidates: state: ruled note: 'Ruled in October 2026 to follow worksheets; the later statute-first rule requires a model change if this credit is outside the statutory exception. Code not yet on main: mo_federal_income_tax_deduction.' +- id: us-mo:liheap-110-percent-poverty-floor + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Can Missouri's printed 60% SMI limit exclude a large household whose income is below the federal 110% + poverty-guideline floor? + sources: + - kind: statute + citation: 42 U.S.C. 8624(b)(2)(B) + url: https://www.law.cornell.edu/uscode/text/42/8624 + - kind: plan + citation: Missouri FFY2026 LIHEAP State Plan, section 2.1, 60% SMI for all household sizes + url: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8 + - kind: guidance + citation: Missouri FFY26 Appendix K, Income Ranges and Benefit Amounts, 60% SMI monthly limits for sizes 1-20 + url: https://liheapch.acf.gov/docs/2026/benefits-matricies/MO_BenefitMatrix_2026.docx + readings: + statute: Income below 110% of the poverty guideline cannot by itself exclude the household. + other: The printed Missouri limits fall below that floor starting at household size 16 in FFY2026 and FFY2027. + example: In FFY2026, a 16-person household with $107,000 of countable income exceeds the $106,164 state limit + but is below the $107,965 floor and receives the $326 natural-gas Energy Assistance payment. + pe_us: + follows: statute + code: [] + prs: [] + state: unreviewed + note: 'The implementation applies the federal floor gov.hhs.liheap.fpg_floor with the poverty guidelines lagged + one year; no PR is open yet. Code not yet on main: mo_liheap_eligible.' +- id: us-mo:liheap-rule-income-ranges-and-payments + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Does Missouri Energy Assistance use the income ranges up to 135% of the poverty level and the tiered + payments in 13 CSR 40-19.020(14), or the 60% SMI limit and flat fuel amounts in the FFY2026-FFY2027 agency + documents? + sources: + - kind: regulation + citation: 13 CSR 40-19.020(6)(D) and (14), Payment Levels for Missouri (amended effective May 30, 2017) + url: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=4 + - kind: plan + citation: Missouri FFY2026 LIHEAP State Plan, sections 2.1, 2.5 and 2.6 + url: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8 + - kind: guidance + citation: Missouri FFY26 Appendix K, Income Ranges and Benefit Amounts + url: https://liheapch.acf.gov/docs/2026/benefits-matricies/MO_BenefitMatrix_2026.docx + - kind: manual + citation: Missouri LIHEAP Policy and Procedure Manual (October 2025), Appendix K + url: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=129 + - kind: form + citation: Missouri LIHEAP application MO 886-4576 (8-2026), Program Description + url: https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=1 + readings: + statute: No statute is supplied; the rule sets monthly income ranges A-F from 0 to 135% of the poverty level, + with natural gas paying $296 in range A down to $203 in range F. + other: The plan, Appendix K, manual and application set 60% SMI for every size and one amount per fuel, such as + $326 for natural gas. + example: In FFY2026, a family of four with $39,936 of countable income ($3,328 a month, 124% of the 2025 guideline) + that heats with natural gas receives $221 in the rule's range E and $326 under the agency documents. + pe_us: + follows: unknown + code: [] + prs: [] + state: unreviewed + note: 'PE-US follows the plan, Appendix K, manual and application; no FFY2026 or FFY2027 agency document uses the + 2017 rule table. The renter share follows 13 CSR 40-19.020(13) (8% of annual rent) over the 16% in the manual + and plans. Code not yet on main: mo_liheap_eligible, mo_liheap_income_limit and the mo_liheap amount parameters.' - id: us-mo:medicaid-published-dollar-limit-rounding program: medicaid years: From 566343d074aca4df943a2ff8e3a87d7782527620 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 23 Oct 2026 20:57:45 -0400 Subject: [PATCH 2/5] Sum Missouri LIHEAP earned income without built-in sum Co-Authored-By: Claude Opus 5.5 --- .../mo/dss/liheap/income/mo_liheap_countable_income_person.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py index 1c2c1048a09..055aabbc053 100644 --- a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py @@ -23,7 +23,9 @@ class mo_liheap_countable_income_person(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.mo.dss.liheap.income - earned = sum(max_(person(source, period), 0) for source in p.earned_sources) + earned = 0 + for source in p.earned_sources: + earned = earned + max_(person(source, period), 0) countable_earned = earned * (1 - p.earned_income_deduction_rate) # The 2025 manual (Earnings of Children) leaves out the earned income # and the disability income of members under 18 but counts their SSA From c7f6fcef6e14e870a16f8a56f3041cde57f783be Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 28 Oct 2026 20:10:31 -0400 Subject: [PATCH 3/5] Address review round 1 for Missouri 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 --- .../gov/states/mo/dss/liheap/amount.yaml | 9 +- .../liheap/eligibility/resource_limit.yaml | 2 +- .../income/disability_benefit_sources.yaml | 2 +- .../mo/dss/liheap/income/elderly_age.yaml | 2 +- .../dss/liheap/income/medical_deduction.yaml | 2 +- .../dss/liheap/income/unearned_sources.yaml | 14 +- .../gov/states/mo/dss/liheap/rent_share.yaml | 2 +- .../eligibility/mo_liheap_eligible.yaml | 6 +- .../income/mo_liheap_countable_income.yaml | 63 +++++++- .../mo_liheap_countable_income_person.yaml | 112 ++++++++++++-- .../income/mo_liheap_medical_deduction.yaml | 25 +++ .../gov/states/mo/dss/liheap/mo_liheap.yaml | 115 +++++++++++++- .../liheap/eligibility/mo_liheap_eligible.py | 24 ++- .../income/mo_liheap_countable_income.py | 6 +- .../mo_liheap_countable_income_person.py | 27 ++-- .../income/mo_liheap_medical_deduction.py | 2 +- .../gov/states/mo/dss/liheap/mo_liheap.py | 30 +++- .../mo/dss/liheap/mo_liheap_household_size.py | 6 +- source_conflicts/candidates.yaml | 143 ++++++++++++++++-- 19 files changed, 516 insertions(+), 76 deletions(-) diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml index 1d980453293..c1ff5223ece 100644 --- a/policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml @@ -1,4 +1,4 @@ -description: Missouri provides this one-time Energy Assistance payment by primary heating fuel under the Low Income Home Energy Assistance Program. +description: Missouri provides this Energy Assistance amount for the selected fuel under the Low Income Home Energy Assistance Program. # The same amounts appear in the October 2025 manual (its Appendix K), the # FFY2026 Appendix K matrix and the FFY2027 application. 13 CSR 40-19.020(14) # bases payments on household size, income range and fuel source, using @@ -6,7 +6,8 @@ description: Missouri provides this one-time Energy Assistance payment by primar # that decline across income ranges from 0 to 135 percent of the poverty level. # The FFY2026 plan, the Appendix K matrix, the October 2025 manual and the # 8-2026 application set one amount per fuel for incomes up to 60 percent of -# state median income; the model applies those amounts. +# state median income; the model applies those amounts. The household selects +# the fuel to be paid, which may be its electric account (mo_liheap). NATURAL_GAS: 2023-10-01: 326 # Tank propane. The schedule also pays $177 for cylinder propane, which is not @@ -39,12 +40,12 @@ UNSPECIFIED: metadata: unit: currency-USD period: year - label: Missouri LIHEAP Energy Assistance amount by heating fuel + label: Missouri LIHEAP Energy Assistance amount by fuel breakdown: - heating_type reference: - title: "13 CSR 40-19.020(3)(A) and (4) #page 2-3" - href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + href: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 - title: Missouri LIHEAP FFY2026 State Plan, Sections 2.5 and 2.6 href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=9 - title: Missouri LIHEAP FFY2026 Appendix K, Income Ranges and Benefit Amounts diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/resource_limit.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/resource_limit.yaml index 2069a8d678d..67835da5ce9 100644 --- a/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/resource_limit.yaml +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/resource_limit.yaml @@ -12,7 +12,7 @@ metadata: label: Missouri LIHEAP resource limit reference: - title: "13 CSR 40-19.020(2)(N) and (6)(B) #page 2-3" - href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + href: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 - title: Missouri LIHEAP FFY2026 State Plan, Section 2.3 href: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8 - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Resources diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/disability_benefit_sources.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/disability_benefit_sources.yaml index aece6789354..d50830e3695 100644 --- a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/disability_benefit_sources.yaml +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/disability_benefit_sources.yaml @@ -30,6 +30,6 @@ metadata: label: Missouri LIHEAP disability benefit sources reference: - title: 13 CSR 40-19.020(2)(C) - href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + href: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 - title: "Missouri LIHEAP Policy and Procedure Manual (October 2025), Medical Deduction for Elderly-Disabled and Disability #page 36,48" href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/elderly_age.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/elderly_age.yaml index 45b26a8f352..10ce9cd9262 100644 --- a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/elderly_age.yaml +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/elderly_age.yaml @@ -8,6 +8,6 @@ metadata: label: Missouri LIHEAP elderly age reference: - title: 13 CSR 40-19.020(2)(D) - href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + href: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Medical Deduction for Elderly-Disabled href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/medical_deduction.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/medical_deduction.yaml index 207908e8844..2ac5c4021a6 100644 --- a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/medical_deduction.yaml +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/medical_deduction.yaml @@ -8,6 +8,6 @@ metadata: label: Missouri LIHEAP medical deduction reference: - title: "13 CSR 40-19.020(2)(C), (2)(D) and (6)(D)1 #page 2-3" - href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + href: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Medical Deduction for Elderly-Disabled href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml index 351df33790e..fc4f3b84b36 100644 --- a/policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml @@ -1,9 +1,11 @@ description: Missouri counts these unearned income sources under the Low Income Home Energy Assistance Program. -# Social Security counts net of the Medicare Part B premium in -# mo_liheap_countable_income_person, and Missouri TANF is added at the -# household level in mo_liheap_countable_income. Short- and long-term -# disability payments count only for members 18 or older -# (adult_unearned_sources). +# Each source is floored at zero, so a rental loss does not offset other +# income. Social Security is added, and the SMI (Medicare Part B) premium of +# a member receiving Social Security or Railroad Retirement benefits is +# deducted, in mo_liheap_countable_income_person; TANF (the take-up-gated +# tanf) is added at the household level in mo_liheap_countable_income. +# Short- and long-term disability payments count only for members 18 or +# older (adult_unearned_sources). # Interest and dividends are excluded (October 2025 manual, page 38), as are # capital gains, which page 38 treats as lump sums; page 32 lists the Form 1040 # capital gains line among self-employment documents. Foster care payments, @@ -48,6 +50,6 @@ metadata: - title: "Missouri LIHEAP Policy and Procedure Manual (October 2025), Unearned Income, Income Exclusions and Resources #page 32-34,38,40" href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=32 - title: 13 CSR 40-19.020(2)(N), Low-Income Home Energy Assistance Program - href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 + href: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2 - title: "Missouri DSS draft FFY2027 LIHEAP State Plan (report status Saved with Errors), Section 1.9 #page 5-7" href: https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml b/policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml index ae4e181ec0d..fa696ce8034 100644 --- a/policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml +++ b/policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml @@ -15,7 +15,7 @@ metadata: label: Missouri LIHEAP renter annual rent share reference: - title: 13 CSR 40-19.020(13) - href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=4 + href: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=4 - title: Missouri LIHEAP Policy and Procedure Manual (October 2025), Renter Household Payment href: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=63 - title: Missouri LIHEAP FFY2026 State Plan, Section 2.3 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.yaml index 50e87a60c05..9db8fab49b0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.yaml @@ -1,8 +1,10 @@ # Missouri LIHEAP Energy Assistance eligibility: at least one qualifying # member; countable income at or below the 60% SMI limit, or below the # federal 110% poverty floor; cash resources of at most $3,000; heating costs -# paid through the household's own fuel bill or through unsubsidized rent -# that includes heat; and a heating fuel other than coal. +# paid through the household's own fuel bill, through an electric supplier +# account while the home has heating (including a subsidized tenant with heat +# in the rent), or through unsubsidized rent that includes heat; and a heating +# fuel other than coal. - name: Case 1, countable income exactly at the size one limit is eligible. period: 2026 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml index 5db7f57d810..eac45cce594 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml @@ -18,7 +18,7 @@ spm_unit: members: [person1, person2, person3] heating_type: NATURAL_GAS - mo_tanf: 3_504 + tanf: 3_504 households: household: members: [person1, person2, person3] @@ -122,3 +122,64 @@ # 49,920 - 3,600 = 46,320. mo_liheap_household_size: 1 mo_liheap_countable_income: 46_320 + +- name: Case 6, the Medicare Part B premium is deducted for a railroad retiree. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + railroad_benefits: 37_000 + medicare_part_b_premium: 2_434.80 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_100 + households: + household: + members: [person1] + state_code: MO + output: + # 2026 Part B premium 202.90 x 12 = 2,434.80. + # Railroad retirement annuity 37,000 - 2,434.80 = 34,565.20. + # Medical deduction for an applicant 65 or older: 100 x 12 = 1,200. + # 34,565.20 - 1,200 = 33,365.20 <= the size 1 limit of 2,840 x 12 + # = 34,080 -> eligible; natural gas pays 326. Without the premium + # deduction, 37,000 - 1,200 = 35,800 would exceed the limit. + mo_liheap_countable_income_person: [34_565.20] + mo_liheap_medical_deduction: 1_200 + mo_liheap_countable_income: 33_365.20 + mo_liheap_income_limit: 34_080 + mo_liheap_eligible: true + mo_liheap: 326 + +- name: Case 7, Missouri TANF the household does not take up is not counted. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 27 + child_support_received: 2_400 + person2: + age: 6 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + mo_tanf: 3_504 + takes_up_tanf_if_eligible: false + households: + household: + members: [person1, person2, person3] + state_code: MO + output: + # A 292 a month (3,504) Missouri TANF entitlement the household does not + # take up is not received, so tanf = 0. Child support received 2,400 + # counts: 0 + 2,400 = 2,400. Counting mo_tanf would give 5,904. + tanf: 0 + mo_liheap_countable_income: 2_400 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml index 0e387add86b..0a0a8837b30 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml @@ -1,9 +1,10 @@ # Missouri LIHEAP countable income per member: earned income less the 20% -# earned income deduction (each earned source floored at zero; none for -# members under 18), plus unearned income (without short- and long-term -# disability payments for members under 18), plus Social Security net of the -# Medicare Part B premium. Members left out of the household size as -# non-citizens have their income counted. +# earned income deduction (none for members under 18), plus unearned income +# (without short- and long-term disability payments for members under 18) +# and Social Security, each source floored at zero, less the full Medicare +# Part B premium of a member receiving Social Security or railroad +# retirement, with the member's total floored at zero. Members left out of +# the household size as non-citizens have their income counted. - name: Case 1, full-time minimum wage earnings after the 20 percent deduction. period: 2026 @@ -99,7 +100,7 @@ # 24,000 x 0.8 = 19,200. Netting the loss would give 21,000 x 0.8 = 16,800. mo_liheap_countable_income_person: [19_200] -- name: Case 5, Social Security counts net of the Medicare Part B premium. +- name: Case 5, the full Medicare Part B premium is deducted for members receiving Social Security. period: 2026 absolute_error_margin: 0.01 input: @@ -124,9 +125,10 @@ output: # 2026 Part B premium 202.90 x 12 = 2,434.80. # Person 1: 1,950 a month = 23,400 - 2,434.80 = 20,965.20. - # Person 2: max(1,800 - 2,434.80, 0) = 0, plus a 500 a month pension - # of 6,000 = 6,000. - mo_liheap_countable_income_person: [20_965.20, 6_000] + # Person 2: Social Security of 150 a month (1,800) plus a 500 a month + # pension of 6,000 = 7,800; the full premium is deducted from the + # member's total: 7,800 - 2,434.80 = 5,365.20. + mo_liheap_countable_income_person: [20_965.20, 5_365.20] - name: Case 6, unearned sources count in full and interest is excluded. period: 2026 @@ -266,3 +268,95 @@ # child's survivor benefit of 800 a month = 9,600 counts as SSA income # (no Part B premium). mo_liheap_countable_income_person: [18_000, 9_600] + +- name: Case 11, a rental loss does not offset wages. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 45_000 + rental_income: -5_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_100 + households: + household: + members: [person1] + state_code: MO + output: + # Wages 45,000 x 0.8 = 36,000; the rental loss is floored: + # max(-5,000, 0) = 0, so 36,000. No children, so no TANF; no medical + # deduction. 36,000 > the size 1 limit of 2,840 x 12 = 34,080 and the + # 110% poverty floor of 1.1 x 15,650 = 17,215 -> ineligible. Netting the + # loss (31,000) would make the household eligible for 326. + mo_liheap_countable_income_person: [36_000] + mo_liheap_countable_income: 36_000 + mo_liheap_income_limit: 34_080 + mo_liheap_eligible: false + mo_liheap: 0 + +- name: Case 12, every earned income source counts after the deduction. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 52 + employment_income: 16_000 + self_employment_income: 1_000 + sstb_self_employment_income: 2_000 + farm_operations_income: 4_000 + partnership_s_corp_income: 8_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + households: + household: + members: [person1] + state_code: MO + output: + # Wages 16,000 + self-employment 1,000 + professional-service + # self-employment 2,000 + farm 4,000 + partnership or S corporation + # 8,000 = 31,000; dropping any source changes the total. + # 31,000 x (1 - 0.2) = 24,800. + mo_liheap_countable_income_person: [24_800] + +- name: Case 13, remaining unearned income sources count in full. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 52 + strike_benefits: 1_200 + rental_income: 1_800 + farm_rent_income: 2_400 + alimony_income: 3_600 + person2: + age: 60 + railroad_benefits: 9_600 + workers_compensation: 4_800 + military_retirement_pay_survivors: 2_400 + mo_ssp: 1_080 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + # Person 1: strike benefits 1,200 + rent from a building 1,800 + farm + # rent 2,400 + alimony 3,600 = 9,000. + # Person 2: railroad retirement 800 a month (9,600) + workers' + # compensation 4,800 + military survivor benefit 2,400 + a Missouri state + # supplementary payment of 90 a month (1,080, a monthly input summed over + # the year) = 17,880. At 60 the member is not on Medicare, so no Part B + # premium is deducted. Dropping any source changes a member's total. + mo_liheap_countable_income_person: [9_000, 17_880] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.yaml index c5b2e1622a7..b7538352f68 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.yaml @@ -233,3 +233,28 @@ # disability or state supplementary payment. Medicaid is a listed # benefit: 100 x 12 = 1,200. mo_liheap_medical_deduction: 1_200 + +- name: Case 10, each remaining listed benefit qualifies a disabled applicant. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [MO, MO, MO, MO, MO] + age: [50, 50, 50, 50, 50] + is_disabled: [true, true, true, true, true] + ssi: [0, 0, 0, 0, 0] + social_security_disability: [0, 0, 0, 0, 0] + medicaid: [0, 0, 0, 0, 0] + social_security_dependents: [7_200, 0, 0, 0, 0] + social_security_survivors: [0, 9_000, 0, 0, 0] + veterans_benefits: [0, 0, 12_000, 0, 0] + railroad_benefits: [0, 0, 0, 10_800, 0] + mo_ssp: [0, 0, 0, 0, 1_200] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + output: + # Five disabled applicants under 65, each with one listed benefit and no + # other: disabled adult child benefit 600 a month (7,200), disabled + # widow(er) benefit 750 a month (9,000), VA disability compensation 1,000 + # a month (12,000), railroad disability annuity 900 a month (10,800) and + # a Missouri state supplementary payment of 100 a month (1,200, a monthly + # input summed over the year). Each qualifies: 100 x 12 = 1,200. + mo_liheap_medical_deduction: [1_200, 1_200, 1_200, 1_200, 1_200] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml index 0b97f29349c..c9496d2a070 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml @@ -1,8 +1,12 @@ -# Missouri LIHEAP Energy Assistance: a one-time payment by primary heating -# fuel (FFY2026 Appendix K; FFY2027 application MO 886-4576). A renter whose -# heat is included in the rent receives 8% of annual rent, capped at the -# amount for the household's fuel (13 CSR 40-19.020(13)). Zero when -# ineligible. +# Missouri LIHEAP Energy Assistance: a one-time payment for the fuel the +# household selects (FFY2026 Appendix K; FFY2027 application MO 886-4576), +# the largest of the amount for its own heating fuel bill, the renter share +# and the electric amount. An unsubsidized renter whose heat is included in +# the rent receives 8% of annual rent, capped at the amount for the +# household's fuel (13 CSR 40-19.020(13)). A household that heats its home +# and pays an electric supplier, including a subsidized tenant whose heat is +# included in the rent, can select the electric amount. No heating (NONE) and +# an unspecified fuel are not paid. Zero when ineligible. - name: Case 1, payment for every heating fuel. period: 2026 @@ -143,3 +147,104 @@ mo_liheap_income_limit: 46_164 mo_liheap_eligible: true mo_liheap: 153 + +- name: Case 7, a household that heats its home and pays an electric supplier receives the larger of its fuel amount and the electric amount. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [MO, MO, MO, MO, MO, MO] + heating_type: [KEROSENE, WOOD, NATURAL_GAS, OTHER, NONE, UNSPECIFIED] + fuel_oil_expense: [1_500, 0, 0, 0, 0, 0] + wood_expense: [0, 900, 0, 0, 0, 0] + gas_expense: [0, 0, 1_100, 0, 0, 0] + other_heating_fuel_expense: [0, 0, 0, 600, 0, 0] + pre_subsidy_electricity_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200] + mo_liheap_countable_income: [18_000, 18_000, 18_000, 18_000, 18_000, 18_000] + output: + # Each pays a 100 a month electric bill (1,200) and 18,000 <= 34,080. + # Kerosene: max(153, electric 318) = 318. Wood: max(219, 318) = 318. + # Natural gas: max(326, 318) = 326. Other fuel: max(0, 318) = 318. + # A home with no heating (NONE) or an unspecified fuel has no heating + # cost, so the electric bill alone does not make it eligible. + mo_liheap_eligible: [true, true, true, true, false, false] + mo_liheap: [318, 318, 326, 318, 0, 0] + +- name: Case 8, a housing assistance recipient with heat in the rent who pays an electric supplier receives the electric amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 33 + pre_subsidy_rent: 6_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + heat_expense_included_in_rent: true + receives_housing_assistance: true + pre_subsidy_electricity_expense: 1_080 + mo_liheap_countable_income: 14_000 + households: + household: + members: [person1] + state_code: MO + output: + # Subsidized, so no renter share; the household pays an electric supplier + # (90 a month = 1,080), which 13 CSR 40-19.020(7)(D) accepts. + # max(own fuel 0, renter share 0, electric 318) = 318. + mo_liheap_eligible: true + mo_liheap: 318 + +- name: Case 9, a renter with heat in the rent and a small renter share selects the electric amount. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 33 + pre_subsidy_rent: 3_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + heat_expense_included_in_rent: true + pre_subsidy_electricity_expense: 900 + mo_liheap_countable_income: 14_000 + households: + household: + members: [person1] + state_code: MO + output: + # Renter share: 250 a month = 3,000 x 0.08 = 240 < natural gas 326 -> 240. + # Electric bill of 75 a month (900): max(240, 318) = 318. + mo_liheap_eligible: true + mo_liheap: 318 + +- name: Case 10, a renter with heat in the rent and an unspecified fuel receives nothing for its electric account. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 33 + pre_subsidy_rent: 9_000 + spm_units: + spm_unit: + members: [person1] + heating_type: UNSPECIFIED + heat_expense_included_in_rent: true + pre_subsidy_electricity_expense: 1_200 + mo_liheap_countable_income: 22_000 + households: + household: + members: [person1] + state_code: MO + output: + # Eligible through unsubsidized rent that includes heat (22,000 <= 34,080). + # Own fuel 0 (heat in the rent); renter share min(9,000 x 0.08 = 720, + # unspecified fuel 0) = 0. An unspecified fuel does not heat the home, so + # the 100 a month electric bill (1,200) adds no electric amount: + # max(0, 0, 0) = 0. + mo_liheap_eligible: true + mo_liheap: 0 diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py b/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py index 8bf0cb2fabd..81673fb844b 100644 --- a/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py @@ -7,12 +7,13 @@ class mo_liheap_eligible(Variable): entity = SPMUnit definition_period = YEAR label = "Eligible for Missouri LIHEAP Energy Assistance" - documentation = "A Missouri household with at least one citizen or legal immigrant member that meets the income limit or the federal 110 percent poverty floor, has resources within the resource limit, pays for heat either through its own fuel bill or through unsubsidized rent that includes heat, and does not heat with coal. Not modeled: the exclusions in 13 CSR 40-19.020(7)(B), (C) and (E)-(H) (nursing or boarding homes, hotels and shelters, Department of Mental Health transitional living, fuel credit balances over $500, self-cut wood and shared-meter dwellings) and the limit of one Energy Assistance payment per household per year." + documentation = "A Missouri household with at least one citizen or legal immigrant member that meets the income limit or the federal 110 percent poverty floor, has resources within the resource limit, pays for heat through its own heating fuel bill, through an electric supplier account while the home has heating (including a subsidized tenant whose heat is in the rent), or through unsubsidized rent that includes heat, and does not heat with coal. A home with no heating or an unspecified heating fuel does not qualify through its electric account. Not modeled: the exclusions in 13 CSR 40-19.020(7)(B), (C) and (E)-(H) (nursing or boarding homes, hotels and shelters, Department of Mental Health transitional living, fuel credit balances over $500, self-cut wood and shared-meter dwellings) and the limit of one Energy Assistance payment per household per year." reference = ( # PDF pages 2-3 - "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + "https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + # PDF pages 8-9 "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8", - # PDF pages 40, 42-43, 122 + # PDF pages 40, 42-43, 51, 122 "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=40", "https://www.law.cornell.edu/uscode/text/42/8624#b_2_B", ) @@ -31,18 +32,27 @@ def formula(spm_unit, period, parameters): floor = np.round(guideline * parameters(period).gov.hhs.liheap.fpg_floor, 2) income_eligible = (income <= limit) | (income < floor) resource_eligible = spm_unit("spm_unit_cash_assets", period) <= p.resource_limit + heating_type = spm_unit("heating_type", period) + types = heating_type.possible_values + # The household selects the fuel to be paid, including its electric + # account (2025 manual page 51; FFY2026 plan section 2.5). + heats_home = (heating_type != types.NONE) & (heating_type != types.UNSPECIFIED) + pays_electric_supplier = heats_home & ( + spm_unit("pre_subsidy_electricity_expense", period) > 0 + ) # 13 CSR 40-19.020(7)(D): subsidized housing is ineligible unless the # household pays an energy supplier or is billed for heating costs. subsidized = spm_unit("receives_housing_assistance", period) | ( spm_unit.household("is_in_public_housing", period) ) heat_in_rent = spm_unit("heat_expense_included_in_rent", period) - pays_for_heat = spm_unit("has_heating_expense", period) | ( - heat_in_rent & ~subsidized + pays_for_heat = ( + spm_unit("has_heating_expense", period) + | pays_electric_supplier + | (heat_in_rent & ~subsidized) ) # 2025 manual Appendix E, denial code O: "Heats with Coal". - heating_type = spm_unit("heating_type", period) - heats_with_coal = heating_type == heating_type.possible_values.COAL + heats_with_coal = heating_type == types.COAL return ( (size > 0) & income_eligible diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.py b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.py index 88046f23d18..ce8d7d75f96 100644 --- a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.py +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.py @@ -7,20 +7,20 @@ class mo_liheap_countable_income(Variable): definition_period = YEAR unit = USD label = "Missouri LIHEAP countable income" - documentation = "Countable income of all members, including members left out of the household size as non-citizens, plus Missouri TANF, less court-ordered child support members pay to someone outside the household and the medical deduction. The child support input does not identify court orders, so all child support paid is deducted." + documentation = "Countable income of all members, including members left out of the household size as non-citizens, plus TANF received (the take-up-gated tanf, which includes Missouri TANF), less court-ordered child support members pay to someone outside the household and the medical deduction. The child support input does not identify court orders, so all child support paid is deducted." reference = ( # PDF pages 5-7 "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=5", "https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=5", # PDF pages 2-3 - "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + "https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", # PDF pages 36, 42-43 "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36", ) defined_for = StateCode.MO def formula(spm_unit, period, parameters): - income = add(spm_unit, period, ["mo_liheap_countable_income_person", "mo_tanf"]) + income = add(spm_unit, period, ["mo_liheap_countable_income_person", "tanf"]) # The 2025 manual deducts child support "paid by any household member # to someone not included in the LIHEAP household" (page 36) and calls # members left out as non-citizens "ineligible household members" diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py index 055aabbc053..387f583fa7d 100644 --- a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py @@ -7,7 +7,7 @@ class mo_liheap_countable_income_person(Variable): definition_period = YEAR unit = USD label = "Missouri LIHEAP countable income per person" - documentation = "Gross income Missouri counts for a household member, including a member left out of the household size as a non-citizen: earned income after the earned income deduction, unearned income, and Social Security net of the Medicare Part B premium. Each earned source is floored at zero, so business and farm losses do not offset other income. Members under 18 have their earned income and their non-Social Security disability payments excluded; their Social Security and SSI count. Not modeled: a Part B premium paid by a member without Social Security (for example a Railroad Retirement beneficiary) and Medicare Part D premiums. Annual income stands in for twelve times the income of the month before application." + documentation = "Gross income Missouri counts for a household member, including a member left out of the household size as a non-citizen: earned income after the earned income deduction plus unearned income, less the SMI (Medicare Part B) premium of a member who receives Social Security or Railroad Retirement benefits, floored at zero. Each earned and unearned source is floored at zero, so business, farm and rental losses do not offset other income. Members under 18 have their earned income and their non-Social Security disability payments excluded; their Social Security and SSI count. Not modeled: Medicare Part D premiums. Annual income stands in for twelve times the income of the month before application." reference = ( # PDF pages 5-7 "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=5", @@ -16,7 +16,7 @@ class mo_liheap_countable_income_person(Variable): # DSS draft FFY2027 plan (report status "Saved -- with Errors"). # PDF pages 5-7 "https://dss.mo.gov/sites/mydss/files/media/pdf/2026/08/liheap-active-ffy2027.pdf#page=5", - # PDF pages 32, 36, 38, 42-43 + # PDF pages 32, 34, 36, 38, 42-43 "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=32", ) defined_for = StateCode.MO @@ -32,12 +32,19 @@ def formula(person, period, parameters): # income, read here as Social Security and SSI. adult_income = countable_earned + add(person, period, p.adult_unearned_sources) adult = person("age", period) >= p.adult_age - unearned = add(person, period, p.unearned_sources) - # Plan section 1.9 counts Social Security excluding the Medicare - # deduction. - social_security = max_( - person("social_security", period) - - person("medicare_part_b_premium", period), - 0, + # Each unearned source is floored at zero, so a rental loss does not + # offset other income; add() also sums monthly sources such as SSI. + unearned = 0 + for source in p.unearned_sources: + unearned = unearned + max_(add(person, period, [source]), 0) + social_security = person("social_security", period) + # The 2025 manual (page 36) deducts the SMI premium for members who + # receive Social Security or Railroad Retirement benefits and pay it. + receives_ss_or_rrb = (social_security > 0) | ( + person("railroad_benefits", period) > 0 ) - return unearned + social_security + where(adult, adult_income, 0) + smi_premium = where( + receives_ss_or_rrb, person("medicare_part_b_premium", period), 0 + ) + gross = unearned + social_security + where(adult, adult_income, 0) + return max_(gross - smi_premium, 0) diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.py b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.py index 2b4a77e0284..c22d07920f9 100644 --- a/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.py +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_medical_deduction.py @@ -10,7 +10,7 @@ class mo_liheap_medical_deduction(Variable): documentation = "Missouri's monthly medical deduction, annualized and given once per household when the applicant or spouse is elderly or disabled. Disabled means totally and permanently disabled or blind and receiving a listed disability benefit. Tax-unit heads and spouses who are citizens or legal immigrants stand in for the applicant and spouse." reference = ( # PDF pages 2-3 - "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + "https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", # PDF pages 36, 48 "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=36", ) diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py b/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py index 6b1380d189f..3e661560f02 100644 --- a/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py @@ -7,23 +7,39 @@ class mo_liheap(Variable): definition_period = YEAR unit = USD label = "Missouri LIHEAP Energy Assistance" - documentation = "Missouri's one-time regular heating Energy Assistance payment: the amount for the household's primary heating fuel, or for a renter household whose heat is included in the rent, the rent share of annual rent up to that amount. The regular monthly rental charge is pre_subsidy_rent, since only unsubsidized renters with heat in rent are eligible. Verified for FY2026-FY2027; earlier years use model parameter backfilling and are unverified historical estimates. Energy Crisis Intervention Program (ECIP) crisis payments are excluded." + documentation = "Missouri's one-time regular heating Energy Assistance payment for the fuel the household selects, taken as the largest of three amounts: the amount for the fuel of its own heating bill; the electric amount for its electric supplier account when the home has heating; and, for an unsubsidized renter whose heat is included in the rent, the rent share of annual rent up to the amount for its heating fuel. The regular monthly rental charge is pre_subsidy_rent, since only unsubsidized renters receive the rent share. A home with no heating or an unspecified heating fuel receives no electric amount. Verified for FY2026-FY2027; earlier years use model parameter backfilling and are unverified historical estimates. Energy Crisis Intervention Program (ECIP) crisis payments are excluded." reference = ( # PDF pages 2-4 - "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + "https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", "https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=9", "https://liheapch.acf.gov/docs/2026/benefits-matricies/MO_BenefitMatrix_2026.docx", + # PDF pages 1, 3 "https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=1", - # PDF pages 62-63, 129 - "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=62", + # PDF pages 51, 62-63, 129 + "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=51", ) defined_for = "mo_liheap_eligible" def formula(spm_unit, period, parameters): p = parameters(period).gov.states.mo.dss.liheap heating_type = spm_unit("heating_type", period) + types = heating_type.possible_values fuel_amount = p.amount[heating_type] - annual_rent = add(spm_unit, period, ["pre_subsidy_rent"]) - renter_amount = min_(annual_rent * p.rent_share, fuel_amount) + own_fuel_amount = where(spm_unit("has_heating_expense", period), fuel_amount, 0) + subsidized = spm_unit("receives_housing_assistance", period) | ( + spm_unit.household("is_in_public_housing", period) + ) heat_in_rent = spm_unit("heat_expense_included_in_rent", period) - return where(heat_in_rent, renter_amount, fuel_amount) + annual_rent = add(spm_unit, period, ["pre_subsidy_rent"]) + renter_amount = where( + heat_in_rent & ~subsidized, + min_(annual_rent * p.rent_share, fuel_amount), + 0, + ) + heats_home = (heating_type != types.NONE) & (heating_type != types.UNSPECIFIED) + electric_bill = spm_unit("pre_subsidy_electricity_expense", period) + electric_amount = where( + heats_home & (electric_bill > 0), p.amount.ELECTRICITY, 0 + ) + # The household selects the fuel to be paid (2025 manual page 51). + return max_(max_(own_fuel_amount, renter_amount), electric_amount) diff --git a/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py b/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py index aa118c64c4e..e10ba4ffc06 100644 --- a/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py +++ b/policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py @@ -6,11 +6,11 @@ class mo_liheap_household_size(Variable): entity = SPMUnit definition_period = YEAR label = "Missouri LIHEAP household size" - documentation = "Number of SPM unit members who are U.S. citizens or legal immigrants. Missouri leaves members who are not citizens or legal permanent residents out of the household count but counts their income (mo_liheap_countable_income_person). The SPM unit approximates the household living in private quarters that purchases residential heat in common; roomers, boarders and live-in attendants have no inputs and are not excluded." + documentation = "Number of SPM unit members who are U.S. citizens or qualified noncitizens. Missouri counts citizens and legal permanent residents, and the 2025 manual (page 44) also accepts refugees, asylees, parolees and COFA citizens as qualified noncitizens; other members are left out of the household count but their income counts (mo_liheap_countable_income_person). The SPM unit approximates the household living in private quarters that purchases residential heat in common; roomers, boarders and live-in attendants have no inputs and are not excluded." reference = ( # PDF pages 2-3 - "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", - # PDF pages 40-43 + "https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=2", + # PDF pages 40-44 "https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=40", ) defined_for = StateCode.MO diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index bbe3ce296cd..a223740d958 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -3444,10 +3444,120 @@ candidates: pe_us: follows: statute code: [] - prs: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10438 + state: ruled + note: 'Ruled 2026-10-19: the statute governs. The implementation applies the federal floor + gov.hhs.liheap.fpg_floor with the poverty guidelines lagged one year. Code not yet on main: mo_liheap_eligible.' +- id: us-mo:liheap-interest-dividends-and-contributions + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Does Missouri count interest and dividends and leave out cash gifts, as the plan's income checklist + indicates, or exclude interest and dividends and count contributions, as the manual does? + sources: + - kind: plan + citation: Missouri FFY2026 LIHEAP State Plan, section 1.9 (Interest, dividends, or royalties checked; Cash gifts + unchecked) + url: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=6 + - kind: manual + citation: Missouri LIHEAP Policy and Procedure Manual (October 2025), Unearned Income (contributions, pages + 32-33) and Income Exclusions (Interest-Dividend Income, page 38) + url: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=32 + readings: + statute: No statute or regulation is supplied; the manual excludes interest and dividend income and counts + monetary assistance from family and friends as contributions. + other: The plan checklist counts interest, dividends and royalties and does not count cash gifts. + example: In FFY2026, a single adult with $40,000 of wages ($32,000 after the 20% deduction) and $2,500 of + dividends counts $32,000 under the manual and is eligible below the $34,080 limit, but counts $34,500 under + the plan and is not. + pe_us: + follows: gap-fill + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10438 + state: ruled + note: 'Ruled 2026-10-06: follow the manual over the plan. Code not yet on main: unearned_sources, + mo_liheap_countable_income_person.' +- id: us-mo:liheap-qualified-noncitizen-members + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Does Missouri count only citizens and legal permanent residents as household members, as the rule says, + or every qualified noncitizen, such as refugees, asylees, parolees and COFA citizens, as the manual accepts? + sources: + - kind: statute + citation: 8 U.S.C. 1611(a), 1612(b) and 1641(b) + url: https://www.law.cornell.edu/uscode/text/8/1612 + - kind: regulation + citation: 13 CSR 40-19.020(6)(A) and (8)(A) + url: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=3 + - kind: manual + citation: Missouri LIHEAP Policy and Procedure Manual (October 2025), Citizenship and Legal Permanent Residence, + pages 43-44 + url: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=43 + readings: + statute: Qualified aliens (8 U.S.C. 1641(b)) may receive federal public benefits, and 8 U.S.C. 1612(b) lets a + state limit them only in TANF, the social services block grant and Medicaid; the manual (page 44) accepts + refugee, parolee and asylee I-94 annotations and includes COFA citizens among qualified noncitizens. + other: The rule and manual page 43 require a citizen of the United States or a legal permanent resident. + example: In FFY2026, a lawful permanent resident, a refugee and their citizen child count three members (a + $4,588 monthly limit); under the citizen-or-LPR text the refugee is left out and the household counts two + ($3,714). + pe_us: + follows: statute + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10438 state: unreviewed - note: 'The implementation applies the federal floor gov.hhs.liheap.fpg_floor with the poverty guidelines lagged - one year; no PR is open yet. Code not yet on main: mo_liheap_eligible.' + note: 'The model counts every citizen or qualified noncitizen (is_citizen_or_legal_immigrant). The statute + reading is an inference: 8 U.S.C. 1612(b) lets a state limit qualified aliens only in TANF, the social services + block grant and Medicaid, and LIHEAP is not among them. Under the citizen-or-LPR text, household-size Case 2 + would count two members, not three. Code not yet on main: mo_liheap_household_size.' +- id: us-mo:liheap-renter-rent-share + program: liheap + years: + from: 2026 + to: 2027 + type: federal-fiscal + question: Does a Missouri renter whose heat is included in the rent receive 8% of annual rent capped at the + Energy Assistance amount (the rule), 16% capped at that amount (manual and plans), or the lesser of 8% or $100 + (RSMo 660.115.2)? + sources: + - kind: statute + citation: RSMo 660.115.1 and 660.115.2 + url: https://revisor.mo.gov/main/OneSection.aspx?section=660.115 + - kind: regulation + citation: 13 CSR 40-19.020(13) + url: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=4 + - kind: manual + citation: Missouri LIHEAP Policy and Procedure Manual (October 2025), Renter Household Payment + url: https://dss.mo.gov/sites/mydss/files/media/pdf/2025/10/liheap-policy-procedure-manual.pdf#page=63 + - kind: plan + citation: Missouri FFY2026 LIHEAP State Plan, section 2.3 + url: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8 + readings: + statute: The rule pays no more than 8% of annual rent, not to exceed the maximum Energy Assistance payment; + RSMo 660.115.2 limits Utilicare renter payments to the lesser of 8% of annual rent or $100. + other: The manual and the FFY2024-FFY2027 plans pay 16% of annual rent, up to the Energy Assistance amount for + the household's size, income and energy source. + example: In FFY2026, a renter household paying $500 a month ($6,000 a year) with propane heat in the rent + receives $480 (8%) under the rule, $495 (16% is $960, capped at propane) under the manual and $100 under the + Utilicare limit. + pe_us: + follows: statute + code: [] + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10438 + state: ruled + note: 'Ruled 2026-10-21: apply the rule''s 8% of annual rent, capped at the amount for the household''s fuel (the + manual''s reading of the maximum Energy Assistance payment). RSMo 660.115.2 is read as limited to payments + from the Utilicare stabilization fund (660.115.1); Energy Assistance is paid from federal LIHEAP funds. Code not + yet on main: mo_liheap, rent_share.' - id: us-mo:liheap-rule-income-ranges-and-payments program: liheap years: @@ -3458,9 +3568,12 @@ candidates: payments in 13 CSR 40-19.020(14), or the 60% SMI limit and flat fuel amounts in the FFY2026-FFY2027 agency documents? sources: + - kind: statute + citation: RSMo 660.100.2 + url: https://revisor.mo.gov/main/OneSection.aspx?section=660.100 - kind: regulation citation: 13 CSR 40-19.020(6)(D) and (14), Payment Levels for Missouri (amended effective May 30, 2017) - url: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=4 + url: https://web.archive.org/web/20250603190025/https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-19.pdf#page=4 - kind: plan citation: Missouri FFY2026 LIHEAP State Plan, sections 2.1, 2.5 and 2.6 url: https://liheapch.acf.gov/docs/2026/state-plans/MO_Plan_2026.pdf#page=8 @@ -3474,20 +3587,24 @@ candidates: citation: Missouri LIHEAP application MO 886-4576 (8-2026), Program Description url: https://dssmanuals.mo.gov/wp-content/uploads/2022/02/liheap-application.pdf#page=1 readings: - statute: No statute is supplied; the rule sets monthly income ranges A-F from 0 to 135% of the poverty level, - with natural gas paying $296 in range A down to $203 in range F. + statute: RSMo 660.100.2 bounds income at 150% of the poverty level or 60% of state median income and requires + eligibility under the federal program; the rule sets monthly income ranges A-F from 0 to 135% of the poverty + level, with natural gas paying $296 in range A down to $203 in range F, and (14) determines payments using + metrics established by the division. other: The plan, Appendix K, manual and application set 60% SMI for every size and one amount per fuel, such as - $326 for natural gas. + $326 for natural gas, paid for the fuel the household selects, including its electric account. example: In FFY2026, a family of four with $39,936 of countable income ($3,328 a month, 124% of the 2025 guideline) that heats with natural gas receives $221 in the rule's range E and $326 under the agency documents. pe_us: - follows: unknown + follows: conflicting-source code: [] - prs: [] - state: unreviewed - note: 'PE-US follows the plan, Appendix K, manual and application; no FFY2026 or FFY2027 agency document uses the - 2017 rule table. The renter share follows 13 CSR 40-19.020(13) (8% of annual rent) over the 16% in the manual - and plans. Code not yet on main: mo_liheap_eligible, mo_liheap_income_limit and the mo_liheap amount parameters.' + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10438 + state: ruled + note: 'Ruled 2026-10-22: apply the operating 60% SMI limits and flat amounts; (14) sets payments using metrics + established by the division. The agency documents also pay the fuel the household selects, including its + electric account, where the rule''s table is headed Primary Fuel. Code not yet on main: mo_liheap_eligible, + mo_liheap_income_limit, mo_liheap, amount, smi_rate.' - id: us-mo:medicaid-published-dollar-limit-rounding program: medicaid years: From 864ef4a0729c65829f397a76904842db2fb41ff2 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 29 Oct 2026 10:07:52 -0400 Subject: [PATCH 4/5] Set SSI to zero for the railroad retiree in Missouri LIHEAP Case 6 The model's SSI income list does not count railroad retirement annuities, so the 70-year-old annuitant otherwise received $11,928 of SSI. Co-Authored-By: Claude Opus 5.5 --- .../states/mo/dss/liheap/income/mo_liheap_countable_income.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml index eac45cce594..e147756c81e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income.yaml @@ -132,6 +132,8 @@ age: 70 railroad_benefits: 37_000 medicare_part_b_premium: 2_434.80 + # The model's SSI income test does not count railroad annuities. + ssi: 0 spm_units: spm_unit: members: [person1] From f9336d119abc4b2e138129c82eb354b410b3ae38 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 29 Oct 2026 21:59:15 -0400 Subject: [PATCH 5/5] Address review round 2 for Missouri LIHEAP Apply DTrim99's round 2 review: tests for the Medicare premium gate and the per-member floor, comment wording, and candidate code paths. Co-Authored-By: Claude Opus 5.5 --- .../mo_liheap_countable_income_person.yaml | 77 +++++++++++++++++++ .../gov/states/mo/dss/liheap/mo_liheap.yaml | 11 +-- source_conflicts/candidates.yaml | 34 ++++---- 3 files changed, 104 insertions(+), 18 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml index 0a0a8837b30..17272e03336 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.yaml @@ -360,3 +360,80 @@ # the year) = 17,880. At 60 the member is not on Medicare, so no Part B # premium is deducted. Dropping any source changes a member's total. mo_liheap_countable_income_person: [9_000, 17_880] + +- name: Case 14, the Medicare Part B premium is not deducted for a member without Social Security or railroad benefits. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + # A retired public employee whose job was not covered by Social + # Security pays the 2026 Part B premium of 202.90 x 12 directly. + taxable_pension_income: 36_500 + medicare_part_b_premium: 2_434.80 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_100 + households: + household: + members: [person1] + state_code: MO + output: + # The pension of 36,500 counts. With no Social Security or railroad + # benefits, the 2,434.80 premium is not deducted: 36,500. SSI is 0 + # (36,500 / 12 - 20 = 3,021.67 a month > 994), and no state supplement. + # Medical deduction for an applicant 65 or older: 100 x 12 = 1,200. + # 36,500 - 1,200 = 35,300 > the size 1 limit of 2,840 x 12 = 34,080 and + # the 110% poverty floor of 1.1 x 15,650 = 17,215 -> ineligible. + # Deducting the premium would give 36,500 - 2,434.80 = 34,065.20 and + # 34,065.20 - 1,200 = 32,865.20 <= 34,080, eligible for natural gas 326. + # The railroad retiree of mo_liheap_countable_income Case 6 has the + # premium deducted. + mo_liheap_countable_income_person: [36_500] + mo_liheap_medical_deduction: 1_200 + mo_liheap_countable_income: 35_300 + mo_liheap_income_limit: 34_080 + mo_liheap_eligible: false + mo_liheap: 0 + +- name: Case 15, a member's countable income is floored at zero when the Medicare Part B premium exceeds that member's income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 52_000 + person2: + # A parent who takes up neither SSI nor the Medicare Savings Program + # and pays the full premium. As an input dependent, the parent does + # not become the tax-unit head (which would add a 1,200 medical + # deduction); with SSI taken up, the model would pay about + # (994 - 130) x 12 = 10,368, more than the premium. + age: 66 + is_tax_unit_dependent: true + social_security_retirement: 1_800 + medicare_part_b_premium: 2_434.80 + takes_up_ssi_if_eligible: false + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + households: + household: + members: [person1, person2] + state_code: MO + output: + # Person 1: $25.00 an hour x 2,080 hours = 52,000 x (1 - 0.2) = 41,600. + # Person 2: Social Security of 150 a month (1,800) less the 2026 Part B + # premium of 202.90 x 12 = 2,434.80, floored: max(-634.80, 0) = 0. + # No medical deduction: the head is 40 and the parent is a dependent. + # No child under 18, so no TANF: 41,600 + 0 = 41,600. + # Without the floor, person 2 would count -634.80 and the household + # 41,600 - 634.80 = 40,965.20. + mo_liheap_countable_income_person: [41_600, 0] + mo_liheap_medical_deduction: 0 + mo_liheap_countable_income: 41_600 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml index c9496d2a070..2f139f739a6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/liheap/mo_liheap.yaml @@ -164,8 +164,9 @@ # Each pays a 100 a month electric bill (1,200) and 18,000 <= 34,080. # Kerosene: max(153, electric 318) = 318. Wood: max(219, 318) = 318. # Natural gas: max(326, 318) = 326. Other fuel: max(0, 318) = 318. - # A home with no heating (NONE) or an unspecified fuel has no heating - # cost, so the electric bill alone does not make it eligible. + # A home with no heating (NONE) has no heating cost. An unspecified fuel + # is not paid (heating_type is a required input; issue 9754), so the + # electric bill alone does not make either household eligible. mo_liheap_eligible: [true, true, true, true, false, false] mo_liheap: [318, 318, 326, 318, 0, 0] @@ -243,8 +244,8 @@ output: # Eligible through unsubsidized rent that includes heat (22,000 <= 34,080). # Own fuel 0 (heat in the rent); renter share min(9,000 x 0.08 = 720, - # unspecified fuel 0) = 0. An unspecified fuel does not heat the home, so - # the 100 a month electric bill (1,200) adds no electric amount: - # max(0, 0, 0) = 0. + # unspecified fuel 0) = 0. An unspecified fuel is not paid (heating_type + # is a required input; issue 9754), so the 100 a month electric bill + # (1,200) adds no electric amount: max(0, 0, 0) = 0. mo_liheap_eligible: true mo_liheap: 0 diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 0b15e69233b..1c37b7ac50b 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -3790,12 +3790,13 @@ candidates: but is below the $107,965 floor and receives the $326 natural-gas Energy Assistance payment. pe_us: follows: statute - code: [] + code: + - policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py prs: - https://github.com/PolicyEngine/policyengine-us/pull/10438 state: ruled note: 'Ruled 2026-10-19: the statute governs. The implementation applies the federal floor - gov.hhs.liheap.fpg_floor with the poverty guidelines lagged one year. Code not yet on main: mo_liheap_eligible.' + gov.hhs.liheap.fpg_floor with the poverty guidelines lagged one year.' - id: us-mo:liheap-interest-dividends-and-contributions program: liheap years: @@ -3822,12 +3823,13 @@ candidates: the plan and is not. pe_us: follows: gap-fill - code: [] + code: + - policyengine_us/parameters/gov/states/mo/dss/liheap/income/unearned_sources.yaml + - policyengine_us/variables/gov/states/mo/dss/liheap/income/mo_liheap_countable_income_person.py prs: - https://github.com/PolicyEngine/policyengine-us/pull/10438 state: ruled - note: 'Ruled 2026-10-06: follow the manual over the plan. Code not yet on main: unearned_sources, - mo_liheap_countable_income_person.' + note: 'Ruled 2026-10-06: follow the manual over the plan.' - id: us-mo:liheap-qualified-noncitizen-members program: liheap years: @@ -3857,14 +3859,15 @@ candidates: ($3,714). pe_us: follows: statute - code: [] + code: + - policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap_household_size.py prs: - https://github.com/PolicyEngine/policyengine-us/pull/10438 state: unreviewed note: 'The model counts every citizen or qualified noncitizen (is_citizen_or_legal_immigrant). The statute reading is an inference: 8 U.S.C. 1612(b) lets a state limit qualified aliens only in TANF, the social services block grant and Medicaid, and LIHEAP is not among them. Under the citizen-or-LPR text, household-size Case 2 - would count two members, not three. Code not yet on main: mo_liheap_household_size.' + would count two members, not three.' - id: us-mo:liheap-renter-rent-share program: liheap years: @@ -3897,14 +3900,15 @@ candidates: Utilicare limit. pe_us: follows: statute - code: [] + code: + - policyengine_us/parameters/gov/states/mo/dss/liheap/rent_share.yaml + - policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py prs: - https://github.com/PolicyEngine/policyengine-us/pull/10438 state: ruled note: 'Ruled 2026-10-21: apply the rule''s 8% of annual rent, capped at the amount for the household''s fuel (the manual''s reading of the maximum Energy Assistance payment). RSMo 660.115.2 is read as limited to payments - from the Utilicare stabilization fund (660.115.1); Energy Assistance is paid from federal LIHEAP funds. Code not - yet on main: mo_liheap, rent_share.' + from the Utilicare stabilization fund (660.115.1); Energy Assistance is paid from federal LIHEAP funds.' - id: us-mo:liheap-rule-income-ranges-and-payments program: liheap years: @@ -3944,14 +3948,18 @@ candidates: that heats with natural gas receives $221 in the rule's range E and $326 under the agency documents. pe_us: follows: conflicting-source - code: [] + code: + - policyengine_us/parameters/gov/states/mo/dss/liheap/amount.yaml + - policyengine_us/parameters/gov/states/mo/dss/liheap/eligibility/smi_rate.yaml + - policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_eligible.py + - policyengine_us/variables/gov/states/mo/dss/liheap/eligibility/mo_liheap_income_limit.py + - policyengine_us/variables/gov/states/mo/dss/liheap/mo_liheap.py prs: - https://github.com/PolicyEngine/policyengine-us/pull/10438 state: ruled note: 'Ruled 2026-10-22: apply the operating 60% SMI limits and flat amounts; (14) sets payments using metrics established by the division. The agency documents also pay the fuel the household selects, including its - electric account, where the rule''s table is headed Primary Fuel. Code not yet on main: mo_liheap_eligible, - mo_liheap_income_limit, mo_liheap, amount, smi_rate.' + electric account, where the rule''s table is headed Primary Fuel.' - id: us-mo:medicaid-published-dollar-limit-rounding program: medicaid years: