diff --git a/changelog.d/ok-liheap.added.md b/changelog.d/ok-liheap.added.md new file mode 100644 index 00000000000..f3aed37029d --- /dev/null +++ b/changelog.d/ok-liheap.added.md @@ -0,0 +1 @@ +Add Oklahoma LIHEAP regular heating assistance, including qualified household size, income deeming, heating responsibility, and published payment schedules, with documented input limitations. diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/earned_income.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/earned_income.yaml new file mode 100644 index 00000000000..561ad51af73 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/earned_income.yaml @@ -0,0 +1,21 @@ +description: Oklahoma deducts up to this monthly amount from each employed member's earned income under the Low Income Home Energy Assistance Program. +# Eligible members receive this deduction after the gross income test. +# Ineligible members receive it within deeming before that test. +# The 10/1/2024, 10/1/2025 and 10/1/2026 editions of Appendix C-7 all print +# $240. +values: + 2024-10-01: 240 + +metadata: + unit: currency-USD + period: month + label: Oklahoma LIHEAP monthly earned income deduction + reference: + - title: OKDHS Appendix C-7, Earned income deduction, 10/1/2024 edition + href: https://web.archive.org/web/20241207141659id_/https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf + - title: OKDHS Appendix C-7, Earned income deduction, 10/1/2025 edition + href: https://web.archive.org/web/20260509201726id_/https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf + - title: OKDHS Appendix C-7, Earned income deduction, current edition (10/1/2026) + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf + - title: OAC 340:20-1-11(c)(3), September 2025 permanent adoption + href: https://oklahoma.gov/content/dam/ok/en/omma/content/rulemaking-process/rules/Register_Volume-42_Issue-20.pdf#page=581 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/medical_age_threshold.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/medical_age_threshold.yaml new file mode 100644 index 00000000000..66c0134236b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/medical_age_threshold.yaml @@ -0,0 +1,11 @@ +description: Oklahoma limits the medical expense deduction to members this age or older, or disabled, under the Low Income Home Energy Assistance Program. +values: + 2025-09-15: 60 + +metadata: + unit: year + period: year + label: Oklahoma LIHEAP medical deduction age threshold + reference: + - title: OAC 340:20-1-11(c)(1), September 2025 permanent adoption + href: https://oklahoma.gov/content/dam/ok/en/omma/content/rulemaking-process/rules/Register_Volume-42_Issue-20.pdf#page=580 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deeming/child_only_need_standard.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deeming/child_only_need_standard.yaml new file mode 100644 index 00000000000..22990dceee6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deeming/child_only_need_standard.yaml @@ -0,0 +1,55 @@ +description: Oklahoma deducts this monthly need standard from the income of a children-only group of ineligible members before deeming it under the Low Income Home Energy Assistance Program. +# C-1 Schedule IX-B is children only. Adult-containing groups reuse the +# existing TANF Schedule IX-A parameter. The 1/1/2025, 7/1/2025, 4/1/2026 +# and 7/1/2026 editions of Appendix C-1 print the same schedule. +brackets: + - threshold: + 2025-01-01: 1 + amount: + 2025-01-01: 193 + - threshold: + 2025-01-01: 2 + amount: + 2025-01-01: 380 + - threshold: + 2025-01-01: 3 + amount: + 2025-01-01: 535 + - threshold: + 2025-01-01: 4 + amount: + 2025-01-01: 691 + - threshold: + 2025-01-01: 5 + amount: + 2025-01-01: 830 + - threshold: + 2025-01-01: 6 + amount: + 2025-01-01: 974 + - threshold: + 2025-01-01: 7 + amount: + 2025-01-01: 1_098 + - threshold: + 2025-01-01: 8 + amount: + 2025-01-01: 1_219 + - threshold: + 2025-01-01: 9 + amount: + 2025-01-01: 1_333 + +metadata: + type: single_amount + threshold_unit: person + amount_unit: currency-USD + period: month + label: Oklahoma LIHEAP children-only deemed-income need standard + reference: + - title: OAC 340:20-1-11(a)(4)(C), need allowance for ineligible members + href: https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html + - title: OKDHS Appendix C-1, Schedule IX-B, 1/1/2025 edition + href: https://web.archive.org/web/20250222193016id_/https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-1.pdf#page=4 + - title: OKDHS Appendix C-1, Schedule IX-B, 7/1/2026 edition + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-1.pdf#page=5 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_rate.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_rate.yaml new file mode 100644 index 00000000000..74396ce6392 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_rate.yaml @@ -0,0 +1,19 @@ +description: Oklahoma limits gross income to this multiple of the federal poverty guideline under the Low Income Home Energy Assistance Program. +values: + 2024-10-01: 1.3 + +metadata: + unit: /1 + period: year + label: Oklahoma LIHEAP federal poverty guideline rate + reference: + - title: Oklahoma FY2025 State Plan, Section 2.1 + href: https://liheapch.acf.gov/docs/2025/state-plans/OK_Plan_2025.pdf#page=9 + - title: Oklahoma FY2026 State Plan, Section 2.1 + href: https://liheapch.acf.gov/docs/2026/state-plans/OK_Plan_2026.pdf#page=9 + - title: Oklahoma FY2025 Winter Heating application announcement + href: https://oklahoma.gov/okdhs/newsroom/2024/december/comm12172024.html + - title: Oklahoma FY2026 Winter Heating application announcement + href: https://oklahoma.gov/okdhs/newsroom/2026/january/comm01062026.html + - title: OKDHS Appendix C-7, effective October 1, 2026 + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_year_lag.yaml new file mode 100644 index 00000000000..0d825c244b1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_year_lag.yaml @@ -0,0 +1,21 @@ +description: Oklahoma uses the federal poverty guideline from this many years before the heating benefit year under the Low Income Home Energy Assistance Program. +# The 10/1/2024, 10/1/2025 and 10/1/2026 Appendix C-7 charts reconcile to +# the 2024, 2025 and 2026 guidelines. +values: + 2024-10-01: 1 + +metadata: + unit: year + period: year + label: Oklahoma LIHEAP federal poverty guideline year lag + reference: + - title: Oklahoma FY2025 State Plan, Section 2.1 + href: https://liheapch.acf.gov/docs/2025/state-plans/OK_Plan_2025.pdf#page=9 + - title: Oklahoma FY2025 Winter Heating application announcement + href: https://oklahoma.gov/okdhs/newsroom/2024/december/comm12172024.html + - title: Oklahoma FY2026 State Plan, Section 2.1 + href: https://liheapch.acf.gov/docs/2026/state-plans/OK_Plan_2026.pdf#page=9 + - title: Oklahoma FY2026 Winter Heating application announcement + href: https://oklahoma.gov/okdhs/newsroom/2026/january/comm01062026.html + - title: OKDHS Appendix C-7, effective October 1, 2026 + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/max_table_size.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/max_table_size.yaml new file mode 100644 index 00000000000..eab87954154 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/max_table_size.yaml @@ -0,0 +1,17 @@ +description: Oklahoma sets monthly income limits through this household size and adds a per-member amount above it under the Low Income Home Energy Assistance Program. +values: + 2024-10-01: 8 + +metadata: + unit: person + period: year + label: Oklahoma LIHEAP maximum income table size + reference: + - title: Oklahoma FY2025 Winter Heating application announcement + href: https://oklahoma.gov/okdhs/newsroom/2024/december/comm12172024.html + - title: Oklahoma FY2026 Winter Heating application announcement + href: https://oklahoma.gov/okdhs/newsroom/2026/january/comm01062026.html + - title: OKDHS Appendix C-7, additional-person instruction, 10/1/2024 edition + href: https://web.archive.org/web/20241207141659id_/https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf + - title: OKDHS Appendix C-7, additional-person instruction, 10/1/2026 edition + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/rounding_increment.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/rounding_increment.yaml new file mode 100644 index 00000000000..2a6cb8734e2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/rounding_increment.yaml @@ -0,0 +1,20 @@ +description: Oklahoma rounds monthly income limits up to this increment under the Low Income Home Energy Assistance Program. +# Ceiling the base and each extra-person amount separately matches the +# published charts and their $583, $596 and $616 additional-person amounts +# (Appendix C-7, 10/1/2024, 10/1/2025 and 10/1/2026 editions). +values: + 2024-10-01: 1 + +metadata: + unit: currency-USD + period: month + label: Oklahoma LIHEAP monthly income limit rounding increment + reference: + - title: Oklahoma FY2025 Winter Heating application announcement + href: https://oklahoma.gov/okdhs/newsroom/2024/december/comm12172024.html + - title: Oklahoma FY2026 Winter Heating application announcement + href: https://oklahoma.gov/okdhs/newsroom/2026/january/comm01062026.html + - title: OKDHS Appendix C-7, 10/1/2024 edition + href: https://web.archive.org/web/20241207141659id_/https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf + - title: OKDHS Appendix C-7, effective October 1, 2026 + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/earned.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/earned.yaml new file mode 100644 index 00000000000..a6fb04016ec --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/earned.yaml @@ -0,0 +1,24 @@ +description: Oklahoma uses these sources as earned income under the Low Income Home Energy Assistance Program. +# Existing net business inputs stand in for gross receipts less the 50% +# business-expense deduction (OAC 340:20-1-11(c)(4)); no new expense input. +# partnership_s_corp_income mixes active partners' self-employment earnings, +# earned under 340:20-1-11(a)(2), with S corporation and passive partnership +# shares that Oklahoma SNAP counts as unearned (340:50-7-29(b)(2), (c)(8)). +# The input cannot separate them; only the $240 earned deduction differs. +values: + 2025-09-15: + - employment_income + - self_employment_income + - sstb_self_employment_income + - farm_operations_income + - partnership_s_corp_income + +metadata: + unit: list + period: year + label: Oklahoma LIHEAP earned income sources + reference: + - title: "OAC 340:20-1-11(a)-(b), September 2025 permanent adoption #page 576-578" + href: https://oklahoma.gov/content/dam/ok/en/omma/content/rulemaking-process/rules/Register_Volume-42_Issue-20.pdf#page=576 + - title: OAC 340:50-7-22, Incorporated SNAP income exclusions + href: https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/unearned.yaml new file mode 100644 index 00000000000..d72f0b444fc --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/unearned.yaml @@ -0,0 +1,57 @@ +description: Oklahoma uses these sources as unearned income under the Low Income Home Energy Assistance Program. +# OAC 340:20-1-11(a) counts earned and unearned income unless excluded. +# Income sources represent regular receipts, not excluded asset principal, +# loans, nonrecurring lump sums or restricted trust distributions. The +# September 2025 rule replaces the old 38-item list with program-specific +# exclusions, defaulting to Oklahoma SNAP exclusions. Aggregate inputs cannot +# distinguish every exclusion, including irregular small gifts, qualified +# educational/VA aid, restricted tribal trust receipts, redirected support +# and third-party payments. Those detailed pathways remain unverified. +# State SSP receipts are not modeled; SSI is federal, and TANF is added once +# at SPMUnit level through the take-up-gated tanf aggregate. +values: + 2025-09-15: + # Reported unemployment compensation, otherwise modeled Oklahoma UI (ok_ui). + - total_unemployment_compensation + - strike_benefits + # OAC 340:20-1-11(a) counts "All gross earned and unearned income", and + # 340:20-1-11(c) requires the gross income standard to be met "before + # allowing applicable income deductions", which include "Medicare premiums" + # (340:50-7-31(a)(3)(A)(vi)). Plan item 1.9 (FY2025-FY2027, PDF page 6) + # checks "Excluding MediCare deduction" for SSA benefits; the regulation + # governs, and the plan narrative (FY2026, PDF page 7) also uses gross income. + - social_security + - ssi + # Military retirement pay is a separate input from the pension inputs that + # pension_income adds, so both are listed; a household reports the amount + # in one or the other. + - pension_income + - military_retirement_pay + # Plan Section 1.9 counts retirement benefits; IRA, 401(k), 403(b), SEP + # and Keogh distributions are separate inputs from pension_income. + - retirement_distributions + - survivor_benefits + - railroad_benefits + - workers_compensation + - disability_benefits + - rental_income + - farm_rent_income + - alimony_income + - child_support_received + - interest_income + - ordinary_dividend_income + - veterans_benefits + - financial_assistance + - estate_income + +metadata: + unit: list + period: year + label: Oklahoma LIHEAP unearned income sources + reference: + - title: "OAC 340:20-1-11(a)-(b), September 2025 permanent adoption #page 576-578" + href: https://oklahoma.gov/content/dam/ok/en/omma/content/rulemaking-process/rules/Register_Volume-42_Issue-20.pdf#page=576 + - title: OAC 340:50-7-22 and 340:50-7-29(c), incorporated SNAP income exclusions and inclusions + href: https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html + - title: "Oklahoma FY2026 State Plan, Section 1.9 and income narrative #page 6-7" + href: https://liheapch.acf.gov/docs/2026/state-plans/OK_Plan_2026.pdf#page=6 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/student_earned_income_age_limit.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/student_earned_income_age_limit.yaml new file mode 100644 index 00000000000..ed9c87423d8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/student_earned_income_age_limit.yaml @@ -0,0 +1,17 @@ +description: Oklahoma excludes earned income of elementary or high school students under adult control below this age under the Low Income Home Energy Assistance Program. +# The current LIHEAP rule incorporates program-dependent exclusions and +# defaults to Oklahoma SNAP exclusions. is_in_k12_school represents elementary +# or high school attendance and tax dependency approximates adult control; +# excluded training income is not separately identified. +values: + 2025-09-15: 18 + +metadata: + unit: year + period: year + label: Oklahoma LIHEAP student earned income exclusion age limit + reference: + - title: OAC 340:20-1-11(b), September 2025 permanent adoption + href: https://oklahoma.gov/content/dam/ok/en/omma/content/rulemaking-process/rules/Register_Volume-42_Issue-20.pdf#page=578 + - title: OAC 340:50-7-22(9), Child earnings + href: https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/household_size_group.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/household_size_group.yaml new file mode 100644 index 00000000000..d3386deb81f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/household_size_group.yaml @@ -0,0 +1,26 @@ +description: Oklahoma uses this household-size group for the regular heating payment under the Low Income Home Energy Assistance Program. +brackets: + - threshold: + 2021-10-01: 0 + amount: + 2021-10-01: 1 + - threshold: + 2021-10-01: 4 + amount: + 2021-10-01: 2 + - threshold: + 2021-10-01: 7 + amount: + 2021-10-01: 3 + +metadata: + type: single_amount + threshold_unit: person + amount_unit: /1 + period: year + label: Oklahoma LIHEAP payment household size group + reference: + - title: OKDHS Appendix C-7-A, Winter Heating Program + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1 + - title: Oklahoma FY2026 Benefits Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/OK_BenefitMatrix_2026.docx diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/income_band.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/income_band.yaml new file mode 100644 index 00000000000..7601df31f23 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/income_band.yaml @@ -0,0 +1,28 @@ +description: Oklahoma uses this net monthly income band for the regular heating payment under the Low Income Home Energy Assistance Program. +# Printed lower bounds are inclusive. Monthly net income is rounded half up +# to the nearest dollar before the lookup (OAC 340:20-1-11(a)). +brackets: + - threshold: + 2021-10-01: 0 + amount: + 2021-10-01: 1 + - threshold: + 2021-10-01: 401 + amount: + 2021-10-01: 2 + - threshold: + 2021-10-01: 701 + amount: + 2021-10-01: 3 + +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + period: month + label: Oklahoma LIHEAP net monthly income band + reference: + - title: OKDHS Appendix C-7-A, Winter Heating Program + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1 + - title: Oklahoma FY2026 Benefits Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/OK_BenefitMatrix_2026.docx diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/delivered.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/delivered.yaml new file mode 100644 index 00000000000..8f1b8a47721 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/delivered.yaml @@ -0,0 +1,42 @@ +description: Oklahoma provides this regular winter heating payment by net income and household size for propane, kerosene or heating oil under the Low Income Home Energy Assistance Program. + +1: + 1: + 2021-10-01: 425 + 2: + 2021-10-01: 468 + 3: + 2021-10-01: 500 + +2: + 1: + 2021-10-01: 350 + 2: + 2021-10-01: 385 + 3: + 2021-10-01: 412 + +3: + 1: + 2021-10-01: 280 + 2: + 2021-10-01: 308 + 3: + 2021-10-01: 330 + +metadata: + unit: currency-USD + period: year + label: Oklahoma LIHEAP delivered winter payment matrix + propagate_metadata_to_children: true + breakdown: + - range(1, 4) + - range(1, 4) + breakdown_labels: + - Net monthly income band + - Household size group + reference: + - title: OKDHS Appendix C-7-A, Winter Heating Program + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1 + - title: Oklahoma FY2026 Benefits Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/OK_BenefitMatrix_2026.docx diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/ordinary.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/ordinary.yaml new file mode 100644 index 00000000000..d92bec62434 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/ordinary.yaml @@ -0,0 +1,42 @@ +description: Oklahoma provides this regular winter heating payment by net income and household size for natural gas, electricity, wood or coal under the Low Income Home Energy Assistance Program. + +1: + 1: + 2021-10-01: 365 + 2: + 2021-10-01: 402 + 3: + 2021-10-01: 430 + +2: + 1: + 2021-10-01: 265 + 2: + 2021-10-01: 292 + 3: + 2021-10-01: 312 + +3: + 1: + 2021-10-01: 235 + 2: + 2021-10-01: 259 + 3: + 2021-10-01: 277 + +metadata: + unit: currency-USD + period: year + label: Oklahoma LIHEAP ordinary winter payment matrix + propagate_metadata_to_children: true + breakdown: + - range(1, 4) + - range(1, 4) + breakdown_labels: + - Net monthly income band + - Household size group + reference: + - title: OKDHS Appendix C-7-A, Winter Heating Program + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1 + - title: Oklahoma FY2026 Benefits Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/OK_BenefitMatrix_2026.docx diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/renter.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/renter.yaml new file mode 100644 index 00000000000..3c68ef9efdb --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/renter.yaml @@ -0,0 +1,42 @@ +description: Oklahoma provides this regular winter heating payment by net income and household size for heating included in rent under the Low Income Home Energy Assistance Program. + +1: + 1: + 2021-10-01: 150 + 2: + 2021-10-01: 165 + 3: + 2021-10-01: 180 + +2: + 1: + 2021-10-01: 110 + 2: + 2021-10-01: 120 + 3: + 2021-10-01: 135 + +3: + 1: + 2021-10-01: 100 + 2: + 2021-10-01: 110 + 3: + 2021-10-01: 125 + +metadata: + unit: currency-USD + period: year + label: Oklahoma LIHEAP renter winter payment matrix + propagate_metadata_to_children: true + breakdown: + - range(1, 4) + - range(1, 4) + breakdown_labels: + - Net monthly income band + - Household size group + reference: + - title: OKDHS Appendix C-7-A, Winter Heating Program + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1 + - title: Oklahoma FY2026 Benefits Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/OK_BenefitMatrix_2026.docx diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/roomer.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/roomer.yaml new file mode 100644 index 00000000000..48a6d0e40e1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/roomer.yaml @@ -0,0 +1,42 @@ +description: Oklahoma provides this regular winter heating payment by net income and household size for roomers with heating included in rent under the Low Income Home Energy Assistance Program. + +1: + 1: + 2021-10-01: 70 + 2: + 2021-10-01: 0 + 3: + 2021-10-01: 0 + +2: + 1: + 2021-10-01: 50 + 2: + 2021-10-01: 0 + 3: + 2021-10-01: 0 + +3: + 1: + 2021-10-01: 40 + 2: + 2021-10-01: 0 + 3: + 2021-10-01: 0 + +metadata: + unit: currency-USD + period: year + label: Oklahoma LIHEAP roomer winter payment matrix + propagate_metadata_to_children: true + breakdown: + - range(1, 4) + - range(1, 4) + breakdown_labels: + - Net monthly income band + - Household size group + reference: + - title: OKDHS Appendix C-7-A, Winter Heating Program + href: https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1 + - title: Oklahoma FY2026 Benefits Matrix + href: https://liheapch.acf.gov/docs/2026/benefits-matricies/OK_BenefitMatrix_2026.docx diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 5250ab3aa89..166a83384e0 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -808,8 +808,16 @@ programs: category: Benefits agency: HHS status: partial - coverage: DC, Riverside County, MA, IL, IN, KS, KY, MD, MS, NC, NE, NJ, NY, OR, TX + coverage: DC, Riverside County, MA, IL, IN, KS, KY, MD, MS, NC, NE, NJ, NY, OK, OR, TX state_implementations: + - state: OK + status: partial + name: Oklahoma LIHEAP + full_name: Oklahoma Low Income Home Energy Assistance Program + variable: ok_liheap + parameter_prefix: gov.states.ok.dhs.liheap + verified_years: "2025-2027" + notes: FY2025-FY2027 regular winter heating only, using the Appendix C-7-A payment matrix. Crisis, cooling, weatherization and equipment assistance are out of scope. - state: DC status: complete name: DC LIHEAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.yaml new file mode 100644 index 00000000000..c2198812f65 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.yaml @@ -0,0 +1,73 @@ +# Oklahoma LIHEAP regular heating cases. + +# OAC 340:20-1-10(h)(2), 340:20-1-11(a); C-7 size 1 limit $1,729/mo (20,748/yr), inclusive. Monthly gross rounds half up: +# 20,748/12 = 1,729.00 -> eligible; 20,753/12 = 1,729.42 -> 1,729, eligible; 20,754/12 = 1,729.50 -> 1,730 > 1,729, ineligible. +# The ordinary program has no asset test. +- name: Case 1, the gross ceiling compares monthly income rounded to the nearest dollar and assets do not change it. + period: 2027 + input: + state_code: [OK, OK, OK] + age: [40, 40, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [CITIZEN, CITIZEN, CITIZEN] + ok_liheap_gross_income: [20_748, 20_753, 20_754] + has_heating_expense: [true, true, true] + bank_account_assets: [1_000_000, 1_000_000, 1_000_000] + ssi: [0, 0, 0] + output: + ok_liheap_income_limit: [20_748, 20_748, 20_748] + ok_liheap_eligible: [true, true, false] + +# OAC 340:20-1-19(d) pays heat-in-rent renters who pay a surcharge, and 340:20-1-10(h) denies unverified +# responsibility; a positive primary fuel bill represents the surcharge. Subsidy status no longer matters: +# unsubsidized and subsidized with no bill -> false; the responsibility flag alone (subsidized or public housing) +# -> false; subsidized with a 1 bill -> true. +- name: Case 2, heat in rent needs a positive surcharge whether or not the rent is subsidized and the flag alone does + not qualify. + period: 2027 + input: + state_code: [OK, OK, OK, OK, OK] + age: [40, 40, 40, 40, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [CITIZEN, CITIZEN, CITIZEN, CITIZEN, CITIZEN] + ok_liheap_gross_income: [0, 0, 0, 0, 0] + heat_expense_included_in_rent: [true, true, true, true, true] + receives_housing_assistance: [false, true, true, true, false] + is_in_public_housing: [false, false, false, false, true] + gas_expense: [0, 0, 0, 1, 0] + has_heating_expense: [false, false, true, false, true] + ssi: [0, 0, 0, 0, 0] + output: + ok_liheap_eligible: [false, false, false, true, false] + +# Current OAC 340:20-1-10(e), (h)(1) includes total or partial responsibility. A direct obligation may be reported with +# the existing has_heating_expense or demonstrated by a positive primary bill. +- name: Case 3, direct responsibility can be reported or established by a positive primary bill. + period: 2027 + input: + state_code: [OK, OK, OK] + age: [40, 40, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [CITIZEN, CITIZEN, CITIZEN] + ok_liheap_gross_income: [0, 0, 0] + heat_expense_included_in_rent: [false, false, false] + has_heating_expense: [true, false, false] + gas_expense: [0, 0, 1] + ssi: [0, 0, 0] + output: + ok_liheap_eligible: [true, false, true] + +# Current OAC 340:20-1-10(a), (h)(3) and state scope: Oklahoma ordinary heating requires heat and at least one qualified +# member. +- name: Case 4, state no heat and no qualified member each prevent eligibility. + period: 2027 + input: + state_code: [TX, OK, OK] + age: [40, 40, 40] + heating_type: [NATURAL_GAS, NONE, NATURAL_GAS] + immigration_status: [CITIZEN, CITIZEN, UNDOCUMENTED] + ok_liheap_gross_income: [0, 0, 0] + has_heating_expense: [true, true, true] + ssi: [0, 0, 0] + output: + ok_liheap_eligible: [false, false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.yaml new file mode 100644 index 00000000000..073465c09f7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.yaml @@ -0,0 +1,104 @@ +# Oklahoma LIHEAP regular heating cases. + +# OAC 340:20-1-10(d)(3) and 340:50-5-67(a) follow SNAP alien eligibility. In January 2027 the SNAP list after +# P.L. 119-21 sec. 10108 is citizen, permanent resident and Cuban/Haitian entrant; the permanent resident has 5 +# qualified years. Refugee, asylee, withheld, parolee and conditional entrant are now ineligible, as are DACA, TPS +# and undocumented. +- name: Case 1, represented statuses follow the post July 2025 SNAP alien eligibility list. + period: 2027 + input: + state_code: [OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK] + age: [40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [CITIZEN, LEGAL_PERMANENT_RESIDENT, REFUGEE, ASYLEE, DEPORTATION_WITHHELD, CUBAN_HAITIAN_ENTRANT, + PAROLED_ONE_YEAR, CONDITIONAL_ENTRANT, DACA, TPS, UNDOCUMENTED] + years_since_us_entry: [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5] + snap_alien_qualifying_quarters: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + is_snap_lpr_in_waiting_period_exempt_category: [false, false, false, false, false, false, false, false, false, + false, false] + is_snap_alien_military_connected: [false, false, false, false, false, false, false, false, false, false, false] + is_usda_disabled: [false, false, false, false, false, false, false, false, false, false, false] + ssi: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + output: + ok_liheap_immigration_eligible: [true, true, false, false, false, true, false, false, false, false, false] + +# 7 CFR 273.4(a)(6)(iii)(A): a permanent resident needs five qualified years (years_since_us_entry approximates the +# clock): 4 -> false, 5 -> true. Parolees and conditional entrants are off the 2027 SNAP list, so false at 4 or 5 years. +- name: Case 2, five qualified years admit a permanent resident while parolees and conditional entrants stay ineligible. + period: 2027 + input: + state_code: [OK, OK, OK, OK, OK, OK] + age: [40, 40, 40, 40, 40, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [LEGAL_PERMANENT_RESIDENT, LEGAL_PERMANENT_RESIDENT, PAROLED_ONE_YEAR, PAROLED_ONE_YEAR, CONDITIONAL_ENTRANT, + CONDITIONAL_ENTRANT] + years_since_us_entry: [4, 5, 4, 5, 4, 5] + snap_alien_qualifying_quarters: [0, 0, 0, 0, 0, 0] + is_snap_lpr_in_waiting_period_exempt_category: [false, false, false, false, false, false] + is_snap_alien_military_connected: [false, false, false, false, false, false] + is_usda_disabled: [false, false, false, false, false, false] + ssi: [0, 0, 0, 0, 0, 0] + output: + ok_liheap_immigration_eligible: [false, true, false, false, false, false] + +# 7 CFR 273.4(a)(6)(ii)(A),(H),(J) waiting-period exceptions for permanent residents with 0 qualified years: under 18 +# -> true; age 18 with 39 quarters -> false; 40 quarters -> true; disability benefits -> true. The parolee with 40 +# quarters and the 17-year-old conditional entrant are off the 2027 SNAP list -> false. +- name: Case 3, permanent resident waiting period exceptions apply while parolee and conditional entrant statuses fail. + period: 2027 + input: + state_code: [OK, OK, OK, OK, OK, OK] + age: [17, 18, 18, 18, 17, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [LEGAL_PERMANENT_RESIDENT, LEGAL_PERMANENT_RESIDENT, LEGAL_PERMANENT_RESIDENT, PAROLED_ONE_YEAR, + CONDITIONAL_ENTRANT, LEGAL_PERMANENT_RESIDENT] + years_since_us_entry: [0, 0, 0, 0, 0, 0] + snap_alien_qualifying_quarters: [0, 39, 40, 40, 0, 0] + is_snap_lpr_in_waiting_period_exempt_category: [false, false, false, false, false, false] + is_snap_alien_military_connected: [false, false, false, false, false, false] + is_usda_disabled: [false, false, false, false, false, true] + ssi: [0, 0, 0, 0, 0, 0] + output: + ok_liheap_immigration_eligible: [true, false, true, false, false, true] + +# OAC 340:20-1-10(d)(3) follows SNAP, and P.L. 119-21 sec. 10108 removed refugees from 7 U.S.C. 2015(f) from +# July 2025. The annual result uses January 2027, when a refugee is not SNAP eligible -> false. +- name: Case 4, a refugee is ineligible in 2027 because Oklahoma follows the narrowed SNAP alien eligibility. + period: 2027 + input: + state_code: [OK] + age: [40] + heating_type: [NATURAL_GAS] + immigration_status: [REFUGEE] + years_since_us_entry: [0] + snap_alien_qualifying_quarters: [0] + is_usda_disabled: [false] + is_snap_alien_military_connected: [false] + is_snap_lpr_in_waiting_period_exempt_category: [false] + ssi: [0] + output: + ok_liheap_immigration_eligible: false + is_snap_immigration_status_eligible: + 2027-01: false + +# The annual result uses January. In January 2025 the pre-P.L. 119-21 SNAP list still includes refugees, who are exempt +# from the waiting period by status (7 CFR 273.4(a)(6)(ii)(B)) -> true. The SNAP list drops refugees from July 2025. +- name: Case 5, a newly arrived refugee is eligible for 2025 because January precedes the SNAP narrowing. + period: 2025 + input: + state_code: [OK] + age: [40] + heating_type: [NATURAL_GAS] + immigration_status: [REFUGEE] + years_since_us_entry: [0] + snap_alien_qualifying_quarters: [0] + is_usda_disabled: [false] + is_snap_alien_military_connected: [false] + is_snap_lpr_in_waiting_period_exempt_category: [false] + ssi: [0] + output: + ok_liheap_immigration_eligible: true + is_snap_immigration_status_eligible: + 2025-01: true + 2025-07: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.yaml new file mode 100644 index 00000000000..362d4b9636e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.yaml @@ -0,0 +1,49 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# January 6, 2026 announcement: monthly 1,696, 2,292, 2,888, 3,483, 4,079, 4,675, 5,271, 5,867, times 12. +- name: Case 1, all eight FY2026 monthly limits reproduce the official winter announcement annually. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK, OK, OK, OK, OK, OK] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS] + ok_liheap_household_size: [1, 2, 3, 4, 5, 6, 7, 8] + output: + ok_liheap_income_limit: [20_352, 27_504, 34_656, 41_796, 48_948, 56_100, 63_252, 70_404] + +# C-7 10/1/2026: monthly 1,729, 2,345, 2,960, 3,575, 4,191, 4,806, 5,421, 6,037; add 616 per person over 8: +# size 9 = 6,653 x 12, size 10 = 7,269 x 12. +- name: Case 2, FY2027 limits and separately rounded additional persons match current C7. + period: 2027 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK, OK, OK, OK, OK, OK, OK, OK] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + ok_liheap_household_size: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + output: + ok_liheap_income_limit: [20_748, 28_140, 35_520, 42_900, 50_292, 57_672, 65_052, 72_444, 79_836, 87_228] + +# FY2025 (December 17, 2024 announcement; C-7 10/1/2024): 130% of the 2024 guideline (15,060 + 5,380 per person), base +# and increment each rounded up: 1,632, 5,712, plus 583 -> 19,584, 68,544, 75,540. +- name: Case 3, FY2025 limits use the 2024 guideline and the separately rounded additional-person amount. + period: 2025 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + ok_liheap_household_size: [1, 8, 9] + output: + ok_liheap_income_limit: [19_584, 68_544, 75_540] + +# The zero-size guard gives no one-person allowance. +- name: Case 4, zero unit size receives no income limit. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK] + heating_type: [NATURAL_GAS] + ok_liheap_household_size: [0] + output: + ok_liheap_income_limit: [0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.yaml new file mode 100644 index 00000000000..030a3a9ccfe --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.yaml @@ -0,0 +1,298 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# OAC 340:20-1-11(a)-(b) (Register pp. 576-578) with the existing net business inputs: +# 12,000 + 2,400 + 600 + 0 + 1,200 = 16,200. No further 50% business deduction. +- name: Case 1, adult positive sources count without another business deduction and losses are zero. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + self_employment_income: 2_400 + sstb_self_employment_income: 600 + farm_operations_income: -1_200 + partnership_s_corp_income: 1_200 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_countable_earned_income: 16_200 + +# Incorporated SNAP rule 340:50-7-22(9) exempts elementary or high school students 17 and younger under adult control. +# K-12 explicitly true and tax dependency approximate attendance and control. +- name: Case 2, dependent elementary school earnings are excluded. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + person2: + age: 10 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + employment_income: 1_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_countable_earned_income: [12_000, 0] + +# SNAP rule 340:50-7-22(9), incorporated by Register p. 578, needs age under 18, K-12 attendance and adult control. +# Wages 6,000 + business 1,200 = 7,200 count unless all three hold; adult college is not K-12. +- name: Case 3, dependent high school student follows all three student exclusion conditions. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + person2: + age: 17 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + employment_income: 6_000 + self_employment_income: 1_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_countable_earned_income: [12_000, 0] + +# SNAP rule 340:50-7-22(9), incorporated by Register p. 578, needs age under 18, K-12 attendance and adult control. +# Wages 6,000 + business 1,200 = 7,200 count unless all three hold; adult college is not K-12. +- name: Case 4, dependent nonstudent follows all three student exclusion conditions. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + person2: + age: 17 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 6_000 + self_employment_income: 1_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_countable_earned_income: [12_000, 7_200] + +# SNAP rule 340:50-7-22(9), incorporated by Register p. 578, needs age under 18, K-12 attendance and adult control. +# Wages 6,000 + business 1,200 = 7,200 count unless all three hold; adult college is not K-12. +- name: Case 5, nondependent high school student follows all three student exclusion conditions. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + person2: + age: 17 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: true + is_disabled: false + ssi: 0 + employment_income: 6_000 + self_employment_income: 1_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_countable_earned_income: [12_000, 7_200] + +# SNAP rule 340:50-7-22(9), incorporated by Register p. 578, needs age under 18, K-12 attendance and adult control. +# Wages 6,000 + business 1,200 = 7,200 count unless all three hold; adult college is not K-12. +- name: Case 6, eighteen year old high school student follows all three student exclusion conditions. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + person2: + age: 18 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + employment_income: 6_000 + self_employment_income: 1_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_countable_earned_income: [12_000, 7_200] + +# SNAP rule 340:50-7-22(9), incorporated by Register p. 578, needs age under 18, K-12 attendance and adult control. +# Wages 6,000 + business 1,200 = 7,200 count unless all three hold; adult college is not K-12. +- name: Case 7, adult college student follows all three student exclusion conditions. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + person2: + age: 20 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 6_000 + self_employment_income: 1_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_countable_earned_income: [12_000, 7_200] + +# OAC 340:20-1-11(a)(2) counts self-employment as earned income; farm_operations_income is the existing net farm input. +# 12,000 wages + 1,200 net farm income = 13,200 (12,000 if the farm source were not listed). +- name: Case 8, positive net farm income counts as earned income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + ssi: 0 + employment_income: 12_000 + farm_operations_income: 1_200 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_countable_earned_income: 13_200 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.yaml new file mode 100644 index 00000000000..f9620579f2f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.yaml @@ -0,0 +1,194 @@ +# Oklahoma LIHEAP regular heating cases. + +# OAC 340:20-1-11(a)(2)-(4): 12,000 wages + 600 rent + 1,200 farm rent + 1,200 annual SSI = 15,000; the 2,400 pension +# stays with its recipient before deeming. SSI is monthly, but the supplied annual receipt is counted once. +- name: Case 1, person income preserves separate annual receipts before immigration deeming. + period: 2027 + input: + people: + eligible: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 1200 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 12000 + rental_income: 600 + farm_rent_income: 1200 + ineligible: + age: 35 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + pension_income: 2400 + tax_units: + tax_unit: + members: [eligible, ineligible] + spm_units: + spm_unit: + members: [eligible, ineligible] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [eligible, ineligible] + state_code: OK + output: + ok_liheap_countable_income: [15000, 2400] + +# OAC 340:20-1-11(a) counts gross Social Security; the 2,434.80 Part B premium (202.90 x 12) is only a medical deduction +# after the gross test, even when it exceeds the benefit: 1,200 + 12,000 pension = 13,200. +- name: Case 2, Social Security counts gross even when the Part B premium exceeds it. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + immigration_status: CITIZEN + is_disabled: false + ssi: 0 + social_security: 1_200 + medicare_part_b_premium: 2_434.80 + pension_income: 12_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_countable_income: 13_200 + ok_liheap_gross_income: 13_200 + +# Each unearned source is floored at zero before summing, so losses cannot offset other income: +# person1 12,000 wages + max(-6,000 rental, 0) = 12,000; person2 5,000 pension + max(-3,000 farm rent, 0) + max(-2,000 estate, 0) = 5,000. +# Gross 12,000 + 5,000 = 17,000. +- name: Case 3, rental farm rent and estate losses do not offset wages or pension income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + immigration_status: CITIZEN + is_disabled: false + ssi: 0 + employment_income: 12_000 + rental_income: -6_000 + person2: + age: 62 + immigration_status: CITIZEN + is_disabled: false + ssi: 0 + pension_income: 5_000 + farm_rent_income: -3_000 + estate_income: -2_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_countable_income: [12_000, 5_000] + ok_liheap_gross_income: 17_000 + +# Plan Section 1.9 counts retirement benefits; an IRA withdrawal enters through retirement_distributions. +# Social Security 1,000/mo (12,000) counts gross. IRA withdrawal 300/mo (3,600). Countable 12,000 + 3,600 = 15,600 +# (1,300/mo). +- name: Case 4, an IRA withdrawal counts alongside gross Social Security for a retiree. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 75 + immigration_status: CITIZEN + is_disabled: false + ssi: 0 + social_security: 12_000 + medicare_part_b_premium: 2_434.80 + taxable_ira_distributions: 3_600 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_countable_income: 15_600 + ok_liheap_gross_income: 15_600 + +# OAC 340:20-1-11(a) and 340:50-7-29(c)(3) count unemployment compensation; with none reported, +# total_unemployment_compensation uses modeled Oklahoma UI (40 O.S. 2-104, 2-106, 2-207; 2026 parameters). +# Monetary test: 28,200 >= 1,500 and 36,000 >= 1.5 x 9,936 = 14,904 -> eligible. Weekly benefit floor(9,936 / 23) = 432 +# (DOL's Oklahoma average weekly benefit, July 2024-June 2025, is 432.08). Maximum min(min(432 x 16 = 6,912, 10,384), +# 0.475 x 36,000 = 17,100) = 6,912. ok_ui = min(432 x 15 = 6,480, 6,912) = 6,480. +# Countable = gross = net = 6,480 (540/mo <= 1,696, no deductions): band 2, size 1-3, ordinary -> 265 (365 without UI). +- name: Case 5, modeled Oklahoma unemployment insurance counts as unearned income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + ssi: 0 + ok_ui_base_period_taxable_wages: 28_200 + ok_ui_base_period_total_wages: 36_000 + ok_ui_high_quarter_taxable_wages: 9_936 + ok_ui_high_quarter_total_wages: 9_936 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 15 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_ui: 6_480 + total_unemployment_compensation: 6_480 + ok_liheap_countable_income: 6_480 + ok_liheap_gross_income: 6_480 + ok_liheap_net_income: 6_480 + ok_liheap: 265 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.yaml new file mode 100644 index 00000000000..741ad524f9d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.yaml @@ -0,0 +1,611 @@ +# Oklahoma LIHEAP regular heating cases. +# Cases dated 2027 use the current Appendix C-1 need standards and Appendix C-7 earned income deduction. + +# Current OAC 340:20-1-11(a)(4); C-7 p. 1 and C-1 p. 4 IX-A. Annual 12,000 - 2,880 - 398 x 12 = 4,344 (monthly 362). +# The eligible child receives no ineligible need allowance. No second deduction in net. +- name: Case 1, one ineligible employed adult contributes after the earned and single adult need allowances. + period: 2027 + input: + people: + adult: + age: 40 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 12000 + child: + age: 10 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + tax_units: + family: + members: [adult, child] + spm_units: + spm_unit: + members: [adult, child] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [adult, child] + state_code: OK + output: + ok_liheap_deemed_income: 4344 + ok_liheap_household_size: 1 + ok_liheap_gross_income: 4344 + ok_liheap_net_income: 4344 + +# Current OAC 340:20-1-11(a)(4), C-1 p. 4 IX-A size 3 need 645. Ineligible 19,200 - 2 x 2,880 - 645 x 12 = 5,700; +# eligible 600 gives 6,300. An equal-age representative tie must not count 5,700 twice. Tax units approximate the +# claimable-dependent group. +- name: Case 2, equal age adults and their ineligible dependent contribute once as one represented group. + period: 2027 + input: + people: + adult1: + age: 40 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 12000 + adult2: + age: 40 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 6000 + ineligible_child: + age: 12 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 1200 + eligible_child: + age: 8 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 600 + tax_units: + tax_unit: + members: [adult1, adult2, ineligible_child, eligible_child] + spm_units: + spm_unit: + members: [adult1, adult2, ineligible_child, eligible_child] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [adult1, adult2, ineligible_child, eligible_child] + state_code: OK + output: + ok_liheap_deemed_income: 5700 + ok_liheap_gross_income: 6300 + ok_liheap_net_income: 6300 + ok_liheap_household_size: 1 + +# Current OAC 340:20-1-11(a)(4), C-1 p. 4: group 1 = 12,000 - 2,880 - 4,776 = 4,344; group 2 = 9,000 - 4,776 = 4,224; +# eligible adult 6,000 gives 14,568 gross. Deduct only the eligible worker's 2,880 later: 11,688 net. +- name: Case 3, separate represented tax units each use their own ineligible need allowance. + period: 2027 + input: + people: + adult1: + age: 40 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 12000 + child: + age: 8 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + adult2: + age: 35 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + pension_income: 9000 + eligible_adult: + age: 30 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 6000 + tax_units: + family1: + members: [adult1, child] + family2: + members: [adult2] + family3: + members: [eligible_adult] + spm_units: + spm_unit: + members: [adult1, child, adult2, eligible_adult] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [adult1, child, adult2, eligible_adult] + state_code: OK + output: + ok_liheap_deemed_income: [4344, 4224, 0] + ok_liheap_gross_income: 14568 + ok_liheap_net_income: 11688 + ok_liheap_household_size: 2 + +# C-1 p. 5 IX-B size 2 need 380. 6,000 - 380 x 12 = 1,440 from the child-only tax unit, not dropped because there is no +# adult tax head. Eligible 6,000 gives 7,440 gross; minus the 2,880 eligible allowance gives 4,560 net. +- name: Case 4, a child only tax unit uses the child need standard and still contributes once. + period: 2027 + input: + people: + child1: + age: 15 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 3600 + child2: + age: 10 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 2400 + adult: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 6000 + tax_units: + children: + members: [child1, child2] + adult_unit: + members: [adult] + spm_units: + spm_unit: + members: [child1, child2, adult] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [child1, child2, adult] + state_code: OK + output: + ok_liheap_deemed_income: [1440, 0] + ok_liheap_gross_income: 7440 + ok_liheap_net_income: 4560 + ok_liheap_household_size: 1 + +# C-1 p. 5 IX-B 9-or-more need 1,333. Ten ineligible children in one represented unit: 24,000 - 1,333 x 12 = 8,004. +# The eligible adult is excluded from need. No inferred additional-child increment. +- name: Case 5, the child only need standard uses its published nine or more ceiling. + period: 2027 + input: + people: + child0: + age: 17 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 24000 + child1: + age: 16 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + child2: + age: 15 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + child3: + age: 14 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + child4: + age: 13 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + child5: + age: 12 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + child6: + age: 11 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + child7: + age: 10 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + child8: + age: 9 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + child9: + age: 8 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 0 + adult: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + tax_units: + children: + members: [child0, child1, child2, child3, child4, child5, child6, child7, child8, child9] + adult_unit: + members: [adult] + spm_units: + spm_unit: + members: [child0, child1, child2, child3, child4, child5, child6, child7, child8, child9, adult] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [child0, child1, child2, child3, child4, child5, child6, child7, child8, child9, adult] + state_code: OK + output: + ok_liheap_deemed_income: [8004, 0] + ok_liheap_gross_income: 8004 + +# Current OAC 340:20-1-11(a)(4): max(3,000 - 398 x 12, 0) = 0; a fully eligible tax unit has no deemed income or need +# deduction. The eligible pension of 1,000 stays fully counted. +- name: Case 6, zero ineligible members and income below need both produce zero contribution. + period: 2027 + input: + people: + ineligible: + age: 40 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + pension_income: 3000 + eligible: + age: 35 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + pension_income: 1000 + tax_units: + unit1: + members: [ineligible] + unit2: + members: [eligible] + spm_units: + spm_unit: + members: [ineligible, eligible] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [ineligible, eligible] + state_code: OK + output: + ok_liheap_deemed_income: [0, 0] + ok_liheap_gross_income: 1000 + ok_liheap_net_income: 1000 + +# C-1 pp. 4-5 IX-A/B: child-only size 1 need 193 gives 3,600 - 2,316 = 1,284; adult size 1 need 398 gives +# max(3,600 - 4,776, 0) = 0. is_adult (age 18) approximates the schedule's adult and child groups. +- name: Case 7, a child only group uses child need until its member is an adult. + period: 2027 + input: + people: + minor: + age: 17 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 3600 + young_adult: + age: 18 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 3600 + eligible: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + tax_units: + minor_unit: + members: [minor] + adult_unit: + members: [young_adult] + eligible_unit: + members: [eligible] + spm_units: + spm_unit: + members: [minor, young_adult, eligible] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [minor, young_adult, eligible] + state_code: OK + output: + ok_liheap_deemed_income: [1284, 0, 0] + ok_liheap_gross_income: 1284 + +# C-1 1/1/2025 Schedule IX-B children only, size 2 need 380: 3,600 + 2,400 survivor benefits - 380 x 12 = 1,440 deemed. +# Gross 6,000 eligible wages + 1,440 = 7,440 (620/mo <= 1,632, the 2025 size 1 limit 19,584/yr). +# Net 7,440 - 2,880 (C-7 10/1/2024 $240 x 12) = 4,560 -> 380/mo, band 1 -> natural gas 365. +- name: Case 8, the 2025 child only need standard and earned deduction apply to a represented child only unit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 15 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 3_600 + person2: + age: 10 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + survivor_benefits: 2_400 + person3: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 6_000 + tax_units: + tax_unit1: + members: [person1, person2] + tax_unit2: + members: [person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2, person3] + state_code: OK + output: + ok_liheap_deemed_income: [1_440, 0] + ok_liheap_household_size: 1 + ok_liheap_gross_income: 7_440 + ok_liheap_income_limit: 19_584 + ok_liheap_net_income: 4_560 + ok_liheap_eligible: true + ok_liheap: 365 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.yaml new file mode 100644 index 00000000000..8872d48ece5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.yaml @@ -0,0 +1,188 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# Register income rule and FY2026 plan source categories: 12,000 + 1,200 + 2,400 + 1,200 + 2,400 = 19,200 before ordinary +# benefit deductions. +- name: Case 1, rental and survivor receipts remain separate from wages and pensions. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + rental_income: 1_200 + farm_rent_income: 2_400 + survivor_benefits: 1_200 + pension_income: 2_400 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_gross_income: 19_200 + +# Register OAC 340:20-1-11(a)-(b) ordinary regular receipts: 12,000 + 2,400 + 1,200 + 600 + 1,200 + 600 + 1,200 + 600 +# + 120 + 240 + 1,200 + 600 + 600 + 600 = 23,160. Estate and help inputs here are regular unrestricted receipts, not +# excluded nonrecurring principal. +- name: Case 2, ordinary disjoint unearned income is counted before net deductions. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 1_200 + social_security: 12_000 + unemployment_compensation: 2_400 + workers_compensation: 1_200 + disability_benefits: 600 + veterans_benefits: 600 + child_support_received: 1_200 + alimony_income: 600 + interest_income: 120 + ordinary_dividend_income: 240 + railroad_benefits: 1_200 + estate_income: 600 + financial_assistance: 600 + strike_benefits: 600 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_gross_income: 23_160 + +# 6,000 adult wages + 1,200 adult federal SSI + 1,200 child Social Security + 3,600 annual family OK TANF = 12,000. The +# school exception covers earnings, not child Social Security; monthly program receipts aggregate once. +- name: Case 3, monthly SSI and state TANF are annualized once and child unearned income remains included. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 1_200 + employment_income: 6_000 + person2: + age: 8 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + social_security: 1_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 3_600 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_gross_income: 12_000 + +# Register p. 578 incorporates program exclusions; SNAP and housing subsidy are not added to ordinary gross income. This +# does not assert categorical eligibility. +- name: Case 4, SNAP and housing assistance do not enter the gross income base. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + snap: 6_000 + housing_assistance: 6_000 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_gross_income: 12_000 + +# Same household as Case 3, but it does not take up TANF, so the take-up-gated tanf aggregate is 0 and the +# 3,600 Oklahoma TANF entitlement is not counted: 6,000 wages + 1,200 SSI + 1,200 child Social Security = 8,400. +- name: Case 5, an Oklahoma TANF entitlement the family does not take up is not counted as income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 1_200 + employment_income: 6_000 + person2: + age: 8 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + social_security: 1_200 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 3_600 + takes_up_tanf_if_eligible: false + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + tanf: 0 + ok_liheap_gross_income: 8_400 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.yaml new file mode 100644 index 00000000000..01acbbe175b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.yaml @@ -0,0 +1,62 @@ +# Oklahoma LIHEAP regular heating cases. +# Cases dated 2027 use the current Appendix C-1 need standards and Appendix C-7 earned income deduction. + +# OAC 340:20-1-11(c), C-7 p. 1: earned allowance = min(earnings, 2,880). Age 40, not disabled: 1,200 + 300 = 1,500 +# (no medical); age 60: 2,880 + 600 + 400 = 3,880; is_usda_disabled: 2,880 + 700 + 500 = 4,080. The household floor +# applies later, so person deductions may exceed income. +- name: Case 1, person deductions retain the earned cap and medical attribution before grouping. + period: 2027 + input: + state_code: [OK, OK, OK] + age: [40, 60, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [CITIZEN, CITIZEN, CITIZEN] + ok_liheap_countable_earned_income: [1200, 12000, 12000] + is_usda_disabled: [false, false, true] + other_medical_expenses: [500, 600, 700] + child_support_expense: [300, 400, 500] + output: + ok_liheap_income_deductions: [1500, 3880, 4080] + +# C-7 10/1/2024 edition: $240/mo per employed member -> 240 x 12 = 2,880/yr in 2025. +# min(12,000, 2,880) = 2,880; min(1,200, 2,880) = 1,200. Age 40 and not disabled, so no medical deduction. +- name: Case 2, the 2025 earned income deduction is two hundred forty dollars a month capped at earnings. + period: 2025 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK] + age: [40, 40] + immigration_status: [CITIZEN, CITIZEN] + is_disabled: [false, false] + ssi: [0, 0] + employment_income: [12_000, 1_200] + heating_type: [NATURAL_GAS, NATURAL_GAS] + output: + ok_liheap_countable_earned_income: [12_000, 1_200] + ok_liheap_income_deductions: [2_880, 1_200] + +# OAC 340:20-1-11(c)(1) with SNAP's list in 340:50-7-31(a)(3)(A)(v): health premiums count whether withheld through +# payroll or paid after tax. 1,440 is KFF's 2025 average worker contribution for single coverage. +# Earned allowance min(12,000, 2,880) = 2,880. Age 62 with a payroll premium: 2,880 + 1,440 = 4,320; age 62 with an +# after-tax premium: 4,320; age 40, not disabled: 2,880 only. Gross 12,000 (1,000/mo <= 1,696), all eligible. +# Net 7,680 (640/mo, band 2) -> 265; 7,680 -> 265; 9,120 (760/mo, band 3) -> 235. +- name: Case 3, payroll and after-tax health premiums of an older worker are both deductible medical expenses. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK] + age: [62, 62, 40] + immigration_status: [CITIZEN, CITIZEN, CITIZEN] + ssi: [0, 0, 0] + employment_income: [12_000, 12_000, 12_000] + pre_tax_health_insurance_premiums: [1_440, 0, 1_440] + health_insurance_premiums_without_medicare_part_b: [0, 1_440, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_200, 1_200, 1_200] + ok_tanf: [0, 0, 0] + ok_child_care_subsidies: [0, 0, 0] + ok_ccs_copay: [0, 0, 0] + output: + ok_liheap_income_deductions: [4_320, 4_320, 2_880] + ok_liheap_net_income: [7_680, 7_680, 9_120] + ok_liheap: [265, 265, 235] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.yaml new file mode 100644 index 00000000000..842bb3ab04c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.yaml @@ -0,0 +1,293 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# C-7 dated 2026-10-01: 240 monthly x 12 = 2,880 for each of two workers. 24,000 - 2,880 - 2,880 = 18,240; worker 1 has +# two sources but gets one allowance. +- name: Case 1, FY2027 earned allowance applies once per worker rather than once per source or household. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + self_employment_income: 6_000 + person2: + age: 39 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 6_000 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_gross_income: 24_000 + ok_liheap_net_income: 18_240 + +# C-7 FY2027 per-worker earned allowance limited to actual 1,200 earnings. 7,200 - min(1,200, 2,880) = 6,000; the remaining +# allowance does not reduce the pension. +- name: Case 2, FY2027 unused earned allowance cannot offset unearned income. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 1_200 + pension_income: 6_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_gross_income: 7_200 + ok_liheap_net_income: 6_000 + +# C-7 FY2027 size 1 limit 1,729 x 12 = 20,748. Gross 20,754/12 = 1,729.50 rounds half up to 1,730, above the limit; +# net 20,754 - 2,880 = 17,874 is below it. No final eligibility output is asserted. +- name: Case 3, FY2027 gross income that rounds above its monthly limit still has a lower benefit net income. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 20_754 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_gross_income: 20_754 + ok_liheap_income_limit: 20_748 + ok_liheap_net_income: 17_874 + +# Register pp. 580-581 permit age 60+ or disabled person costs. 30,000 - 2,880 worker allowance - 2,400 elder medical +# - 1,200 medical of the SSDI recipient = 23,520. Age 59 nondisabled medical 3,600 is not deductible. +- name: Case 4, FY2027 medical deduction follows each elderly or disabled person separately. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + pension_income: 12_000 + other_medical_expenses: 2_400 + person2: + age: 59 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + other_medical_expenses: 3_600 + person3: + age: 39 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: true + ssi: 0 + social_security_disability: 6_000 + other_medical_expenses: 1_200 + spm_units: + spm_unit: + members: [person1, person2, person3] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1, person2, person3] + state_code: OK + output: + ok_liheap_gross_income: 30_000 + ok_liheap_net_income: 23_520 + +# Register p. 581 and C-7 FY2027: 12,000 - 2,880 earned allowance - 1,200 support paid = 7,920. +- name: Case 5, FY2027 legally binding child support is deducted after the earned allowance. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + child_support_expense: 1_200 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_gross_income: 12_000 + ok_liheap_net_income: 7_920 + +# Earned deduction first limited to 1,200; further legally mandated support of 2,400 cannot make final net income negative. +- name: Case 6, FY2027 deductions exceeding income stop at zero. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 1_200 + child_support_expense: 2_400 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_gross_income: 1_200 + ok_liheap_net_income: 0 + +# Register p. 581 allows the OKDHS CCS copay for actual recipients. Annual copay 1,200 (100 monthly) is deducted once with +# a positive subsidy: 12,000 - 2,880 - 1,200 = 7,920. +- name: Case 7, FY2027 reported CCS copay is deducted for an actual subsidy recipient. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + person2: + age: 8 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 2_400 + ok_ccs_copay: 1_200 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_gross_income: 12_000 + ok_liheap_net_income: 7_920 + +# Register p. 581 receipt condition: with a zero CCS subsidy, a scheduled copay of 1,200 is not a deductible actual +# recipient expense. 12,000 - 2,880 = 9,120. +- name: Case 8, FY2027 calculated copay is not deducted without a subsidy receipt. + period: 2027 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + employment_income: 12_000 + person2: + age: 8 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + spm_units: + spm_unit: + members: [person1, person2] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 1_200 + households: + household: + members: [person1, person2] + state_code: OK + output: + ok_liheap_gross_income: 12_000 + ok_liheap_net_income: 9_120 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap.yaml new file mode 100644 index 00000000000..f91a4cb6946 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap.yaml @@ -0,0 +1,459 @@ +# Oklahoma LIHEAP regular heating cases. +# Cases dated 2027 use the current Appendix C-1 need standards and Appendix C-7 earned income deduction. + +# OAC 340:20-1-11(a)(4), C-1 p. 4, C-7 p. 1: 13,200 - 2,880 - 4,776 = 5,544 deemed (462/mo). +# C-7-A p. 1 ordinary fuel, size 1-3, 401-700 -> 265 despite the 10 annual bill; the schedule has no expense cap. +- name: Case 1, the ordinary mixed status heating award uses deemed net income without a bill cap. + period: 2027 + input: + people: + adult: + age: 40 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 13200 + child: + age: 10 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + tax_units: + tax_unit: + members: [adult, child] + spm_units: + spm_unit: + members: [adult, child] + heating_type: NATURAL_GAS + gas_expense: 10 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [adult, child] + state_code: OK + output: + ok_liheap_household_size: 1 + ok_liheap_gross_income: 5544 + ok_liheap_net_income: 5544 + ok_liheap_eligible: true + ok_liheap: 265 + +# C-7 p. 1: 12,000 - 2,880 = 9,120 (760/mo); C-7-A p. 1 delivered fuel, size 1-3, 701 or more -> 280. +# The 10 bill does not cap the award. +- name: Case 2, a delivered fuel household receives the published award after its earned allowance. + period: 2027 + input: + people: + adult: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 12000 + tax_units: + tax_unit: + members: [adult] + spm_units: + spm_unit: + members: [adult] + heating_type: PROPANE + gas_expense: 0 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + bottled_gas_expense: 10 + households: + household: + members: [adult] + state_code: OK + output: + ok_liheap_gross_income: 12000 + ok_liheap_net_income: 9120 + ok_liheap_eligible: true + ok_liheap: 280 + +# OAC 340:20-1-19(d) pays heat-in-rent renters and roomers only when they pay a surcharge (positive fuel bill). +# Size 1, net 0: C-7-A renter 150, roomer 70. Unsubsidized renter and roomer with no surcharge -> 0; subsidized renter +# with a 10 surcharge -> 150; subsidized renter with no surcharge -> 0. +- name: Case 3, heat in rent renters and roomers are paid only with a surcharge whether or not the rent is subsidized. + period: 2027 + input: + state_code: [OK, OK, OK, OK] + age: [40, 40, 40, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + immigration_status: [CITIZEN, CITIZEN, CITIZEN, CITIZEN] + ssi: [0, 0, 0, 0] + ok_tanf: [0, 0, 0, 0] + ok_child_care_subsidies: [0, 0, 0, 0] + ok_ccs_copay: [0, 0, 0, 0] + heat_expense_included_in_rent: [true, true, true, true] + receives_housing_assistance: [false, false, true, true] + ok_liheap_dwelling_type: [STANDARD, ROOMER, STANDARD, STANDARD] + gas_expense: [0, 0, 10, 0] + has_heating_expense: [false, false, false, false] + output: + ok_liheap_eligible: [false, false, true, false] + ok_liheap: [0, 0, 150, 0] + +# Current OAC 340:20-1-11(a)(4), (c), C-1 p. 4, C-7 p. 1: ineligible 12,000 - 2,880 - 600 medical - 1,200 support +# - 4,776 need = 2,544. Gross 2,544 + 6,000 eligible + 1,200 annual TANF = 9,744. Net 9,744 - 2,880 eligible allowance +# - 600 eligible support - 600 annual CCS copay = 5,664 = 472 monthly; C-7-A p. 1 ordinary, size 2 -> 265. +# No duplicate ineligible deductions or SPM transfers. +- name: Case 4, ineligible person deductions TANF and the household copay are each applied once. + period: 2027 + input: + people: + ineligible: + age: 60 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 12000 + other_medical_expenses: 600 + child_support_expense: 1200 + eligible: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 6000 + child_support_expense: 600 + child: + age: 8 + immigration_status: CITIZEN + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + tax_units: + tax_unit: + members: [ineligible, eligible, child] + spm_units: + spm_unit: + members: [ineligible, eligible, child] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 1200 + ok_child_care_subsidies: 2400 + ok_ccs_copay: 600 + households: + household: + members: [ineligible, eligible, child] + state_code: OK + output: + ok_liheap_deemed_income: 2544 + ok_liheap_household_size: 2 + ok_liheap_gross_income: 9744 + ok_liheap_net_income: 5664 + ok_liheap_eligible: true + ok_liheap: 265 + +# Current OAC 340:20-1-11(a)(1), (4), (c): 18,000 + 4,344 deemed = 22,344 gross exceeds the 20,748 size 1 limit. +# Net 22,344 - 2,880 = 19,464 does not restore eligibility. +- name: Case 5, deemed income enters the gross gate before the eligible worker deduction. + period: 2027 + input: + people: + eligible: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 18000 + ineligible: + age: 35 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + employment_income: 12000 + tax_units: + tax_unit: + members: [eligible, ineligible] + spm_units: + spm_unit: + members: [eligible, ineligible] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [eligible, ineligible] + state_code: OK + output: + ok_liheap_deemed_income: 4344 + ok_liheap_household_size: 1 + ok_liheap_gross_income: 22344 + ok_liheap_income_limit: 20748 + ok_liheap_net_income: 19464 + ok_liheap_eligible: false + ok_liheap: 0 + +# Current OAC 340:20-1-10 and C-7-A p. 1 ordinary fuel, size 1, 0 net -> 365. Outside OK or explicit NONE gives 0; +# no cooling/crisis award substituted. +- name: Case 6, the final award applies state and no heating gates. + period: 2027 + input: + state_code: [OK, TX, OK] + age: [40, 40, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS, NONE] + immigration_status: [CITIZEN, CITIZEN, CITIZEN] + has_heating_expense: [true, true, true] + gas_expense: [1, 1, 1] + ssi: [0, 0, 0] + ok_tanf: [0, 0, 0] + ok_child_care_subsidies: [0, 0, 0] + ok_ccs_copay: [0, 0, 0] + output: + ok_liheap: [365, 0, 0] + +# OAC 340:20-1-11(a), (c): Social Security counts gross in the income test; the Part B premium is a medical deduction +# (340:50-7-31(a)(3)(A)(vi)) taken only after it. Both retirees: 21,360/12 = 1,780 > 1,696 (2026 size 1 limit 20,352) -> 0. +# Net income: person 1 deducts 202.90 x 12 = 2,434.80 -> 18,925.20; person 2 pays no premium -> 21,360. +- name: Case 7, Social Security counts gross in the income test and the Part B premium does not restore eligibility. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK] + age: [70, 70] + immigration_status: [CITIZEN, CITIZEN] + ssi: [0, 0] + social_security: [21_360, 21_360] + medicare_part_b_premium: [2_434.80, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_200, 1_200] + ok_tanf: [0, 0] + ok_child_care_subsidies: [0, 0] + ok_ccs_copay: [0, 0] + output: + ok_liheap_countable_income: [21_360, 21_360] + ok_liheap_gross_income: [21_360, 21_360] + ok_liheap_income_limit: [20_352, 20_352] + ok_liheap_eligible: [false, false] + ok_liheap_net_income: [18_925.20, 21_360] + ok_liheap: [0, 0] + +# Military retirement pay is a separate input from pension_income and counts as unearned income. +# 24,000/12 = 2,000 > 1,696 (2026 size 1 limit) -> ineligible, 0. +# 12,000/12 = 1,000 <= 1,696 -> eligible; no deductions, net 1,000/mo is band 3 -> natural gas 235. +- name: Case 8, military retirement pay counts toward the gross limit and the payment band. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK] + age: [62, 62] + immigration_status: [CITIZEN, CITIZEN] + ssi: [0, 0] + military_retirement_pay: [24_000, 12_000] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_200, 1_200] + ok_tanf: [0, 0] + ok_child_care_subsidies: [0, 0] + ok_ccs_copay: [0, 0] + output: + ok_liheap_countable_income: [24_000, 12_000] + ok_liheap_gross_income: [24_000, 12_000] + ok_liheap_eligible: [false, true] + ok_liheap_net_income: [24_000, 12_000] + ok_liheap: [0, 235] + +# OAC 340:20-1-11(a) rounds monthly income to the nearest dollar; 2026 size 1 limit is 1,696/mo (20,352/yr). +# Wages 20,355/12 = 1,696.25 -> 1,696 <= 1,696, eligible; net 20,355 - 2,880 = 17,475 -> 1,456.25 -> 1,456, band 3 -> 235. +# Wages 20,358/12 = 1,696.50 -> rounds half up to 1,697 > 1,696 -> ineligible, 0 (net 20,358 - 2,880 = 17,478). +- name: Case 9, monthly gross income within fifty cents of the limit rounds to the nearest dollar before the test. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK] + age: [40, 40] + immigration_status: [CITIZEN, CITIZEN] + ssi: [0, 0] + employment_income: [20_355, 20_358] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_200, 1_200] + ok_tanf: [0, 0] + ok_child_care_subsidies: [0, 0] + ok_ccs_copay: [0, 0] + output: + ok_liheap_gross_income: [20_355, 20_358] + ok_liheap_income_limit: [20_352, 20_352] + ok_liheap_eligible: [true, false] + ok_liheap_net_income: [17_475, 17_478] + ok_liheap: [235, 0] + +# OAC 340:20-1-19(d)(1)-(2): heat-in-rent renters and roomers who pay a verified surcharge are paid. A 300 surcharge +# ($50 a month in six high-usage months) is the positive primary fuel bill. Size 1, net 0 -> C-7-A renter 150, +# roomer 70. The responsibility flag with no surcharge bill does not qualify -> ineligible, 0 (matrix still 150). +- name: Case 10, a surcharge bill pays unsubsidized heat in rent renters and roomers but the responsibility flag alone + does not. + period: 2027 + input: + state_code: [OK, OK, OK] + age: [40, 40, 40] + immigration_status: [CITIZEN, CITIZEN, CITIZEN] + ssi: [0, 0, 0] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + heat_expense_included_in_rent: [true, true, true] + ok_liheap_dwelling_type: [STANDARD, ROOMER, STANDARD] + gas_expense: [300, 300, 0] + has_heating_expense: [false, false, true] + ok_tanf: [0, 0, 0] + ok_child_care_subsidies: [0, 0, 0] + ok_ccs_copay: [0, 0, 0] + output: + ok_liheap_eligible: [true, true, false] + ok_liheap_matrix_amount: [150, 70, 150] + ok_liheap: [150, 70, 0] + +# OAC 340:20-1-11(c)(1) with OAC 340:50-7-31(a)(3)(A)(v)-(vi): a member 60+ deducts Medicare and health premiums. +# A member 60+ deducts the whole 2026 Part B premium after the gross test: 202.90 x 12 = 2,434.80. +# Pension 750/mo (9,000) -> gross 750/mo <= 1,696 (2026 size 1 limit), eligible. +# Net 9,000 - 2,434.80 = 6,565.20 -> 547.10/mo rounds to 547, band 2 (401-700) -> natural gas 265. +- name: Case 11, a retiree deducts the full Medicare Part B premium after the gross income test. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + immigration_status: CITIZEN + is_disabled: false + ssi: 0 + social_security: 0 + medicare_part_b_premium: 2_434.80 + pension_income: 9_000 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_countable_income: 9_000 + ok_liheap_gross_income: 9_000 + ok_liheap_income_deductions: 2_434.80 + ok_liheap_eligible: true + ok_liheap_net_income: 6_565.20 + ok_liheap: 265 + +# OAC 340:20-1-11(a), (c): Social Security 1,000/mo counts gross, so countable income = 12,000 (1,000/mo <= 1,696), +# eligible. Deductions after the gross test = 1,800 Medigap (150/mo) + 2,434.80 Part B (202.90 x 12) = 4,234.80. +# Net 12,000 - 4,234.80 = 7,765.20 -> 647.10/mo rounds to 647, band 2 (401-700) -> natural gas 265. +- name: Case 12, a retiree with Social Security deducts the Part B premium and another health premium after the gross + test. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + immigration_status: CITIZEN + is_disabled: false + ssi: 0 + social_security: 12_000 + medicare_part_b_premium: 2_434.80 + health_insurance_premiums_without_medicare_part_b: 1_800 + spm_units: + spm_unit: + members: [person1] + heating_type: NATURAL_GAS + gas_expense: 1_200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [person1] + state_code: OK + output: + ok_liheap_countable_income: 12_000 + ok_liheap_gross_income: 12_000 + ok_liheap_income_deductions: 4_234.80 + ok_liheap_eligible: true + ok_liheap_net_income: 7_765.20 + ok_liheap: 265 + +# OAC 340:20-1-11(c)(1) and 340:50-5-4 (7 CFR 271.2): a member under 60 is "considered disabled" only with a qualifying +# disability benefit. SSA's 2026 average disabled-worker benefit is 1,630/mo (19,560/yr). +# Person 1 receives SSDI, so is_usda_disabled: gross 19,560 (1,630/mo <= 1,696), deducts 1,200 medical -> net 18,360 +# (1,530/mo), band 3 -> 235. Person 2 reports a disability but receives no qualifying benefit: gross 19,560 wages, eligible; +# only the 2,880 earned allowance -> net 16,680 (1,390/mo), band 3 -> 235. +- name: Case 13, Social Security disability receipt qualifies a member under 60 for the medical deduction. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK] + age: [50, 50] + immigration_status: [CITIZEN, CITIZEN] + ssi: [0, 0] + is_disabled: [false, true] + social_security_disability: [19_560, 0] + employment_income: [0, 19_560] + other_medical_expenses: [1_200, 1_200] + heating_type: [NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_200, 1_200] + ok_tanf: [0, 0] + ok_child_care_subsidies: [0, 0] + ok_ccs_copay: [0, 0] + output: + is_usda_disabled: [true, false] + ok_liheap_income_deductions: [1_200, 2_880] + ok_liheap_gross_income: [19_560, 19_560] + ok_liheap_eligible: [true, true] + ok_liheap_net_income: [18_360, 16_680] + ok_liheap: [235, 235] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap_household_size.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap_household_size.yaml new file mode 100644 index 00000000000..426e283c3c9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap_household_size.yaml @@ -0,0 +1,118 @@ +# Oklahoma LIHEAP regular heating cases. + +# OAC 340:20-1-10(h)(3) excludes ineligible members from the income standard and the benefit size. In January 2027 +# only the citizen qualifies: the refugee is off the narrowed SNAP list, the permanent resident has 4 of 5 qualified +# years, and the child is undocumented -> size 1. +- name: Case 1, only the qualified members enter the financial and payment household size. + period: 2027 + input: + people: + citizen: + age: 40 + immigration_status: CITIZEN + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + refugee: + age: 35 + immigration_status: REFUGEE + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 1 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + recent_lpr: + age: 30 + immigration_status: LEGAL_PERMANENT_RESIDENT + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 4 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + child: + age: 10 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + tax_units: + tax_unit: + members: [citizen, refugee, recent_lpr, child] + spm_units: + spm_unit: + members: [citizen, refugee, recent_lpr, child] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [citizen, refugee, recent_lpr, child] + state_code: OK + output: + ok_liheap_immigration_eligible: [true, false, false, false] + ok_liheap_household_size: 1 + +# Current OAC 340:20-1-10(h)(3) requires at least one eligible member; zero size has no one-person income allowance. +- name: Case 2, a household without any qualified member has zero size and is ineligible. + period: 2027 + input: + people: + adult: + age: 40 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: false + is_in_k12_school: false + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + child: + age: 10 + immigration_status: UNDOCUMENTED + is_tax_unit_dependent: true + is_in_k12_school: true + is_disabled: false + ssi: 0 + years_since_us_entry: 5 + snap_alien_qualifying_quarters: 0 + is_snap_lpr_in_waiting_period_exempt_category: false + is_snap_alien_military_connected: false + tax_units: + tax_unit: + members: [adult, child] + spm_units: + spm_unit: + members: [adult, child] + heating_type: NATURAL_GAS + gas_expense: 1200 + ok_tanf: 0 + ok_child_care_subsidies: 0 + ok_ccs_copay: 0 + households: + household: + members: [adult, child] + state_code: OK + output: + ok_liheap_household_size: 0 + ok_liheap_income_limit: 0 + ok_liheap_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.yaml new file mode 100644 index 00000000000..86c04d3343e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.yaml @@ -0,0 +1,119 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# C-7-A p. 1 and the matching FY2026 matrix, 36 literal cells: 4 tables x 3 monthly bands x 3 size groups. The fixed +# matrix has no bill cap. Heat in rent with an unknown fuel uses the all-fuels tables; roomer 4+ zeros are retained. +# Ungated amount only. +- name: Case 1, all thirty six winter matrix cells match including explicit roomer zeros. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, + OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS, NATURAL_GAS, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, PROPANE, + PROPANE, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, + UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, + UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] + heat_expense_included_in_rent: [false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true] + ok_liheap_dwelling_type: [STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, + STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, + STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, STANDARD, ROOMER, + ROOMER, ROOMER, ROOMER, ROOMER, ROOMER, ROOMER, ROOMER, ROOMER] + ok_liheap_net_income: [0, 0, 0, 4_812, 4_812, 4_812, 8_412, 8_412, 8_412, 0, 0, 0, 4_812, 4_812, 4_812, + 8_412, 8_412, 8_412, 0, 0, 0, 4_812, 4_812, 4_812, 8_412, 8_412, 8_412, 0, 0, 0, 4_812, 4_812, 4_812, + 8_412, 8_412, 8_412] + ok_liheap_household_size: [1, 4, 7, 1, 4, 7, 1, 4, 7, 1, 4, 7, 1, 4, 7, 1, 4, 7, 1, 4, 7, 1, 4, 7, 1, 4, 7, 1, + 4, 7, 1, 4, 7, 1, 4, 7] + output: + ok_liheap_matrix_amount: [365, 402, 430, 265, 292, 312, 235, 259, 277, 425, 468, 500, 350, 385, 412, + 280, 308, 330, 150, 165, 180, 110, 120, 135, 100, 110, 125, 70, 0, 0, 50, 0, 0, 40, 0, 0] + +# C-7-A bands start at $0, $401 and $701; OAC 340:20-1-11(a) rounds monthly income to the nearest dollar (half up). +# Annual net /12 = 0, 400, 400.01, 400.49, 400.50, 400.99, 401, 700, 700.01, 700.49, 700.50, 700.99, 701 +# -> rounded 0, 400, 400, 400, 401, 401, 401, 700, 700, 700, 701, 701, 701 -> size 1 ordinary 365 (band 1), 265 (band 2), 235 (band 3). +- name: Case 2, monthly net income rounds half up to the nearest dollar before the four hundred one and seven + hundred one band starts. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, + NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + ok_liheap_household_size: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + ok_liheap_net_income: [0, 4_800, 4_800.12, 4_805.88, 4_806, 4_811.88, 4_812, 8_400, 8_400.12, 8_405.88, 8_406, + 8_411.88, 8_412] + output: + ok_liheap_matrix_amount: [365, 365, 365, 365, 265, 265, 265, 265, 265, 265, 235, 235, 235] + +# C-7-A ordinary fuel, monthly 500 row: sizes 1-3 -> 265, 4-6 -> 292, 7+ -> 312. +- name: Case 3, household group boundaries three four six and seven use the correct column. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK, OK] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + ok_liheap_household_size: [3, 4, 6, 7] + ok_liheap_net_income: [6_000, 6_000, 6_000, 6_000] + output: + ok_liheap_matrix_amount: [265, 292, 292, 312] + +# C-7-A headers explicitly map ordinary gas, electricity, wood and coal and delivered LP gas, oil and kerosene. ROOMER +# changes only the heat-in-rent schedule; direct fuel rows remain unchanged. +- name: Case 4, all seven priced direct fuels retain their source group even for a roomer dwelling. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK, OK, OK, OK, OK] + heating_type: [NATURAL_GAS, ELECTRICITY, WOOD, COAL, PROPANE, FUEL_OIL, KEROSENE] + ok_liheap_dwelling_type: [ROOMER, ROOMER, ROOMER, ROOMER, ROOMER, ROOMER, ROOMER] + heat_expense_included_in_rent: [false, false, false, false, false, false, false] + ok_liheap_household_size: [1, 1, 1, 1, 1, 1, 1] + ok_liheap_net_income: [0, 0, 0, 0, 0, 0, 0] + output: + ok_liheap_matrix_amount: [365, 365, 365, 365, 425, 425, 425] + +# C-7-A all-energy-sources heat-in-rent tables give 150 standard / 70 roomer at zero income, size 1. Explicit NONE has no +# heat; an unknown fuel is permitted for heat in rent. No final housing eligibility assertion. +- name: Case 5, heat in rent is fuel neutral for standard renters and roomers but explicit no heat returns + zero. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK] + heating_type: [UNSPECIFIED, UNSPECIFIED, NONE] + heat_expense_included_in_rent: [true, true, true] + ok_liheap_dwelling_type: [STANDARD, ROOMER, STANDARD] + ok_liheap_household_size: [1, 1, 1] + ok_liheap_net_income: [0, 0, 0] + output: + ok_liheap_matrix_amount: [150, 70, 0] + +# The matrix guards zero size and state; it does not assert mixed-status deeming or final eligibility. +- name: Case 6, zero household size and out of state residence receive no Oklahoma matrix amount. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, TX] + heating_type: [NATURAL_GAS, NATURAL_GAS] + ok_liheap_household_size: [0, 1] + ok_liheap_net_income: [0, 0] + output: + ok_liheap_matrix_amount: [0, 0] + +# C-7-A prices only natural gas, electricity, wood and coal (ordinary) and propane, fuel oil and kerosene (delivered). +# Paid directly (heat not in rent), OTHER, SOLAR and UNSPECIFIED have no priced column -> 0. +# Natural gas control: size 1, net 0 -> band 1 ordinary 365. +- name: Case 7, unpriced direct heating fuels receive no matrix amount while natural gas is paid. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK, OK] + heating_type: [OTHER, SOLAR, UNSPECIFIED, NATURAL_GAS] + heat_expense_included_in_rent: [false, false, false, false] + ok_liheap_dwelling_type: [STANDARD, STANDARD, STANDARD, STANDARD] + ok_liheap_household_size: [1, 1, 1, 1] + ok_liheap_net_income: [0, 0, 0, 0] + output: + ok_liheap_matrix_amount: [0, 0, 0, 365] diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.py new file mode 100644 index 00000000000..7a9a415c080 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.py @@ -0,0 +1,61 @@ +from policyengine_us.model_api import * + + +class ok_liheap_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Eligible for Oklahoma LIHEAP regular heating assistance" + defined_for = StateCode.OK + # OAC 340:20-1-10(c)-(h), 340:20-1-11(a), 340:20-1-19(d): eligible size, + # gross income including deemed contributions, and heating responsibility. + reference = ( + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + "https://liheapch.acf.gov/docs/2026/state-plans/OK_Plan_2026.pdf#page=9", + ) + + def formula(spm_unit, period, parameters): + size = spm_unit("ok_liheap_household_size", period) + # OAC 340:20-1-11(a) converts income to a monthly amount and rounds it + # to the nearest dollar; Appendix C-7 prints whole-dollar monthly + # limits. Rounding the monthly total half up approximates the + # per-source rounding. + income = spm_unit("ok_liheap_gross_income", period) + monthly_income = np.floor(income / MONTHS_IN_YEAR + 0.5) + monthly_limit = spm_unit("ok_liheap_income_limit", period) / MONTHS_IN_YEAR + fuel = spm_unit("heating_type", period) + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + # OAC 340:20-1-19(d)(1) pays "renters, roomers, and boarders who pay a + # surcharge for utilities included in their rent", and 340:20-1-19(d)(2) + # and 340:20-1-13(2)(B)-(C) verify "the surcharge" by a landlord + # statement, a lease, or "a rent receipt designating that the fuel cost + # is separate from the total shelter payment". 340:20-1-10(h) denies + # households that do not verify responsibility for energy costs. The + # FY2026 plan, item 2.3 (page 9), agrees: heat-in-rent renters "must + # verify that a specific portion of the rent is for utilities or be + # charged a surcharge". A positive primary fuel bill represents that + # charge for every heat-in-rent renter or roomer, subsidized or not; + # the flag alone does not. + # NOTE: 340:20-1-10(c) counts "undesignated payments for energy in the + # form of rent", and 340:20-1-10(f)(3) names only "subsidized + # households whose heating or cooling costs are included in the rent" + # as non-vulnerable. Reading those to pay an unsubsidized renter with + # no surcharge is not followed: (c) defines the household unit and + # (f) lists examples. + # Directly billed OTHER and SOLAR fuels have no Appendix C-7-A column + # (solar is not an approved main energy source under 340:20-1-10(b)(1)); + # they stay eligible with a $0 matrix amount, a documented coverage + # limit. UNSPECIFIED carries no bill, so a heat-in-rent household with + # an unknown fuel is paid $0 (default fuel: #9754). + has_bill = spm_unit("heating_expense", period) > 0 + # A direct obligation may be reported with the flag; it represents the + # household's remaining cost after any utility allowance. + pays_directly = ~heat_in_rent & spm_unit("has_heating_expense", period) + # Roomer relatedness, shared-meter/institutional facts, and tribal + # LIHEAP receipt are not available as existing inputs. + return ( + (size > 0) + & (monthly_income <= monthly_limit) + & (fuel != fuel.possible_values.NONE) + & (has_bill | pays_directly) + ) diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.py new file mode 100644 index 00000000000..994d10ab1a4 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class ok_liheap_immigration_eligible(Variable): + value_type = bool + entity = Person + definition_period = YEAR + label = "Meets Oklahoma LIHEAP citizenship and immigration requirements" + defined_for = StateCode.OK + reference = ( + # OAC 340:20-1-10(d) and 340:50-5-67(a). + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + "https://www.ecfr.gov/current/title-7/section-273.4", + "https://www.govinfo.gov/content/pkg/PLAW-119publ21/html/PLAW-119publ21.htm", + ) + + def formula(person, period, parameters): + # OAC 340:20-1-10(d)(3) admits "an alien who is both qualified and + # eligible, per OAC 340:50-67". That cites the SNAP rule 340:50-5-67(a): + # "Per Section 273.4 of Title 7 of the Code of Federal Regulations ... + # to be eligible for food benefits a person must be:" the same four + # categories as 340:20-1-10(d)(1)-(4). LIHEAP therefore follows SNAP + # alien eligibility, including P.L. 119-21 sec. 10108, which limits + # 7 U.S.C. 2015(f) to citizens and nationals, permanent residents, + # Cuban and Haitian entrants and COFA residents from July 2025. + # NOTE: The eCFR text of 7 CFR 273.4(a)(6) still lists refugees and + # asylees; reading that unamended text would keep them eligible. + # Noncitizen nationals and 273.4(a)(3)-(5) groups have no status value. + # Annual eligibility uses the first month's circumstances. + return person("is_snap_immigration_status_eligible", period.first_month) diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.py new file mode 100644 index 00000000000..3da403ab4b4 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.py @@ -0,0 +1,45 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class ok_liheap_income_limit(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP annualized income limit" + defined_for = StateCode.OK + reference = ( + "https://oklahoma.gov/okdhs/newsroom/2024/december/comm12172024.html", + "https://oklahoma.gov/okdhs/newsroom/2026/january/comm01062026.html", + "https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ok.dhs.liheap.income.limit + size = spm_unit("ok_liheap_household_size", period) + capped_size = clip(size, 1, p.max_table_size) + state_group = spm_unit.household("state_group_str", period) + guideline = fpg( + capped_size, state_group, period, parameters, year_lag=p.fpg_year_lag + ) + additional_guideline = ( + fpg( + capped_size + 1, + state_group, + period, + parameters, + year_lag=p.fpg_year_lag, + ) + - guideline + ) + monthly_base = guideline * p.fpg_rate / MONTHS_IN_YEAR + monthly_increment = additional_guideline * p.fpg_rate / MONTHS_IN_YEAR + # Ceiling the base and increment separately reconciles the published + # FY2025-FY2027 limits and additional-person amounts in Appendix C-7. + rounding = p.rounding_increment + rounded_base = np.ceil(monthly_base / rounding) * rounding + rounded_increment = np.ceil(monthly_increment / rounding) * rounding + extra_people = max_(size - p.max_table_size, 0) + monthly_limit = rounded_base + extra_people * rounded_increment + return where(size > 0, monthly_limit * MONTHS_IN_YEAR, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.py new file mode 100644 index 00000000000..6f1a75f2898 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class ok_liheap_countable_earned_income(Variable): + value_type = float + entity = Person + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP gross countable earned income" + defined_for = StateCode.OK + reference = ( + # OAC 340:20-1-11(a)-(b), effective September 15, 2025. + # PDF pages 576-578 + "https://oklahoma.gov/content/dam/ok/en/omma/content/rulemaking-process/rules/Register_Volume-42_Issue-20.pdf#page=576", + # OAC 340:50-7-22(9), incorporated SNAP student earnings exclusion. + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ok.dhs.liheap.income + income = 0 + for source in p.sources.earned: + income = income + max_(person(source, period), 0) + # Existing net business inputs replace gross receipts; do not apply + # an additional 50% business deduction or introduce work expenses. + # K-12 attendance defaults to an overridable age-based imputation. + # Tax dependency approximates parental control; exact control + # relationships and federal student-work programs are not modeled. + exempt_student = ( + (person("age", period) < p.student_earned_income_age_limit) + & person("is_in_k12_school", period) + & person("is_tax_unit_dependent", period) + ) + return where(exempt_student, 0, income) diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.py new file mode 100644 index 00000000000..942ab1e7d3f --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class ok_liheap_countable_income(Variable): + value_type = float + entity = Person + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP countable personal income before deductions" + defined_for = StateCode.OK + # OAC 340:20-1-11(a)-(b). The same personal sources apply before + # ordinary eligibility and before ineligible-member income deeming. + reference = ( + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + # Section 1.9 of the FY2025, FY2026 and FY2027 plans. + "https://liheapch.acf.gov/docs/2025/state-plans/OK_Plan_2025.pdf#page=6", + "https://liheapch.acf.gov/docs/2026/state-plans/OK_Plan_2026.pdf#page=6", + "https://oklahoma.gov/content/dam/ok/en/okdhs/documents/okdhs-pdf-library/adult-and-family-services/DETAILED%20MODEL%20PLAN%2010_01_2026.pdf#page=6", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ok.dhs.liheap.income.sources + income = person("ok_liheap_countable_earned_income", period) + # Each source is floored at zero, so a loss in one source cannot + # offset another. + for source in p.unearned: + # SSI is monthly; ADD annualizes it exactly once here. Other + # listed streams are disjoint annual personal income inputs. + income = income + max_(add(person, period, [source], options=[ADD]), 0) + # TANF is an SPM aggregate and is counted separately once. + return income diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.py new file mode 100644 index 00000000000..799041761f2 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.py @@ -0,0 +1,43 @@ +from policyengine_us.model_api import * + + +class ok_liheap_deemed_income(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP income deemed from ineligible tax unit members" + defined_for = StateCode.OK + reference = ( + # OAC 340:20-1-11(a)(4): contribution after personal deductions and + # need enters eligible members' income before the gross test. + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + # Schedule IX-A and IX-B. + # PDF pages 4-5 + "https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-1.pdf#page=4", + ) + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.ok.dhs + person = tax_unit.members + ineligible = ~person("ok_liheap_immigration_eligible", period) + size = tax_unit.sum(ineligible) + income = tax_unit.sum(person("ok_liheap_countable_income", period) * ineligible) + deductions = tax_unit.sum( + person("ok_liheap_income_deductions", period) * ineligible + ) + # Tax-unit membership within the SPM unit represents the ineligible + # adult(s) and their co-resident, tax-claimable ineligible dependents. + # Actual claiming, multiple possible claimants and separate returns + # can differ. Spouses count as adults, not as tax dependents. Eligible + # members never enlarge this need group or contribute income here. + # Existing is_adult (age 18+) approximates the schedule distinction. + has_adult = tax_unit.any(person("is_adult", period) & ineligible) + lookup_size = max_(size, 1) + monthly_need = where( + has_adult, + p.tanf.income.need_standard.calc(lookup_size), + p.liheap.income.deeming.child_only_need_standard.calc(lookup_size), + ) + need = where(size > 0, monthly_need * MONTHS_IN_YEAR, 0) + return max_(income - deductions - need, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.py new file mode 100644 index 00000000000..c1715618d93 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.py @@ -0,0 +1,35 @@ +from policyengine_us.model_api import * + + +class ok_liheap_gross_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP gross income including deemed contributions" + defined_for = StateCode.OK + reference = ( + # OAC 340:20-1-11(a)(4), (b): deeming precedes the gross test. + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + # Section 1.9 counts TANF benefits. + "https://liheapch.acf.gov/docs/2026/state-plans/OK_Plan_2026.pdf#page=6", + ) + + def formula(spm_unit, period, parameters): + person = spm_unit.members + eligible = person("ok_liheap_immigration_eligible", period) + eligible_income = spm_unit.sum( + person("ok_liheap_countable_income", period) * eligible + ) + # Select one representative per tax unit, including all-child units. + # The tax-law head flag excludes children and would lose those groups. + representative = person.get_rank(person.tax_unit, -person("age", period)) == 0 + deemed_income = spm_unit.sum( + person.tax_unit("ok_liheap_deemed_income", period) * representative + ) + # The annual tanf aggregate includes ok_tanf and applies take-up; + # ok_tanf alone is the monthly entitlement and would count benefits + # a nonrecipient could get. Count the cash aggregate once; existing + # inputs do not allocate it to individual recipients. + tanf = spm_unit("tanf", period) + return max_(eligible_income + deemed_income + tanf, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.py new file mode 100644 index 00000000000..0a4451b0858 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.py @@ -0,0 +1,40 @@ +from policyengine_us.model_api import * + + +class ok_liheap_income_deductions(Variable): + value_type = float + entity = Person + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP personal income deductions" + defined_for = StateCode.OK + reference = ( + # OAC 340:20-1-11(a)(4), (c), 340:50-5-4 and 340:50-7-31(a)(3)(A)(v)-(vi): + # these person deductions apply to ineligible-member deeming and + # eligible members' net income. + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + "https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7.pdf", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ok.dhs.liheap.income.deductions + earned = person("ok_liheap_countable_earned_income", period) + # Annualization assumes earnings and expenses are spread over the + # year. An unused earned allowance cannot offset unearned income. + earned_deduction = min_(earned, p.earned_income * MONTHS_IN_YEAR) + # OAC 340:20-1-11(c)(1) deducts medical expenses of members 60 or older + # or "considered disabled, per OAC 340:50-5-4", which adopts the 7 CFR + # 271.2 benefit-receipt test. Categories with no input ((a)(3)-(5) and + # (a)(10)-(11), such as government disability retirement and interim + # assistance) are not modeled. + medical_eligible = (person("age", period) >= p.medical_age_threshold) | person( + "is_usda_disabled", period + ) + # Allowable expenses follow SNAP's list in 340:50-7-31(a)(3)(A), without + # its $35 threshold: health premiums paid after tax or through payroll, + # the whole Medicare Part B premium, and other medical costs. + medical_expenses = max_(person("snap_allowable_medical_expenses", period), 0) + medical_deduction = medical_expenses * medical_eligible + child_support = person("child_support_expense", period) + # The SPM-level actual CCS copay is deducted separately once. + return earned_deduction + medical_deduction + child_support diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.py new file mode 100644 index 00000000000..659048d3d96 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class ok_liheap_net_income(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP net income for regular heating assistance" + defined_for = StateCode.OK + reference = ( + # OAC 340:20-1-11(a)(4), (c): do not repeat deductions already + # applied to ineligible members before the gross-income test. + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + ) + + def formula(spm_unit, period, parameters): + person = spm_unit.members + gross_income = spm_unit("ok_liheap_gross_income", period) + eligible = person("ok_liheap_immigration_eligible", period) + personal_deductions = spm_unit.sum( + person("ok_liheap_income_deductions", period) * eligible + ) + receives_subsidy = spm_unit("ok_child_care_subsidies", period) > 0 + copay = spm_unit("ok_ccs_copay", period, options=[ADD]) + # The SPM copay has no payer attribution. Deduct it once at net, + # without assigning it to an ineligible tax unit before the gross + # test. Gross income can be overstated when that person paid it. + childcare_deduction = where(receives_subsidy, copay, 0) + return max_(gross_income - personal_deductions - childcare_deduction, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap.py new file mode 100644 index 00000000000..08eb2e7b64f --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ok_liheap(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP regular heating assistance" + defined_for = StateCode.OK + reference = ( + # OAC 340:20-1-10(i)(1), 340:20-1-11(d). + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + "https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + eligible = spm_unit("ok_liheap_eligible", period) + amount = spm_unit("ok_liheap_matrix_amount", period) + # The regular heating matrix has no actual-expense cap. Unsupported + # direct fuels and the published roomer 4+ zero remain in the matrix. + return eligible * amount diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap_household_size.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap_household_size.py new file mode 100644 index 00000000000..305d3b73072 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap_household_size.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class ok_liheap_household_size(Variable): + value_type = int + entity = SPMUnit + definition_period = YEAR + label = "Oklahoma LIHEAP eligible household size" + defined_for = StateCode.OK + # OAC 340:20-1-10(h)(3): exclude ineligible aliens from both the + # financial standard and benefit size; their income follows deeming. + reference = "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html" + # SPM membership represents the economic unit sharing heating costs. + # SSN furnishing/application and shared-meter household facts are + # not represented by the available inputs. + adds = ["ok_liheap_immigration_eligible"] diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_dwelling_type.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_dwelling_type.py new file mode 100644 index 00000000000..2697508df0d --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_dwelling_type.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class OKLIHEAPDwellingType(Enum): + STANDARD = "Standard dwelling" + ROOMER = "Roomer" + + +class ok_liheap_dwelling_type(Variable): + value_type = Enum + entity = SPMUnit + possible_values = OKLIHEAPDwellingType + default_value = OKLIHEAPDwellingType.STANDARD + definition_period = YEAR + label = "Oklahoma LIHEAP dwelling type" + defined_for = StateCode.OK + reference = "https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1" diff --git a/policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.py new file mode 100644 index 00000000000..c93e02fc80a --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.py @@ -0,0 +1,60 @@ +from policyengine_us.model_api import * + + +class ok_liheap_matrix_amount(Variable): + value_type = float + entity = SPMUnit + definition_period = YEAR + unit = USD + label = "Oklahoma LIHEAP winter heating matrix amount" + defined_for = StateCode.OK + reference = ( + # OAC 340:20-1-11(a), (d). + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + "https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1", + "https://liheapch.acf.gov/docs/2026/benefits-matricies/OK_BenefitMatrix_2026.docx", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ok.dhs.liheap.payment + size = spm_unit("ok_liheap_household_size", period) + # OAC 340:20-1-11(a) rounds monthly income to the nearest dollar, and + # Appendix C-7-A prints whole-dollar bands, so round half up first. + net_income = spm_unit("ok_liheap_net_income", period) + monthly_income = np.floor(net_income / MONTHS_IN_YEAR + 0.5) + band = p.income_band.calc(max_(monthly_income, 0)).astype(int) + size_group = p.household_size_group.calc(max_(size, 1)).astype(int) + fuel = spm_unit("heating_type", period) + fuels = fuel.possible_values + ordinary_fuel = ( + (fuel == fuels.NATURAL_GAS) + | (fuel == fuels.ELECTRICITY) + | (fuel == fuels.WOOD) + | (fuel == fuels.COAL) + ) + delivered_fuel = ( + (fuel == fuels.PROPANE) + | (fuel == fuels.FUEL_OIL) + | (fuel == fuels.KEROSENE) + ) + direct_payment = select( + [ordinary_fuel, delivered_fuel], + [p.matrix.ordinary[band][size_group], p.matrix.delivered[band][size_group]], + # OTHER, SOLAR and UNSPECIFIED have no supported direct-payment + # mapping. Zero is an unverified estimate, not a legal denial. + default=0, + ) + dwelling = spm_unit("ok_liheap_dwelling_type", period) + roomer = dwelling == dwelling.possible_values.ROOMER + rent_payment = where( + roomer, + p.matrix.roomer[band][size_group], + p.matrix.renter[band][size_group], + ) + # Heat-in-rent schedules cover every fuel. Eligibility separately needs + # a positive surcharge bill, which an unknown fuel cannot carry. + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + amount = where(heat_in_rent, rent_payment, direct_payment) + # The matrix has no actual-expense cap. Gross eligibility and heating + # responsibility are applied by the final award variable. + return where((size > 0) & (fuel != fuels.NONE), amount, 0)