From d76ee1995862c4dc1757f8c2bb8a4f9a768eef30 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sat, 3 Oct 2026 19:49:21 -0400 Subject: [PATCH 1/6] Add OK regular heating LIHEAP --- changelog.d/ok-liheap.added.md | 1 + .../eligible_immigration_statuses.yaml | 25 + .../income/deductions/earned_income.yaml | 22 + .../deductions/medical_age_threshold.yaml | 11 + .../deeming/child_only_need_standard.yaml | 53 ++ .../ok/dhs/liheap/income/limit/fpg_rate.yaml | 15 + .../dhs/liheap/income/limit/fpg_year_lag.yaml | 17 + .../liheap/income/limit/max_table_size.yaml | 13 + .../income/limit/rounding_increment.yaml | 16 + .../ok/dhs/liheap/income/sources/earned.yaml | 21 + .../dhs/liheap/income/sources/unearned.yaml | 42 ++ .../student_earned_income_age_limit.yaml | 16 + .../liheap/payment/household_size_group.yaml | 26 + .../ok/dhs/liheap/payment/income_band.yaml | 28 + .../dhs/liheap/payment/matrix/delivered.yaml | 42 ++ .../dhs/liheap/payment/matrix/ordinary.yaml | 42 ++ .../ok/dhs/liheap/payment/matrix/renter.yaml | 42 ++ .../ok/dhs/liheap/payment/matrix/roomer.yaml | 42 ++ policyengine_us/programs.yaml | 9 +- .../eligibility/ok_liheap_eligible.yaml | 66 +++ .../ok_liheap_immigration_eligible.yaml | 77 +++ .../eligibility/ok_liheap_income_limit.yaml | 51 ++ .../ok_liheap_countable_earned_income.yaml | 266 +++++++++ .../income/ok_liheap_countable_income.yaml | 51 ++ .../income/ok_liheap_deemed_income.yaml | 537 ++++++++++++++++++ .../liheap/income/ok_liheap_gross_income.yaml | 143 +++++ .../income/ok_liheap_income_deductions.yaml | 17 + .../liheap/income/ok_liheap_net_income.yaml | 287 ++++++++++ .../gov/states/ok/dhs/liheap/ok_liheap.yaml | 248 ++++++++ .../dhs/liheap/ok_liheap_household_size.yaml | 117 ++++ .../payment/ok_liheap_matrix_amount.yaml | 110 ++++ .../liheap/eligibility/ok_liheap_eligible.py | 40 ++ .../ok_liheap_immigration_eligible.py | 32 ++ .../eligibility/ok_liheap_income_limit.py | 45 ++ .../ok_liheap_countable_earned_income.py | 32 ++ .../income/ok_liheap_countable_income.py | 23 + .../liheap/income/ok_liheap_deemed_income.py | 42 ++ .../liheap/income/ok_liheap_gross_income.py | 31 + .../income/ok_liheap_income_deductions.py | 35 ++ .../dhs/liheap/income/ok_liheap_net_income.py | 30 + .../gov/states/ok/dhs/liheap/ok_liheap.py | 22 + .../ok/dhs/liheap/ok_liheap_household_size.py | 18 + .../liheap/payment/ok_liheap_dwelling_type.py | 17 + .../liheap/payment/ok_liheap_matrix_amount.py | 55 ++ 44 files changed, 2874 insertions(+), 1 deletion(-) create mode 100644 changelog.d/ok-liheap.added.md create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/eligibility/eligible_immigration_statuses.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/earned_income.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/medical_age_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deeming/child_only_need_standard.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/max_table_size.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/rounding_increment.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/earned.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/unearned.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/income/student_earned_income_age_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/household_size_group.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/income_band.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/delivered.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/ordinary.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/renter.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/matrix/roomer.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap_household_size.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.yaml create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap_household_size.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_dwelling_type.py create mode 100644 policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.py 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/eligibility/eligible_immigration_statuses.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/eligibility/eligible_immigration_statuses.yaml new file mode 100644 index 00000000000..d2d57f4cc67 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/eligibility/eligible_immigration_statuses.yaml @@ -0,0 +1,25 @@ +description: Oklahoma allows these represented citizenship and immigration statuses, subject to the incorporated qualified-alien waiting rule, under the Low Income Home Energy Assistance Program. +# The current OAC incorporates 7 CFR 273.4, whose FY2026/FY2027 text is +# unchanged. SNAP's later statutory status exclusions are not applied here. +# The model lacks precise enum categories for noncitizen nationals and +# several special eligible groups; their absence is an input limitation. +values: + 2025-09-15: + - CITIZEN + - LEGAL_PERMANENT_RESIDENT + - REFUGEE + - ASYLEE + - DEPORTATION_WITHHELD + - CUBAN_HAITIAN_ENTRANT + - PAROLED_ONE_YEAR + - CONDITIONAL_ENTRANT + +metadata: + unit: list + period: year + label: Oklahoma LIHEAP represented eligible immigration statuses + reference: + - title: OAC 340:20-1-10(d) and 340:50-5-67(a), current Title 340 + href: https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html + - title: 7 CFR 273.4(a), citizenship and alien status + href: https://www.ecfr.gov/current/title-7/section-273.4 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..a09a2f62590 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/earned_income.yaml @@ -0,0 +1,22 @@ +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. +# Quest operational guidance updated August 12, 2026 states $240 per worker; +# this is the earliest recovered evidence date, not a proven policy start. +# C-7 independently confirms $240 effective October 1, 2026. Earlier periods, +# including annual 2026 evaluated at January 1, remain backfilled estimates. +values: + 2026-08-12: 240 + 2026-10-01: 240 + +metadata: + unit: currency-USD + period: month + label: Oklahoma LIHEAP monthly earned income deduction + reference: + - title: Quest LIHEAP Eligibility - Income, Income deductions, updated August 12, 2026 + href: https://fsquest.oucpm.org/2022/programs/liheap-ecap/eligibility-income/ + - title: OKDHS Appendix C-7, Earned income deduction + 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..f79e4c1db2f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deductions/medical_age_threshold.yaml @@ -0,0 +1,11 @@ +description: Oklahoma allows medical expense deductions beginning at this age or for a qualifying disabled member 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..e1dab24c365 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deeming/child_only_need_standard.yaml @@ -0,0 +1,53 @@ +description: Oklahoma protects this monthly need amount for a represented children-only ineligible group before deeming its income 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. Earlier years are backfilled +# estimates; this observed schedule is effective July 1, 2026. +brackets: + - threshold: + 2026-07-01: 1 + amount: + 2026-07-01: 193 + - threshold: + 2026-07-01: 2 + amount: + 2026-07-01: 380 + - threshold: + 2026-07-01: 3 + amount: + 2026-07-01: 535 + - threshold: + 2026-07-01: 4 + amount: + 2026-07-01: 691 + - threshold: + 2026-07-01: 5 + amount: + 2026-07-01: 830 + - threshold: + 2026-07-01: 6 + amount: + 2026-07-01: 974 + - threshold: + 2026-07-01: 7 + amount: + 2026-07-01: 1_098 + - threshold: + 2026-07-01: 8 + amount: + 2026-07-01: 1_219 + - threshold: + 2026-07-01: 9 + amount: + 2026-07-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, effective July 1, 2026 + 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..6e4a3878411 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_rate.yaml @@ -0,0 +1,15 @@ +description: Oklahoma limits gross income to this multiple of the federal poverty guideline under the Low Income Home Energy Assistance Program. +values: + 2025-10-01: 1.3 + +metadata: + unit: /1 + period: year + label: Oklahoma LIHEAP federal poverty guideline rate + reference: + - 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/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..705cadae938 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_year_lag.yaml @@ -0,0 +1,17 @@ +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 FY2026/FY2027 published charts reconcile to 2025/2026 guidelines. +# Earlier years use the requested guideline year, but are unverified. +values: + 2025-10-01: 1 + +metadata: + unit: year + period: year + label: Oklahoma LIHEAP federal poverty guideline year lag + reference: + - 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..dc88b695dd5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/max_table_size.yaml @@ -0,0 +1,13 @@ +description: Oklahoma publishes monthly income limits through this household size before adding a separate additional-person amount under the Low Income Home Energy Assistance Program. +values: + 2025-10-01: 8 + +metadata: + unit: person + period: year + label: Oklahoma LIHEAP maximum income table size + reference: + - 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 + 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..dcdd4e3be03 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/rounding_increment.yaml @@ -0,0 +1,16 @@ +description: Oklahoma publishes monthly income limits in increments of this amount under the Low Income Home Energy Assistance Program. +# Ceiling the base and each extra-person amount separately matches both +# published charts and the FY2027 $616 additional-person amount. The FY2026 +# $596 extension is inferred; the announcement prints only sizes 1-8. +values: + 2025-10-01: 1 + +metadata: + unit: currency-USD + period: month + label: Oklahoma LIHEAP monthly income limit rounding increment + reference: + - 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/sources/earned.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/earned.yaml new file mode 100644 index 00000000000..e7433598002 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/earned.yaml @@ -0,0 +1,21 @@ +description: Oklahoma counts these earned income sources for fully qualified households under the Low Income Home Energy Assistance Program. +# Use existing net business inputs without a further 50% business-expense +# deduction or new expense input. Passive versus active partnership income +# is not distinguishable with existing input data. +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 + 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://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22 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..41a33a508ec --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/sources/unearned.yaml @@ -0,0 +1,42 @@ +description: Oklahoma counts these unearned income sources for fully qualified households 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. +# Pension income includes military pensions. military_retirement_pay is a +# tax classification and is not independently added. State SSP receipts are +# not modeled; SSI is federal, and OK TANF is added once at SPMUnit level. +values: + 2025-09-15: + - unemployment_compensation + - strike_benefits + - social_security + - ssi + - pension_income + - 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 + 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://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22 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..0cd0463362b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/student_earned_income_age_limit.yaml @@ -0,0 +1,16 @@ +description: Oklahoma excludes earned income of secondary-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. Tax dependency approximates control; +# separate elementary attendance and excluded training income are unavailable. +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://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22 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..2eaf956cafb --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/household_size_group.yaml @@ -0,0 +1,26 @@ +description: Oklahoma assigns this payment group based on household size 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..c39d3178aeb --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/income_band.yaml @@ -0,0 +1,28 @@ +description: Oklahoma assigns this payment band based on net monthly income under the Low Income Home Energy Assistance Program. +# Printed lower bounds are inclusive; retained cents remain in the lower +# band until income reaches 401 or 701. +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 756dc2c4988..efe93493a63 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -802,8 +802,15 @@ programs: category: Benefits agency: HHS status: partial - coverage: OR, DC, Riverside County, MA, IL, KS, MS, TX + coverage: OK, OR, DC, Riverside County, MA, IL, KS, MS, 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 + notes: Regular winter assistance using the published FY2026 matrix and current income rules. The $240 earned allowance is directly supported for FY2027; earlier backfill and payment carry-forward are unverified. Mixed-status deeming uses documented tax-unit grouping and incorporated-CFR immigration rules. Missing case facts and deduction attribution remain input limitations; no complete-year verification is claimed. Crisis, cooling, weatherization and equipment assistance are excluded. - state: OR status: in_progress name: 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..9ec80899254 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.yaml @@ -0,0 +1,66 @@ +# Source-derived Oklahoma ordinary heating cases under contract v1.3. +# Current C1 need and C7 earned amounts are tested in2027. + +# Current340:20-1-10(h)(2), C7p1:1person1729*12=20748 inclusive gross ceiling. Current ordinary program has no asset test. +- name: Case 1, the ordinary gross ceiling is inclusive and assets do not change it. + period: 2027 + input: + state_code: [OK, OK] + age: [40, 40] + heating_type: [NATURAL_GAS, NATURAL_GAS] + immigration_status: [CITIZEN, CITIZEN] + ok_liheap_gross_income: [20748, 20749] + has_heating_expense: [true, true] + bank_account_assets: [1000000, 1000000] + ssi: [0, 0] + output: + ok_liheap_income_limit: [20748, 20748] + ok_liheap_eligible: [true, false] + +# Current340:20-1-10(e)-(h): unsubsidized included heat qualifies; subsidized included heat requires verified surcharge, modeled by positive primary heating expense. Explicit responsibility cannot bypass zero surcharge. Public housing is a subsidy proxy. +- name: Case 2, subsidized heat in rent needs a positive excess charge despite a responsibility flag. + 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: [true, false, false, true, false] + +# Current340:20-1-10(e),(h)(1) includes total or partial responsibility. Direct obligation may be reported with 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] + +# Current340: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..5a03900804b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.yaml @@ -0,0 +1,77 @@ +# Source-derived Oklahoma ordinary heating cases under contract v1.3. +# Current C1 need and C7 earned amounts are tested in2027. + +# Current OAC340:20-1-10(d) incorporates340:50-5-67 and7CFR273.4(a)(6). All represented qualified categories at5years qualify; DACA/TPS/undocumented do not independently satisfy it. Missing enum categories remain outside this test. +- name: Case 1, represented statuses follow the incorporated qualified alien categories. + 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, true, true, true, true, true, true, false, false, false] + +# 7CFR273.4(a)(6)(iii)(A),(B),(D): five qualified years; years_since_us_entry is the existing qualified-status-clock approximation. +- name: Case 2, five years satisfies the waiting period for each subject status. + 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, true, false, true] + +# 7CFR273.4(a)(6)(ii)(A),(H),(J): under18 exemption, LPR40quarters exception (not parolee40), and benefit-based disability exemption. Age18 with39quarters and0qualifiedyears fails. +- name: Case 3, child quarters and benefit based disability exceptions retain their distinct conditions. + 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, true, true] + +# Current OAC incorporation and7CFR273.4(a)(6)(ii)(B) allow refugee status without waiting. P.L.119-21sec10108 separately narrows7USC2015(f) SNAP. Expected LIHEAPtrue derives from incorporated text, not the SNAP result. +- name: Case 4, a refugee remains eligible under the incorporated rule despite the separate SNAP statutory restriction. + 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: true + is_snap_immigration_status_eligible: + 2027-01: 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..3a784ced0cb --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/eligibility/ok_liheap_income_limit.yaml @@ -0,0 +1,51 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# Jan6,2026 officialannouncement monthly[1696,2292,2888,3483,4079,4675,5271,5867], multipliedby12. No FY2027 amounts mixed into2026. +- 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] + gas_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200] + 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] + +# C7effective2026-10-01 monthly[1729,2345,2960,3575,4191,4806,5421,6037]; add616perperson over8. Annualizeonce;size9=6653*12 and10=7269*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] + gas_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200] + 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] + +# Unverified2025 estimate uses2024FPG15060,size8=52720,increment5380. Monthlyceil at130% gives1632,5712 andextra583;annual19584,68544,75540. Does not verify historical fullprogram. +- name: Case 3, historical backfill uses its own prior year federal guideline and rounded increment. + period: 2025 + absolute_error_margin: 0.01 + input: + state_code: [OK, OK, OK] + heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_200, 1_200, 1_200] + ok_liheap_household_size: [1, 8, 9] + output: + ok_liheap_income_limit: [19_584, 68_544, 75_540] + +# Zero-size guard has no one-person allowance; normal cases represent fullyqualifiedhouseholds. +- 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] + gas_expense: [1_200] + 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..744f48e718c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.yaml @@ -0,0 +1,266 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# Register pp576-578 and approved existing-net-input convention:12000+2400+600+0+1200=16200. No second legal50% business deduction is applied. +- 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 SNAP340:50-7-22(9) exempts elementary or high-school students17andunder underadultcontrol. K12 explicitlytrue and taxdependency approximate attendance/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] + +# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +- 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 + is_full_time_student: true + 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] + +# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +- 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 + is_full_time_student: false + 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] + +# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +- 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 + is_full_time_student: true + 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] + +# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +- 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 + is_full_time_student: true + 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] + +# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +- 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 + is_full_time_student: true + 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] 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..909d9e123cc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.yaml @@ -0,0 +1,51 @@ +# Source-derived Oklahoma ordinary heating cases under contract v1.3. +# Current C1 need and C7 earned amounts are tested in2027. + +# Current340:20-1-11(a)(2)-(4):12000wages+600rent+1200farmrent+1200annualSSI=15000;2400pension 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] 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..3a4700540e0 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.yaml @@ -0,0 +1,537 @@ +# Source-derived Oklahoma ordinary heating cases under contract v1.3. +# Current C1 need and C7 earned amounts are tested in2027. + +# Current340:20-1-11(a)(4); C7p1 and C1p4 IX-A. Annual12000-2880-398*12=4344 (monthly362). 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 + +# Current340:20-1-11(a)(4), C1p4 IX-A size3need645. Ineligible19200-2*2880-645*12=5700; eligible600 gives6300. Equal-age representative tie must not count5700 twice. Tax-unit grouping is the documented approximation. +- 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 + +# Current340:20-1-11(a)(4), C1p4: group1=12000-2880-4776=4344; group2=9000-4776=4224; eligible adult6000 gives14568gross. Deduct only eligible worker2880 later:11688net. +- 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 + +# C1p5 IX-B size2need380.6000-380*12=1440 from child-only taxunit, not dropped because there is no adult tax head. Eligible6000 gives7440gross; minus2880eligible allowance gives4560net. +- 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 + +# C1p5 IX-B9-or-more need1333. Ten ineligible children in one represented unit:24000-1333*12=8004. 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 + +# Current340:20-1-11(a)(4): max(3000-398*12,0)=0; fully eligible taxunit has no deemed income or need deduction. Eligible pension1000 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 + +# C1pp4-5 IX-A/B: child-only1need193 gives3600-2316=1284; adult1need398 givesmax(3600-4776,0)=0. Existing is_adult age18 is the contracted schedule-classification approximation. +- 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 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..e485b681ad6 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.yaml @@ -0,0 +1,143 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# Register income rule and FY2026 plan source categories:12000+1200+2400+1200+2400=19200 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 + +# Register340:20-1-11(a)-(b) ordinary regular receipts:12000+2400+1200+600+1200+600+1200+600+120+240+1200+600+600+600=23160. Estate/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 + +# 6000 adult wages+1200 adult federalSSI+1200 childSSA+3600 annual familyOKTANF=12000. The school exception covers earnings, not childSSA; monthlyprogram 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 + +# Registerp578 incorporates program exclusions; SNAP and housing subsidy are not added to ordinary grossincome. 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 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..9ac9c12e1a9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.yaml @@ -0,0 +1,17 @@ +# Source-derived Oklahoma ordinary heating cases under contract v1.3. +# Current C1 need and C7 earned amounts are tested in2027. + +# Current340:20-1-11(c), C7p1: earned allowance=min(earnings,2880). First1200+300=1500 (age40nondisabledmedical excluded); second2880+600+400=3880; third2880+700+500=4080. Household floor is applied 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_disabled: [false, false, true] + other_medical_expenses: [500, 600, 700] + child_support_expense: [300, 400, 500] + output: + ok_liheap_income_deductions: [1500, 3880, 4080] 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..c19ef99adf7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_net_income.yaml @@ -0,0 +1,287 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# C7 dated2026-10-01:240monthly*12=2880 for each of two workers.24000-2880-2880=18240; worker1 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 + +# C7 FY2027 per-worker earned allowance limited to actual1200 earnings.7200-min(1200,2880)=6000; remaining allowance does not reduce 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 + +# C7 FY2027 size1 limit1729*12=20748. Gross20749 stays above it; net20749-2880=17869. No finaleligibility output is asserted. +- name: Case 3, FY2027 gross income remains above its limit even when benefit net income is below. + 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_749 + 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_749 + ok_liheap_income_limit: 20_748 + ok_liheap_net_income: 17_869 + +# Registerpp580-581 permits age60+ or disabled person costs.30000-2880 workerallowance-2400 eldermedical-1200 disabledmedical=23520. Age59 nondisabled medical3600 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: 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 + +# Registerp581 and C7FY2027:12000-2880 earnedallowance-1200 supportpaid=7920. +- 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 to1200; further legallymandated support2400 cannot make finalnetincome 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 + +# Registerp581 allowsOKDHSCCS copay for actualrecipients. Annualcopay1200 (100monthly) is deductedonce withpositivesubsidy:12000-2880-1200=7920. +- 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 + +# Registerp581 receipt condition: withzeroCCSsubsidy, a scheduledcopay1200 is not a deductibleactualrecipient expense.12000-2880=9120. +- 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..8c41debc714 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap.yaml @@ -0,0 +1,248 @@ +# Source-derived Oklahoma ordinary heating cases under contract v1.3. +# Current C1 need and C7 earned amounts are tested in2027. + +# Current340:20-1-11(a)(4), C1p4/C7p1:13200-2880-4776=5544=462monthly. C7Ap1 ordinaryfuel,size1-3,401-700=>265 despite10annual bill. Regular heating schedule has no actual-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 + +# C7p1 allowance12000-2880=9120=760monthly; C7Ap1 deliveredfuel,size1-3,701orhigher pays280. The10primary bill does not cap the ordinary scheduled 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 + +# Current340:20-1-10(f)-(g) plus C7Ap1:0net,size1 renter150,roomer70; subsidizedpositive surcharge retains150, zero surcharge ineligible. Roomer written-agreement fact is assumed under documented input limitation. +- name: Case 3, renter roomer and subsidized surcharge routes link eligibility to their heating schedules. + 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: [true, true, true, false] + ok_liheap: [150, 70, 150, 0] + +# Current340:20-1-11(a)(4),(c), C1p4/C7p1: ineligible12000-2880-600medical-1200support-4776need=2544. Gross2544+6000eligible+1200annualTANF=9744. Net9744-2880eligibleallowance-600eligiblesupport-600annualCCScopay=5664=472monthly; C7Ap1 ordinary,size2=>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 + +# Current340:20-1-11(a)(1),(4),(c):18000+4344deemed=22344gross exceeds20748size1limit. Net22344-2880=19464 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 + +# Current340:20-1-10 and C7Ap1 ordinaryfuel,size1,0net=>365. OutsideOK or explicitNONE gives0; 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] 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..c487a5bd19e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/ok_liheap_household_size.yaml @@ -0,0 +1,117 @@ +# Source-derived Oklahoma ordinary heating cases under contract v1.3. +# Current C1 need and C7 earned amounts are tested in2027. + +# Current340:20-1-10(h)(3): exclude ineligible members for both financial standard and benefit. Two of four members qualify; child status is still required. +- 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, true, false, false] + ok_liheap_household_size: 2 + +# Current340: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..c7875963b6c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.yaml @@ -0,0 +1,110 @@ +# Oklahoma independent fully qualified household components; no final eligibility or award is asserted. + +# C7A p1 and matchingFY2026matrix literal36cells:4tables*3monthlybands*3sizegroups. Directbill10 doesnotcapfixedmatrix. HIRunknownfuel is supportedallfuels;roomer4+ zerosretained. Ungatedamountonly. +- 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] + gas_expense: [10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + 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] + bottled_gas_expense: [0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + 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] + +# C7Amonthlylowerbounds0,401,701. Annualvalues represent0,400,400.01,400.99,401,700,700.01,700.99,701; fractional convention keepscurrentbanduntilnextprintedlowerbound. +- name: Case 2, printed monthly lower bounds preserve fractional cents until four hundred one and seven + hundred one. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: [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] + gas_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200] + ok_liheap_household_size: [1, 1, 1, 1, 1, 1, 1, 1, 1] + ok_liheap_net_income: [0, 4_800, 4800.12, 4811.88, 4_812, 8_400, 8400.12, 8411.88, 8_412] + output: + ok_liheap_matrix_amount: [365, 365, 365, 365, 265, 265, 265, 265, 235] + +# C7A ordinaryfuelmonthly500 row: sizes1-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] + gas_expense: [1_200, 1_200, 1_200, 1_200] + 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] + +# C7Aheaders explicitlymap ordinarygas/electricity/wood/coal anddeliveredLPG/oil/kerosene. ROOMERchangesonlyheat-in-rentschedule; directfuelrowsremainunchanged. +- 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] + gas_expense: [10, 0, 0, 0, 0, 0, 0] + 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] + pre_subsidy_electricity_expense: [0, 10, 0, 0, 0, 0, 0] + wood_expense: [0, 0, 10, 0, 0, 0, 0] + coal_expense: [0, 0, 0, 10, 0, 0, 0] + bottled_gas_expense: [0, 0, 0, 0, 10, 0, 0] + fuel_oil_expense: [0, 0, 0, 0, 0, 10, 10] + output: + ok_liheap_matrix_amount: [365, 365, 365, 365, 425, 425, 425] + +# C7A allenergysourcesHIRtables give150standard/70roomer atzero income,size1. ExplicitNONE hasnoheat; unknownfuelpermittedHIR. No finalhousingeligibility 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] + gas_expense: [0, 0, 0] + 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] + +# Matrix guardszero size and state; doesnotassertmixedstatusdeemingorfinaleligibility. +- 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] + gas_expense: [1_200, 1_200] + ok_liheap_household_size: [0, 1] + ok_liheap_net_income: [0, 0] + output: + ok_liheap_matrix_amount: [0, 0] 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..013de7da3e1 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_eligible.py @@ -0,0 +1,40 @@ +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): eligible size, gross income + # including deemed contributions, and responsibility for heating costs. + reference = "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html" + + def formula(spm_unit, period, parameters): + size = spm_unit("ok_liheap_household_size", period) + income = spm_unit("ok_liheap_gross_income", period) + income_limit = spm_unit("ok_liheap_income_limit", period) + fuel = spm_unit("heating_type", period) + heat_in_rent = spm_unit("heat_expense_included_in_rent", period) + expense = spm_unit("heating_expense", period) + has_expense = spm_unit("has_heating_expense", period) + subsidized = spm_unit.household("is_in_public_housing", period) | spm_unit( + "receives_housing_assistance", period + ) + # Housing flags proxy income-based rent. A positive heating expense + # represents a verified surcharge when subsidized heat is in rent; + # the general responsibility flag alone cannot satisfy that branch. + rent_responsibility = ~subsidized | (expense > 0) + # Direct expenses represent the remaining household obligation after + # a utility allowance, rather than a fully reimbursed gross bill. + direct_responsibility = has_expense | (expense > 0) + responsibility = where(heat_in_rent, rent_responsibility, direct_responsibility) + # Written roomer agreements, exact shared-meter/institutional facts, + # and tribal LIHEAP receipt are not available as existing inputs. + return ( + (size > 0) + & (income <= income_limit) + & (fuel != fuel.possible_values.NONE) + & responsibility + ) 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..0a935fa2be9 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/eligibility/ok_liheap_immigration_eligible.py @@ -0,0 +1,32 @@ +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 = ( + # Current OAC 340:20-1-10(d) incorporates 340:50-5-67(a), which + # expressly references 7 CFR 273.4. The printed citation omits 5. + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + "https://www.ecfr.gov/current/title-7/section-273.4", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ok.dhs.liheap.eligibility + status = person("immigration_status", period).decode_to_str() + allowed_status = np.isin(status, p.eligible_immigration_statuses) + # Reuse the incorporated CFR waiting rule independently of SNAP's + # additional post-OBBB statutory status exclusions. The retrieved + # FY2026/FY2027 CFR text retains refugee/asylee eligibility. No + # LIHEAP instruction extending SNAP's new exclusions was found. + waiting_period = person( + "meets_snap_qualified_alien_waiting_period", period.first_month + ) + # Annual eligibility uses the first month's circumstances. Existing + # waiting-rule proxies and missing enum categories (including + # noncitizen nationals, trafficking and battered-alien categories) + # remain input limitations; no new immigration input is introduced. + return allowed_status & waiting_period 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..3a74a08e4d3 --- /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/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 published + # FY2026/FY2027 limits. FY2026's $596 additional-person amount is a + # reconciled extension; the announcement only prints sizes 1-8. + 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..c63734110d9 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_earned_income.py @@ -0,0 +1,32 @@ +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), PDF pages 576-578, effective September 15, 2025. + "https://oklahoma.gov/content/dam/ok/en/omma/content/rulemaking-process/rules/Register_Volume-42_Issue-20.pdf#page=576", + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22", + ) + + 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..99807e2e362 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.py @@ -0,0 +1,23 @@ +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" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ok.dhs.liheap.income.sources + income = person("ok_liheap_countable_earned_income", period) + 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) + # Oklahoma 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..83726c59fa5 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.py @@ -0,0 +1,42 @@ +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, physical 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..61bd42c285f --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.py @@ -0,0 +1,31 @@ +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", + ) + + 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 + ) + # Oklahoma TANF is SPMUnit/MONTH. Count the cash aggregate once; + # existing inputs do not allocate it to individual recipients. + tanf = spm_unit("ok_tanf", period, options=[ADD]) + 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..7ceafc658dd --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/income/ok_liheap_income_deductions.py @@ -0,0 +1,35 @@ +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): 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) + medical_eligible = (person("age", period) >= p.medical_age_threshold) | person( + "is_disabled", period + ) + # is_disabled approximates the incorporated SNAP disability test. + # Use the existing nonpremium aggregate without overlapping detailed + # medical inputs; Medicare/premium treatment remains deferred. + medical_deduction = ( + max_(person("other_medical_expenses", period), 0) * 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..e636c3d9088 --- /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", + ) + + 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..6172fcd6bb8 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap_household_size.py @@ -0,0 +1,18 @@ +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" + + def formula(spm_unit, period, parameters): + # SPM membership represents the economic unit sharing heating costs. + # SSN furnishing/application and shared-meter household facts are + # not represented by the available inputs. + return spm_unit.sum(spm_unit.members("ok_liheap_immigration_eligible", period)) 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..c055c3bc980 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/payment/ok_liheap_matrix_amount.py @@ -0,0 +1,55 @@ +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 = ( + "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) + monthly_income = spm_unit("ok_liheap_net_income", period) / MONTHS_IN_YEAR + # Keep cents until the printed next lower bound: $401 or $701. + 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, including an unknown fuel. + 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) From fb59116484976020ffce881284ceeca7b555ee09 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 4 Oct 2026 20:17:40 -0400 Subject: [PATCH 2/6] Clarify OK LIHEAP coverage limitations --- policyengine_us/programs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index efe93493a63..1abe8a660f3 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -810,7 +810,7 @@ programs: full_name: Oklahoma Low Income Home Energy Assistance Program variable: ok_liheap parameter_prefix: gov.states.ok.dhs.liheap - notes: Regular winter assistance using the published FY2026 matrix and current income rules. The $240 earned allowance is directly supported for FY2027; earlier backfill and payment carry-forward are unverified. Mixed-status deeming uses documented tax-unit grouping and incorporated-CFR immigration rules. Missing case facts and deduction attribution remain input limitations; no complete-year verification is claimed. Crisis, cooling, weatherization and equipment assistance are excluded. + notes: Regular winter assistance using the published FY2026 matrix and current income rules. The $240 earned allowance is sourced from October 2026 and the child-only need table from July 2026; earlier operation is unverified. FY2026 income limits above size 8 and unlisted direct-fuel payments remain unverified. Mixed-status grouping and deduction attribution use documented existing-input approximations. Historical backfill and payment carry-forward do not establish a completely verified award year. Crisis, cooling, weatherization and equipment assistance are excluded. - state: OR status: in_progress name: LIHEAP From 39a3ee329cfbc21a88042935c997943a00deabd0 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 6 Oct 2026 18:21:11 -0400 Subject: [PATCH 3/6] Fix Oklahoma LIHEAP income counting from review - Count Social Security net of the Medicare Part B premium, floored per person (FY2025-FY2027 plans section 1.9). - Count military retirement pay; correct the pension comment. - Count TANF through the take-up-gated tanf variable instead of ok_tanf. - Round monthly income half up to the dollar before the gross test and the band lookup (OAC 340:20-1-11). - Date the $240 earned-income deduction from 10/1/2024 and the child-only need standard from 1/1/2025, the earliest official editions. - Follow SNAP's noncitizen rule, as OAC 340:20-1-10(d)(3) directs through 340:50-5-67, by reusing is_snap_immigration_status_eligible (narrowed by P.L. 119-21 from July 2025). - Require a utility surcharge for heat-in-rent renters and roomers (OAC 340:20-1-19(d), plan item 2.3), proxied by a positive heating expense. - Set verified_years to 2025-2027 and shorten the programs.yaml note. - Add and update tests for each change. Co-Authored-By: Claude Opus 5.5 --- .../eligible_immigration_statuses.yaml | 25 ---- .../income/deductions/earned_income.yaml | 15 +-- .../deeming/child_only_need_standard.yaml | 44 +++---- .../dhs/liheap/income/limit/fpg_year_lag.yaml | 4 +- .../income/limit/rounding_increment.yaml | 6 +- .../dhs/liheap/income/sources/unearned.yaml | 14 ++- .../ok/dhs/liheap/payment/income_band.yaml | 4 +- policyengine_us/programs.yaml | 5 +- .../eligibility/ok_liheap_eligible.yaml | 36 +++--- .../ok_liheap_immigration_eligible.yaml | 52 +++++++-- .../income/ok_liheap_countable_income.yaml | 70 +++++++++++ .../income/ok_liheap_deemed_income.yaml | 66 +++++++++++ .../liheap/income/ok_liheap_gross_income.yaml | 40 +++++++ .../income/ok_liheap_income_deductions.yaml | 17 +++ .../liheap/income/ok_liheap_net_income.yaml | 11 +- .../gov/states/ok/dhs/liheap/ok_liheap.yaml | 109 +++++++++++++++++- .../dhs/liheap/ok_liheap_household_size.yaml | 8 +- .../payment/ok_liheap_matrix_amount.yaml | 40 +++++-- .../liheap/eligibility/ok_liheap_eligible.py | 57 +++++---- .../ok_liheap_immigration_eligible.py | 32 +++-- .../eligibility/ok_liheap_income_limit.py | 5 +- .../income/ok_liheap_countable_income.py | 22 +++- .../liheap/income/ok_liheap_gross_income.py | 10 +- .../income/ok_liheap_income_deductions.py | 3 +- .../liheap/payment/ok_liheap_matrix_amount.py | 11 +- 25 files changed, 539 insertions(+), 167 deletions(-) delete mode 100644 policyengine_us/parameters/gov/states/ok/dhs/liheap/eligibility/eligible_immigration_statuses.yaml diff --git a/policyengine_us/parameters/gov/states/ok/dhs/liheap/eligibility/eligible_immigration_statuses.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/eligibility/eligible_immigration_statuses.yaml deleted file mode 100644 index d2d57f4cc67..00000000000 --- a/policyengine_us/parameters/gov/states/ok/dhs/liheap/eligibility/eligible_immigration_statuses.yaml +++ /dev/null @@ -1,25 +0,0 @@ -description: Oklahoma allows these represented citizenship and immigration statuses, subject to the incorporated qualified-alien waiting rule, under the Low Income Home Energy Assistance Program. -# The current OAC incorporates 7 CFR 273.4, whose FY2026/FY2027 text is -# unchanged. SNAP's later statutory status exclusions are not applied here. -# The model lacks precise enum categories for noncitizen nationals and -# several special eligible groups; their absence is an input limitation. -values: - 2025-09-15: - - CITIZEN - - LEGAL_PERMANENT_RESIDENT - - REFUGEE - - ASYLEE - - DEPORTATION_WITHHELD - - CUBAN_HAITIAN_ENTRANT - - PAROLED_ONE_YEAR - - CONDITIONAL_ENTRANT - -metadata: - unit: list - period: year - label: Oklahoma LIHEAP represented eligible immigration statuses - reference: - - title: OAC 340:20-1-10(d) and 340:50-5-67(a), current Title 340 - href: https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html - - title: 7 CFR 273.4(a), citizenship and alien status - href: https://www.ecfr.gov/current/title-7/section-273.4 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 index a09a2f62590..07a17367baa 100644 --- 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 @@ -1,22 +1,19 @@ 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. -# Quest operational guidance updated August 12, 2026 states $240 per worker; -# this is the earliest recovered evidence date, not a proven policy start. -# C-7 independently confirms $240 effective October 1, 2026. Earlier periods, -# including annual 2026 evaluated at January 1, remain backfilled estimates. +# The 10/1/2024, 10/1/2025 and 10/1/2026 editions of Appendix C-7 all print +# $240. values: - 2026-08-12: 240 - 2026-10-01: 240 + 2024-10-01: 240 metadata: unit: currency-USD period: month label: Oklahoma LIHEAP monthly earned income deduction reference: - - title: Quest LIHEAP Eligibility - Income, Income deductions, updated August 12, 2026 - href: https://fsquest.oucpm.org/2022/programs/liheap-ecap/eligibility-income/ - - title: OKDHS Appendix C-7, Earned income deduction + - 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/2026 edition 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/deeming/child_only_need_standard.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/deeming/child_only_need_standard.yaml index e1dab24c365..55811e3fadb 100644 --- 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 @@ -1,44 +1,44 @@ description: Oklahoma protects this monthly need amount for a represented children-only ineligible group before deeming its income 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. Earlier years are backfilled -# estimates; this observed schedule is effective July 1, 2026. +# 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: - 2026-07-01: 1 + 2025-01-01: 1 amount: - 2026-07-01: 193 + 2025-01-01: 193 - threshold: - 2026-07-01: 2 + 2025-01-01: 2 amount: - 2026-07-01: 380 + 2025-01-01: 380 - threshold: - 2026-07-01: 3 + 2025-01-01: 3 amount: - 2026-07-01: 535 + 2025-01-01: 535 - threshold: - 2026-07-01: 4 + 2025-01-01: 4 amount: - 2026-07-01: 691 + 2025-01-01: 691 - threshold: - 2026-07-01: 5 + 2025-01-01: 5 amount: - 2026-07-01: 830 + 2025-01-01: 830 - threshold: - 2026-07-01: 6 + 2025-01-01: 6 amount: - 2026-07-01: 974 + 2025-01-01: 974 - threshold: - 2026-07-01: 7 + 2025-01-01: 7 amount: - 2026-07-01: 1_098 + 2025-01-01: 1_098 - threshold: - 2026-07-01: 8 + 2025-01-01: 8 amount: - 2026-07-01: 1_219 + 2025-01-01: 1_219 - threshold: - 2026-07-01: 9 + 2025-01-01: 9 amount: - 2026-07-01: 1_333 + 2025-01-01: 1_333 metadata: type: single_amount @@ -49,5 +49,7 @@ metadata: 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, effective July 1, 2026 + - 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_year_lag.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/income/limit/fpg_year_lag.yaml index 705cadae938..9b3726f435b 100644 --- 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 @@ -1,6 +1,6 @@ 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 FY2026/FY2027 published charts reconcile to 2025/2026 guidelines. -# Earlier years use the requested guideline year, but are unverified. +# The 10/1/2024, 10/1/2025 and 10/1/2026 Appendix C-7 charts reconcile to +# the 2024, 2025 and 2026 guidelines. values: 2025-10-01: 1 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 index dcdd4e3be03..8cc6059006a 100644 --- 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 @@ -1,7 +1,7 @@ description: Oklahoma publishes monthly income limits in increments of this amount under the Low Income Home Energy Assistance Program. -# Ceiling the base and each extra-person amount separately matches both -# published charts and the FY2027 $616 additional-person amount. The FY2026 -# $596 extension is inferred; the announcement prints only sizes 1-8. +# 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: 2025-10-01: 1 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 index 41a33a508ec..84ad4d7a569 100644 --- 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 @@ -7,16 +7,20 @@ description: Oklahoma counts these unearned income sources for fully qualified h # 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. -# Pension income includes military pensions. military_retirement_pay is a -# tax classification and is not independently added. State SSP receipts are -# not modeled; SSI is federal, and OK TANF is added once at SPMUnit level. +# 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: - unemployment_compensation - strike_benefits - - social_security + # Social Security is counted in the formula, net of the Medicare Part B + # premium (plan Section 1.9). - 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 - survivor_benefits - railroad_benefits - workers_compensation @@ -40,3 +44,5 @@ metadata: 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://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22 + - title: Oklahoma FY2026 State Plan, Section 1.9 + 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/payment/income_band.yaml b/policyengine_us/parameters/gov/states/ok/dhs/liheap/payment/income_band.yaml index c39d3178aeb..7e5ca5ff051 100644 --- 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 @@ -1,6 +1,6 @@ description: Oklahoma assigns this payment band based on net monthly income under the Low Income Home Energy Assistance Program. -# Printed lower bounds are inclusive; retained cents remain in the lower -# band until income reaches 401 or 701. +# 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 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 1abe8a660f3..b6f4b69fa42 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -802,7 +802,7 @@ programs: category: Benefits agency: HHS status: partial - coverage: OK, OR, DC, Riverside County, MA, IL, KS, MS, TX + coverage: OR, DC, Riverside County, MA, IL, KS, MS, OK, TX state_implementations: - state: OK status: partial @@ -810,7 +810,8 @@ programs: full_name: Oklahoma Low Income Home Energy Assistance Program variable: ok_liheap parameter_prefix: gov.states.ok.dhs.liheap - notes: Regular winter assistance using the published FY2026 matrix and current income rules. The $240 earned allowance is sourced from October 2026 and the child-only need table from July 2026; earlier operation is unverified. FY2026 income limits above size 8 and unlisted direct-fuel payments remain unverified. Mixed-status grouping and deduction attribution use documented existing-input approximations. Historical backfill and payment carry-forward do not establish a completely verified award year. Crisis, cooling, weatherization and equipment assistance are excluded. + 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: OR status: in_progress name: 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 index 9ec80899254..caf9d78dac5 100644 --- 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 @@ -1,24 +1,30 @@ # Source-derived Oklahoma ordinary heating cases under contract v1.3. # Current C1 need and C7 earned amounts are tested in2027. -# Current340:20-1-10(h)(2), C7p1:1person1729*12=20748 inclusive gross ceiling. Current ordinary program has no asset test. -- name: Case 1, the ordinary gross ceiling is inclusive and assets do not change it. +# 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] - age: [40, 40] - heating_type: [NATURAL_GAS, NATURAL_GAS] - immigration_status: [CITIZEN, CITIZEN] - ok_liheap_gross_income: [20748, 20749] - has_heating_expense: [true, true] - bank_account_assets: [1000000, 1000000] - ssi: [0, 0] + 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: [20748, 20748] - ok_liheap_eligible: [true, false] + ok_liheap_income_limit: [20_748, 20_748, 20_748] + ok_liheap_eligible: [true, true, false] -# Current340:20-1-10(e)-(h): unsubsidized included heat qualifies; subsidized included heat requires verified surcharge, modeled by positive primary heating expense. Explicit responsibility cannot bypass zero surcharge. Public housing is a subsidy proxy. -- name: Case 2, subsidized heat in rent needs a positive excess charge despite a responsibility flag. +# 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] @@ -33,7 +39,7 @@ has_heating_expense: [false, false, true, false, true] ssi: [0, 0, 0, 0, 0] output: - ok_liheap_eligible: [true, false, false, true, false] + ok_liheap_eligible: [false, false, false, true, false] # Current340:20-1-10(e),(h)(1) includes total or partial responsibility. Direct obligation may be reported with 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. 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 index 5a03900804b..2e010541d87 100644 --- 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 @@ -1,8 +1,11 @@ # Source-derived Oklahoma ordinary heating cases under contract v1.3. # Current C1 need and C7 earned amounts are tested in2027. -# Current OAC340:20-1-10(d) incorporates340:50-5-67 and7CFR273.4(a)(6). All represented qualified categories at5years qualify; DACA/TPS/undocumented do not independently satisfy it. Missing enum categories remain outside this test. -- name: Case 1, represented statuses follow the incorporated qualified alien categories. +# 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] @@ -19,10 +22,11 @@ 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, true, true, true, true, true, true, false, false, false] + ok_liheap_immigration_eligible: [true, true, false, false, false, true, false, false, false, false, false] -# 7CFR273.4(a)(6)(iii)(A),(B),(D): five qualified years; years_since_us_entry is the existing qualified-status-clock approximation. -- name: Case 2, five years satisfies the waiting period for each subject status. +# 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] @@ -37,10 +41,12 @@ is_usda_disabled: [false, false, false, false, false, false] ssi: [0, 0, 0, 0, 0, 0] output: - ok_liheap_immigration_eligible: [false, true, false, true, false, true] + ok_liheap_immigration_eligible: [false, true, false, false, false, false] -# 7CFR273.4(a)(6)(ii)(A),(H),(J): under18 exemption, LPR40quarters exception (not parolee40), and benefit-based disability exemption. Age18 with39quarters and0qualifiedyears fails. -- name: Case 3, child quarters and benefit based disability exceptions retain their distinct conditions. +# 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] @@ -55,10 +61,11 @@ 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, true, true] + ok_liheap_immigration_eligible: [true, false, true, false, false, true] -# Current OAC incorporation and7CFR273.4(a)(6)(ii)(B) allow refugee status without waiting. P.L.119-21sec10108 separately narrows7USC2015(f) SNAP. Expected LIHEAPtrue derives from incorporated text, not the SNAP result. -- name: Case 4, a refugee remains eligible under the incorporated rule despite the separate SNAP statutory restriction. +# 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] @@ -72,6 +79,27 @@ is_snap_lpr_in_waiting_period_exempt_category: [false] ssi: [0] output: - ok_liheap_immigration_eligible: true + 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/income/ok_liheap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/liheap/income/ok_liheap_countable_income.yaml index 909d9e123cc..b9dbc32380a 100644 --- 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 @@ -49,3 +49,73 @@ state_code: OK output: ok_liheap_countable_income: [15000, 2400] + +# Plan Section 1.9 nets the Medicare Part B premium from Social Security only, floored at zero: +# max(1,200 - 2,434.80 (202.90 x 12), 0) = 0, so the excess premium does not reduce the 12,000 pension. Countable 12,000. +- name: Case 2, a Part B premium above the Social Security benefit floors that benefit at zero without reducing other income. + 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: 12_000 + ok_liheap_gross_income: 12_000 + +# 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 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 index 3a4700540e0..34f0d7fa328 100644 --- 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 @@ -535,3 +535,69 @@ 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 index e485b681ad6..0b440f82567 100644 --- 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 @@ -141,3 +141,43 @@ 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 index 9ac9c12e1a9..326c6b2baa1 100644 --- 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 @@ -15,3 +15,20 @@ 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] 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 index c19ef99adf7..5e10f2bd188 100644 --- 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 @@ -70,8 +70,9 @@ ok_liheap_gross_income: 7_200 ok_liheap_net_income: 6_000 -# C7 FY2027 size1 limit1729*12=20748. Gross20749 stays above it; net20749-2880=17869. No finaleligibility output is asserted. -- name: Case 3, FY2027 gross income remains above its limit even when benefit net income is below. +# 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: @@ -83,7 +84,7 @@ is_in_k12_school: false is_disabled: false ssi: 0 - employment_income: 20_749 + employment_income: 20_754 spm_units: spm_unit: members: [person1] @@ -97,9 +98,9 @@ members: [person1] state_code: OK output: - ok_liheap_gross_income: 20_749 + ok_liheap_gross_income: 20_754 ok_liheap_income_limit: 20_748 - ok_liheap_net_income: 17_869 + ok_liheap_net_income: 17_874 # Registerpp580-581 permits age60+ or disabled person costs.30000-2880 workerallowance-2400 eldermedical-1200 disabledmedical=23520. Age59 nondisabled medical3600 is not deductible. - name: Case 4, FY2027 medical deduction follows each elderly or disabled person separately. 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 index 8c41debc714..5b19ac6241d 100644 --- 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 @@ -90,8 +90,10 @@ ok_liheap_eligible: true ok_liheap: 280 -# Current340:20-1-10(f)-(g) plus C7Ap1:0net,size1 renter150,roomer70; subsidizedpositive surcharge retains150, zero surcharge ineligible. Roomer written-agreement fact is assumed under documented input limitation. -- name: Case 3, renter roomer and subsidized surcharge routes link eligibility to their heating schedules. +# 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] @@ -108,8 +110,8 @@ gas_expense: [0, 0, 10, 0] has_heating_expense: [false, false, false, false] output: - ok_liheap_eligible: [true, true, true, false] - ok_liheap: [150, 70, 150, 0] + ok_liheap_eligible: [false, false, true, false] + ok_liheap: [0, 0, 150, 0] # Current340:20-1-11(a)(4),(c), C1p4/C7p1: ineligible12000-2880-600medical-1200support-4776need=2544. Gross2544+6000eligible+1200annualTANF=9744. Net9744-2880eligibleallowance-600eligiblesupport-600annualCCScopay=5664=472monthly; C7Ap1 ordinary,size2=>265. No duplicate ineligible deductions or SPM transfers. - name: Case 4, ineligible person deductions TANF and the household copay are each applied once. @@ -246,3 +248,102 @@ ok_ccs_copay: [0, 0, 0] output: ok_liheap: [365, 0, 0] + +# Plan Section 1.9 counts Social Security "Excluding MediCare deduction". Both retirees get $1,780/mo (21,360/yr). +# Person 1 pays the 2026 standard Part B premium 202.90 x 12 = 2,434.80: countable 21,360 - 2,434.80 = 18,925.20 +# -> 1,577.10/mo rounds to 1,577 <= 1,696 (2026 size 1 limit 20,352/yr); no deductions, net band 3 -> natural gas 235. +# Person 2 pays no premium: 21,360/12 = 1,780 > 1,696 -> ineligible, 0. +- name: Case 7, Social Security net of the Medicare Part B premium decides eligibility for a retiree. + 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: [18_925.20, 21_360] + ok_liheap_gross_income: [18_925.20, 21_360] + ok_liheap_income_limit: [20_352, 20_352] + ok_liheap_eligible: [true, false] + ok_liheap_net_income: [18_925.20, 21_360] + ok_liheap: [235, 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] 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 index c487a5bd19e..09226f970a1 100644 --- 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 @@ -1,7 +1,9 @@ # Source-derived Oklahoma ordinary heating cases under contract v1.3. # Current C1 need and C7 earned amounts are tested in2027. -# Current340:20-1-10(h)(3): exclude ineligible members for both financial standard and benefit. Two of four members qualify; child status is still required. +# 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: @@ -66,8 +68,8 @@ members: [citizen, refugee, recent_lpr, child] state_code: OK output: - ok_liheap_immigration_eligible: [true, true, false, false] - ok_liheap_household_size: 2 + ok_liheap_immigration_eligible: [true, false, false, false] + ok_liheap_household_size: 1 # Current340: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. 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 index c7875963b6c..99fe601647c 100644 --- 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 @@ -32,20 +32,23 @@ 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] -# C7Amonthlylowerbounds0,401,701. Annualvalues represent0,400,400.01,400.99,401,700,700.01,700.99,701; fractional convention keepscurrentbanduntilnextprintedlowerbound. -- name: Case 2, printed monthly lower bounds preserve fractional cents until four hundred one and seven - hundred one. +# 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] + 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] - gas_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200] - ok_liheap_household_size: [1, 1, 1, 1, 1, 1, 1, 1, 1] - ok_liheap_net_income: [0, 4_800, 4800.12, 4811.88, 4_812, 8_400, 8400.12, 8411.88, 8_412] + NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] + gas_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200] + 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, 235] + ok_liheap_matrix_amount: [365, 365, 365, 365, 265, 265, 265, 265, 265, 265, 235, 235, 235] # C7A ordinaryfuelmonthly500 row: sizes1-3=>265,4-6=>292,7+=>312. - name: Case 3, household group boundaries three four six and seven use the correct column. @@ -108,3 +111,22 @@ 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] + other_heating_fuel_expense: [600, 0, 0, 0] + pre_subsidy_electricity_expense: [0, 600, 0, 0] + gas_expense: [0, 0, 0, 600] + 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 index 013de7da3e1..34b133ff7f7 100644 --- 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 @@ -7,34 +7,49 @@ class ok_liheap_eligible(Variable): 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): eligible size, gross income - # including deemed contributions, and responsibility for heating costs. - reference = "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html" + # 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) - income_limit = spm_unit("ok_liheap_income_limit", 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) - expense = spm_unit("heating_expense", period) - has_expense = spm_unit("has_heating_expense", period) - subsidized = spm_unit.household("is_in_public_housing", period) | spm_unit( - "receives_housing_assistance", period - ) - # Housing flags proxy income-based rent. A positive heating expense - # represents a verified surcharge when subsidized heat is in rent; - # the general responsibility flag alone cannot satisfy that branch. - rent_responsibility = ~subsidized | (expense > 0) - # Direct expenses represent the remaining household obligation after - # a utility allowance, rather than a fully reimbursed gross bill. - direct_responsibility = has_expense | (expense > 0) - responsibility = where(heat_in_rent, rent_responsibility, direct_responsibility) - # Written roomer agreements, exact shared-meter/institutional facts, - # and tribal LIHEAP receipt are not available as existing inputs. + # OAC 340:20-1-19(d)(1) pays "renters, roomers, and boarders who pay a + # surcharge for utilities included in their rent", and (d)(2) verifies + # "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. + 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) - & (income <= income_limit) + & (monthly_income <= monthly_limit) & (fuel != fuel.possible_values.NONE) - & responsibility + & (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 index 0a935fa2be9..994d10ab1a4 100644 --- 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 @@ -8,25 +8,23 @@ class ok_liheap_immigration_eligible(Variable): label = "Meets Oklahoma LIHEAP citizenship and immigration requirements" defined_for = StateCode.OK reference = ( - # Current OAC 340:20-1-10(d) incorporates 340:50-5-67(a), which - # expressly references 7 CFR 273.4. The printed citation omits 5. + # 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): - p = parameters(period).gov.states.ok.dhs.liheap.eligibility - status = person("immigration_status", period).decode_to_str() - allowed_status = np.isin(status, p.eligible_immigration_statuses) - # Reuse the incorporated CFR waiting rule independently of SNAP's - # additional post-OBBB statutory status exclusions. The retrieved - # FY2026/FY2027 CFR text retains refugee/asylee eligibility. No - # LIHEAP instruction extending SNAP's new exclusions was found. - waiting_period = person( - "meets_snap_qualified_alien_waiting_period", period.first_month - ) - # Annual eligibility uses the first month's circumstances. Existing - # waiting-rule proxies and missing enum categories (including - # noncitizen nationals, trafficking and battered-alien categories) - # remain input limitations; no new immigration input is introduced. - return allowed_status & waiting_period + # 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 index 3a74a08e4d3..718adeb401c 100644 --- 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 @@ -34,9 +34,8 @@ def formula(spm_unit, period, parameters): ) 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 published - # FY2026/FY2027 limits. FY2026's $596 additional-person amount is a - # reconciled extension; the announcement only prints sizes 1-8. + # 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 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 index 99807e2e362..91413780d3e 100644 --- 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 @@ -10,14 +10,30 @@ class ok_liheap_countable_income(Variable): 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" + reference = ( + "https://prod-ok-administrativerules.tecuity.com/api/BlobStorageGetFile?storageContainer=TitleHtml&name=Title_340.html", + # Section 1.9 (page 6) 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) - # Oklahoma TANF is an SPM aggregate and is counted separately once. - return income + # Plan Section 1.9 checks "Excluding MediCare deduction" for Social + # Security in FY2025-FY2027, so the benefit is counted net of the + # Part B premium the person pays. medicare_part_b_premium is zero for + # a person who is not enrolled and excludes the share a Medicare + # Savings Program pays. OAC 340:20-1-11(a) uses gross income before + # recoupment or garnishment and is silent on premium withholding. + premium = person("medicare_part_b_premium", period) + social_security = max_(person("social_security", period) - premium, 0) + # TANF is an SPM aggregate and is counted separately once. + return income + social_security 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 index 61bd42c285f..61555652ace 100644 --- 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 @@ -11,6 +11,8 @@ class ok_liheap_gross_income(Variable): 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 (page 6) counts TANF benefits. + "https://liheapch.acf.gov/docs/2026/state-plans/OK_Plan_2026.pdf#page=6", ) def formula(spm_unit, period, parameters): @@ -25,7 +27,9 @@ def formula(spm_unit, period, parameters): deemed_income = spm_unit.sum( person.tax_unit("ok_liheap_deemed_income", period) * representative ) - # Oklahoma TANF is SPMUnit/MONTH. Count the cash aggregate once; - # existing inputs do not allocate it to individual recipients. - tanf = spm_unit("ok_tanf", period, options=[ADD]) + # 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 index 7ceafc658dd..6c16b175ab6 100644 --- 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 @@ -26,7 +26,8 @@ def formula(person, period, parameters): ) # is_disabled approximates the incorporated SNAP disability test. # Use the existing nonpremium aggregate without overlapping detailed - # medical inputs; Medicare/premium treatment remains deferred. + # medical inputs. The Medicare Part B premium is netted from Social + # Security in countable income, so it is not deducted again here. medical_deduction = ( max_(person("other_medical_expenses", period), 0) * medical_eligible ) 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 index c055c3bc980..c93e02fc80a 100644 --- 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 @@ -9,6 +9,8 @@ class ok_liheap_matrix_amount(Variable): 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", ) @@ -16,8 +18,10 @@ class ok_liheap_matrix_amount(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ok.dhs.liheap.payment size = spm_unit("ok_liheap_household_size", period) - monthly_income = spm_unit("ok_liheap_net_income", period) / MONTHS_IN_YEAR - # Keep cents until the printed next lower bound: $401 or $701. + # 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) @@ -47,7 +51,8 @@ def formula(spm_unit, period, parameters): p.matrix.roomer[band][size_group], p.matrix.renter[band][size_group], ) - # Heat-in-rent schedules cover every fuel, including an unknown fuel. + # 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 From e522f3db2841881e317b38bd7339cef982dc48b2 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 7 Oct 2026 22:56:53 -0400 Subject: [PATCH 4/6] Fix issues from review: count retirement distributions and deduct premiums Count retirement_distributions; deduct other health premiums and any Part B premium above Social Security for members 60+ or disabled (OAC 340:20-1-11(c)(1)); household size uses adds. Co-Authored-By: Claude Opus 5.5 --- .../dhs/liheap/income/sources/unearned.yaml | 3 + .../income/ok_liheap_countable_income.yaml | 32 ++++++++ .../gov/states/ok/dhs/liheap/ok_liheap.yaml | 75 +++++++++++++++++++ .../income/ok_liheap_income_deductions.py | 18 +++-- .../ok/dhs/liheap/ok_liheap_household_size.py | 10 +-- 5 files changed, 127 insertions(+), 11 deletions(-) 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 index 84ad4d7a569..72d0946cd04 100644 --- 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 @@ -21,6 +21,9 @@ values: # 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 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 index b9dbc32380a..7b20dced755 100644 --- 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 @@ -119,3 +119,35 @@ 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) net of the 2026 Part B premium 202.90 x 12 = 2,434.80 -> 9,565.20. +# IRA withdrawal 300/mo (3,600). Countable 9,565.20 + 3,600 = 13,165.20 (1,097.10/mo). +- name: Case 4, an IRA withdrawal counts alongside Social Security net of the Part B premium 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: 13_165.20 + ok_liheap_gross_income: 13_165.20 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 index 5b19ac6241d..58cec262bb8 100644 --- 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 @@ -347,3 +347,78 @@ 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. +# With no Social Security to net it from, the full 2026 Part B premium 202.90 x 12 = 2,434.80 is deducted. +# 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 without Social Security deducts the full Medicare Part B premium. + 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 + +# Social Security 1,000/mo (12,000) absorbs the whole 2026 Part B premium 202.90 x 12 = 2,434.80 in countable income: +# 12,000 - 2,434.80 = 9,565.20 -> 797.10/mo rounds to 797 <= 1,696, eligible. The Part B deduction is +# max(2,434.80 - 12,000, 0) = 0, so only the 150/mo Medigap premium (1,800) is deducted. +# Net 9,565.20 - 1,800 = 7,765.20 -> 647.10/mo rounds to 647, band 2 (401-700) -> natural gas 265. +- name: Case 12, a retiree deducts another health premium while the Part B premium is only netted from Social + Security. + 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: 9_565.20 + ok_liheap_gross_income: 9_565.20 + ok_liheap_income_deductions: 1_800 + ok_liheap_eligible: true + ok_liheap_net_income: 7_765.20 + ok_liheap: 265 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 index 6c16b175ab6..8399435ad3d 100644 --- 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 @@ -11,6 +11,8 @@ class ok_liheap_income_deductions(Variable): reference = ( # OAC 340:20-1-11(a)(4), (c): these person deductions apply to # ineligible-member deeming and eligible members' net income. + # OAC 340:50-7-31(a)(3)(A)(v)-(vi) lists health insurance and + # Medicare premiums as allowable medical expenses. "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", ) @@ -25,12 +27,18 @@ def formula(person, period, parameters): "is_disabled", period ) # is_disabled approximates the incorporated SNAP disability test. - # Use the existing nonpremium aggregate without overlapping detailed - # medical inputs. The Medicare Part B premium is netted from Social - # Security in countable income, so it is not deducted again here. - medical_deduction = ( - max_(person("other_medical_expenses", period), 0) * medical_eligible + # Countable income nets the Part B premium from Social Security, + # floored at zero, so only the premium that Social Security does not + # cover is deducted here; no premium dollar is counted twice. + part_b_premium = person("medicare_part_b_premium", period) + social_security = max_(person("social_security", period), 0) + unnetted_part_b_premium = max_(part_b_premium - social_security, 0) + other_premiums = max_( + person("health_insurance_premiums_without_medicare_part_b", period), 0 ) + other_expenses = max_(person("other_medical_expenses", period), 0) + medical_expenses = other_expenses + other_premiums + unnetted_part_b_premium + 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/ok_liheap_household_size.py b/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap_household_size.py index 6172fcd6bb8..305d3b73072 100644 --- 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 @@ -10,9 +10,7 @@ class ok_liheap_household_size(Variable): # 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" - - def formula(spm_unit, period, parameters): - # SPM membership represents the economic unit sharing heating costs. - # SSN furnishing/application and shared-meter household facts are - # not represented by the available inputs. - return spm_unit.sum(spm_unit.members("ok_liheap_immigration_eligible", period)) + # 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"] From 66e72954386bed29a67b2017ced089abd2d53844 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 7 Oct 2026 23:24:36 -0400 Subject: [PATCH 5/6] Apply the reference page-citation convention One reference entry per source; single-page citations keep the page only in the href; multi-page titles end with a quoted #page list and the href opens the first cited page; variable references use '# PDF pages ...' comments above multi-page hrefs (CLAUDE.md, PolicyEngine/policyengine-us PR 10009). Reference lines only. Co-Authored-By: Claude Opus 5.5 --- .../ok/dhs/liheap/income/ok_liheap_countable_earned_income.py | 3 ++- .../states/ok/dhs/liheap/income/ok_liheap_countable_income.py | 2 +- .../gov/states/ok/dhs/liheap/income/ok_liheap_deemed_income.py | 3 ++- .../gov/states/ok/dhs/liheap/income/ok_liheap_gross_income.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) 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 index c63734110d9..71e1e42b512 100644 --- 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 @@ -9,7 +9,8 @@ class ok_liheap_countable_earned_income(Variable): label = "Oklahoma LIHEAP gross countable earned income" defined_for = StateCode.OK reference = ( - # OAC 340:20-1-11(a)-(b), PDF pages 576-578, effective September 15, 2025. + # 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", "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22", ) 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 index 91413780d3e..7923503dd98 100644 --- 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 @@ -12,7 +12,7 @@ class ok_liheap_countable_income(Variable): # 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 (page 6) of the FY2025, FY2026 and FY2027 plans. + # 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", 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 index 83726c59fa5..799041761f2 100644 --- 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 @@ -12,7 +12,8 @@ class ok_liheap_deemed_income(Variable): # 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, physical pages 4-5. + # 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", ) 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 index 61555652ace..c1715618d93 100644 --- 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 @@ -11,7 +11,7 @@ class ok_liheap_gross_income(Variable): 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 (page 6) counts TANF benefits. + # Section 1.9 counts TANF benefits. "https://liheapch.acf.gov/docs/2026/state-plans/OK_Plan_2026.pdf#page=6", ) From f0e2f4033e1ae7923e97fcb598632732f2df903f Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 15 Oct 2026 16:11:37 -0400 Subject: [PATCH 6/6] Address review round 1 on Oklahoma LIHEAP - S1: Merge blocker from #9558: the unearned list reads the raw unemployment_compensation, so modeled ok_ui drops ou - S2: Social Security counts net of Part B in the gross test; the OAC counts gross income and deducts the premium af - S3: The medical deduction misses pretax payroll premiums (#10046) and reads is_disabled instead of the 7 CFR 271.2 - S4: Eight parameter descriptions are off the house template, and the student parameter misdescribes its scope - S5: References: two missing page lists, a missing #page=1, and FY2025 limits dated and cited only from FY2026 - S6: farm_operations_income has no test that would fail if it were dropped Also applies the in-scope suggestions. Tests not run locally; CI validates. Co-Authored-By: Claude Opus 5.5 --- .../income/deductions/earned_income.yaml | 4 +- .../deductions/medical_age_threshold.yaml | 2 +- .../deeming/child_only_need_standard.yaml | 2 +- .../ok/dhs/liheap/income/limit/fpg_rate.yaml | 6 +- .../dhs/liheap/income/limit/fpg_year_lag.yaml | 6 +- .../liheap/income/limit/max_table_size.yaml | 10 ++- .../income/limit/rounding_increment.yaml | 8 +- .../ok/dhs/liheap/income/sources/earned.yaml | 15 ++-- .../dhs/liheap/income/sources/unearned.yaml | 22 +++-- .../student_earned_income_age_limit.yaml | 9 +- .../liheap/payment/household_size_group.yaml | 2 +- .../ok/dhs/liheap/payment/income_band.yaml | 2 +- .../eligibility/ok_liheap_eligible.yaml | 9 +- .../ok_liheap_immigration_eligible.yaml | 3 +- .../eligibility/ok_liheap_income_limit.yaml | 16 ++-- .../ok_liheap_countable_earned_income.yaml | 56 +++++++++--- .../income/ok_liheap_countable_income.yaml | 67 +++++++++++--- .../income/ok_liheap_deemed_income.yaml | 26 ++++-- .../liheap/income/ok_liheap_gross_income.yaml | 13 ++- .../income/ok_liheap_income_deductions.yaml | 36 +++++++- .../liheap/income/ok_liheap_net_income.yaml | 21 +++-- .../gov/states/ok/dhs/liheap/ok_liheap.yaml | 89 +++++++++++++------ .../dhs/liheap/ok_liheap_household_size.yaml | 5 +- .../payment/ok_liheap_matrix_amount.yaml | 31 ++----- .../liheap/eligibility/ok_liheap_eligible.py | 24 +++-- .../eligibility/ok_liheap_income_limit.py | 1 + .../ok_liheap_countable_earned_income.py | 3 +- .../income/ok_liheap_countable_income.py | 10 +-- .../income/ok_liheap_income_deductions.py | 30 +++---- .../gov/states/ok/dhs/liheap/ok_liheap.py | 2 +- 30 files changed, 346 insertions(+), 184 deletions(-) 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 index 07a17367baa..561ad51af73 100644 --- 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 @@ -13,7 +13,9 @@ metadata: 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/2026 edition + - 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 index f79e4c1db2f..66c0134236b 100644 --- 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 @@ -1,4 +1,4 @@ -description: Oklahoma allows medical expense deductions beginning at this age or for a qualifying disabled member under the Low Income Home Energy Assistance Program. +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 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 index 55811e3fadb..22990dceee6 100644 --- 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 @@ -1,4 +1,4 @@ -description: Oklahoma protects this monthly need amount for a represented children-only ineligible group before deeming its income under the Low Income Home Energy Assistance Program. +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. 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 index 6e4a3878411..74396ce6392 100644 --- 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 @@ -1,14 +1,18 @@ description: Oklahoma limits gross income to this multiple of the federal poverty guideline under the Low Income Home Energy Assistance Program. values: - 2025-10-01: 1.3 + 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 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 index 9b3726f435b..0d825c244b1 100644 --- 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 @@ -2,13 +2,17 @@ description: Oklahoma uses the federal poverty guideline from this many years be # The 10/1/2024, 10/1/2025 and 10/1/2026 Appendix C-7 charts reconcile to # the 2024, 2025 and 2026 guidelines. values: - 2025-10-01: 1 + 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 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 index dc88b695dd5..eab87954154 100644 --- 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 @@ -1,13 +1,17 @@ -description: Oklahoma publishes monthly income limits through this household size before adding a separate additional-person amount under the Low Income Home Energy Assistance Program. +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: - 2025-10-01: 8 + 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 + - 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 index 8cc6059006a..2a6cb8734e2 100644 --- 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 @@ -1,16 +1,20 @@ -description: Oklahoma publishes monthly income limits in increments of this amount under the Low Income Home Energy Assistance Program. +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: - 2025-10-01: 1 + 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 index e7433598002..a6fb04016ec 100644 --- 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 @@ -1,7 +1,10 @@ -description: Oklahoma counts these earned income sources for fully qualified households under the Low Income Home Energy Assistance Program. -# Use existing net business inputs without a further 50% business-expense -# deduction or new expense input. Passive versus active partnership income -# is not distinguishable with existing input data. +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 @@ -15,7 +18,7 @@ metadata: period: year label: Oklahoma LIHEAP earned income sources reference: - - title: OAC 340:20-1-11(a)-(b), September 2025 permanent adoption + - 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://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22 + 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 index 72d0946cd04..d72f0b444fc 100644 --- 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 @@ -1,4 +1,4 @@ -description: Oklahoma counts these unearned income sources for fully qualified households under the Low Income Home Energy Assistance Program. +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 @@ -11,10 +11,16 @@ description: Oklahoma counts these unearned income sources for fully qualified h # at SPMUnit level through the take-up-gated tanf aggregate. values: 2025-09-15: - - unemployment_compensation + # Reported unemployment compensation, otherwise modeled Oklahoma UI (ok_ui). + - total_unemployment_compensation - strike_benefits - # Social Security is counted in the formula, net of the Medicare Part B - # premium (plan Section 1.9). + # 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 @@ -43,9 +49,9 @@ metadata: period: year label: Oklahoma LIHEAP unearned income sources reference: - - title: OAC 340:20-1-11(a)-(b), September 2025 permanent adoption + - 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://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22 - - title: Oklahoma FY2026 State Plan, Section 1.9 + - 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 index 0cd0463362b..ed9c87423d8 100644 --- 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 @@ -1,7 +1,8 @@ -description: Oklahoma excludes earned income of secondary-school students under adult control below this age under the Low Income Home Energy Assistance Program. +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. Tax dependency approximates control; -# separate elementary attendance and excluded training income are unavailable. +# 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 @@ -13,4 +14,4 @@ metadata: - 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://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22 + 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 index 2eaf956cafb..d3386deb81f 100644 --- 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 @@ -1,4 +1,4 @@ -description: Oklahoma assigns this payment group based on household size under the Low Income Home Energy Assistance Program. +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 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 index 7e5ca5ff051..7601df31f23 100644 --- 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 @@ -1,4 +1,4 @@ -description: Oklahoma assigns this payment band based on net monthly income under the Low Income Home Energy Assistance Program. +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: 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 index caf9d78dac5..c2198812f65 100644 --- 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 @@ -1,5 +1,4 @@ -# Source-derived Oklahoma ordinary heating cases under contract v1.3. -# Current C1 need and C7 earned amounts are tested in2027. +# 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. @@ -41,7 +40,8 @@ output: ok_liheap_eligible: [false, false, false, true, false] -# Current340:20-1-10(e),(h)(1) includes total or partial responsibility. Direct obligation may be reported with existing has_heating_expense or demonstrated by a positive primary bill. +# 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: @@ -57,7 +57,8 @@ output: ok_liheap_eligible: [true, false, true] -# Current340:20-1-10(a),(h)(3) and state scope: Oklahoma ordinary heating requires heat and at least one qualified member. +# 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: 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 index 2e010541d87..073465c09f7 100644 --- 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 @@ -1,5 +1,4 @@ -# Source-derived Oklahoma ordinary heating cases under contract v1.3. -# Current C1 need and C7 earned amounts are tested in2027. +# 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 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 index 3a784ced0cb..362d4b9636e 100644 --- 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 @@ -1,6 +1,6 @@ # Oklahoma independent fully qualified household components; no final eligibility or award is asserted. -# Jan6,2026 officialannouncement monthly[1696,2292,2888,3483,4079,4675,5271,5867], multipliedby12. No FY2027 amounts mixed into2026. +# 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 @@ -8,12 +8,12 @@ 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] - gas_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200] 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] -# C7effective2026-10-01 monthly[1729,2345,2960,3575,4191,4806,5421,6037]; add616perperson over8. Annualizeonce;size9=6653*12 and10=7269*12. +# 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 @@ -21,31 +21,29 @@ 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] - gas_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200] 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] -# Unverified2025 estimate uses2024FPG15060,size8=52720,increment5380. Monthlyceil at130% gives1632,5712 andextra583;annual19584,68544,75540. Does not verify historical fullprogram. -- name: Case 3, historical backfill uses its own prior year federal guideline and rounded increment. +# 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] - gas_expense: [1_200, 1_200, 1_200] ok_liheap_household_size: [1, 8, 9] output: ok_liheap_income_limit: [19_584, 68_544, 75_540] -# Zero-size guard has no one-person allowance; normal cases represent fullyqualifiedhouseholds. +# 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] - gas_expense: [1_200] 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 index 744f48e718c..030a3a9ccfe 100644 --- 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 @@ -1,6 +1,7 @@ # Oklahoma independent fully qualified household components; no final eligibility or award is asserted. -# Register pp576-578 and approved existing-net-input convention:12000+2400+600+0+1200=16200. No second legal50% business deduction is applied. +# 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 @@ -33,7 +34,8 @@ output: ok_liheap_countable_earned_income: 16_200 -# Incorporated SNAP340:50-7-22(9) exempts elementary or high-school students17andunder underadultcontrol. K12 explicitlytrue and taxdependency approximate attendance/control. +# 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 @@ -70,7 +72,8 @@ output: ok_liheap_countable_earned_income: [12_000, 0] -# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +# 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 @@ -91,7 +94,6 @@ is_in_k12_school: true is_disabled: false ssi: 0 - is_full_time_student: true employment_income: 6_000 self_employment_income: 1_200 spm_units: @@ -109,7 +111,8 @@ output: ok_liheap_countable_earned_income: [12_000, 0] -# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +# 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 @@ -130,7 +133,6 @@ is_in_k12_school: false is_disabled: false ssi: 0 - is_full_time_student: false employment_income: 6_000 self_employment_income: 1_200 spm_units: @@ -148,7 +150,8 @@ output: ok_liheap_countable_earned_income: [12_000, 7_200] -# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +# 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 @@ -169,7 +172,6 @@ is_in_k12_school: true is_disabled: false ssi: 0 - is_full_time_student: true employment_income: 6_000 self_employment_income: 1_200 spm_units: @@ -187,7 +189,8 @@ output: ok_liheap_countable_earned_income: [12_000, 7_200] -# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +# 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 @@ -208,7 +211,6 @@ is_in_k12_school: true is_disabled: false ssi: 0 - is_full_time_student: true employment_income: 6_000 self_employment_income: 1_200 spm_units: @@ -226,7 +228,8 @@ output: ok_liheap_countable_earned_income: [12_000, 7_200] -# SNAP340:50-7-22(9), incorporated by current Registerp578, requires ageunder18, K12 attendance and adultcontrol. Young person wages6000+existingbusiness1200 are7200 unless all three hold; adultcollege is not K12. +# 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 @@ -247,7 +250,6 @@ is_in_k12_school: false is_disabled: false ssi: 0 - is_full_time_student: true employment_income: 6_000 self_employment_income: 1_200 spm_units: @@ -264,3 +266,33 @@ 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 index 7b20dced755..f9620579f2f 100644 --- 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 @@ -1,7 +1,7 @@ -# Source-derived Oklahoma ordinary heating cases under contract v1.3. -# Current C1 need and C7 earned amounts are tested in2027. +# Oklahoma LIHEAP regular heating cases. -# Current340:20-1-11(a)(2)-(4):12000wages+600rent+1200farmrent+1200annualSSI=15000;2400pension stays with its recipient before deeming. SSI is monthly but the supplied annual receipt is counted once. +# 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: @@ -50,9 +50,9 @@ output: ok_liheap_countable_income: [15000, 2400] -# Plan Section 1.9 nets the Medicare Part B premium from Social Security only, floored at zero: -# max(1,200 - 2,434.80 (202.90 x 12), 0) = 0, so the excess premium does not reduce the 12,000 pension. Countable 12,000. -- name: Case 2, a Part B premium above the Social Security benefit floors that benefit at zero without reducing other income. +# 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: @@ -78,8 +78,8 @@ members: [person1] state_code: OK output: - ok_liheap_countable_income: 12_000 - ok_liheap_gross_income: 12_000 + 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. @@ -121,9 +121,9 @@ 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) net of the 2026 Part B premium 202.90 x 12 = 2,434.80 -> 9,565.20. -# IRA withdrawal 300/mo (3,600). Countable 9,565.20 + 3,600 = 13,165.20 (1,097.10/mo). -- name: Case 4, an IRA withdrawal counts alongside Social Security net of the Part B premium for a retiree. +# 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: @@ -149,5 +149,46 @@ members: [person1] state_code: OK output: - ok_liheap_countable_income: 13_165.20 - ok_liheap_gross_income: 13_165.20 + 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 index 34f0d7fa328..741ad524f9d 100644 --- 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 @@ -1,7 +1,8 @@ -# Source-derived Oklahoma ordinary heating cases under contract v1.3. -# Current C1 need and C7 earned amounts are tested in2027. +# Oklahoma LIHEAP regular heating cases. +# Cases dated 2027 use the current Appendix C-1 need standards and Appendix C-7 earned income deduction. -# Current340:20-1-11(a)(4); C7p1 and C1p4 IX-A. Annual12000-2880-398*12=4344 (monthly362). The eligible child receives no ineligible need allowance. No second deduction in net. +# 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: @@ -50,7 +51,9 @@ ok_liheap_gross_income: 4344 ok_liheap_net_income: 4344 -# Current340:20-1-11(a)(4), C1p4 IX-A size3need645. Ineligible19200-2*2880-645*12=5700; eligible600 gives6300. Equal-age representative tie must not count5700 twice. Tax-unit grouping is the documented approximation. +# 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: @@ -124,7 +127,8 @@ ok_liheap_net_income: 6300 ok_liheap_household_size: 1 -# Current340:20-1-11(a)(4), C1p4: group1=12000-2880-4776=4344; group2=9000-4776=4224; eligible adult6000 gives14568gross. Deduct only eligible worker2880 later:11688net. +# 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: @@ -201,7 +205,8 @@ ok_liheap_net_income: 11688 ok_liheap_household_size: 2 -# C1p5 IX-B size2need380.6000-380*12=1440 from child-only taxunit, not dropped because there is no adult tax head. Eligible6000 gives7440gross; minus2880eligible allowance gives4560net. +# 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: @@ -265,7 +270,8 @@ ok_liheap_net_income: 4560 ok_liheap_household_size: 1 -# C1p5 IX-B9-or-more need1333. Ten ineligible children in one represented unit:24000-1333*12=8004. Eligible adult is excluded from need. No inferred additional-child increment. +# 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: @@ -422,7 +428,8 @@ ok_liheap_deemed_income: [8004, 0] ok_liheap_gross_income: 8004 -# Current340:20-1-11(a)(4): max(3000-398*12,0)=0; fully eligible taxunit has no deemed income or need deduction. Eligible pension1000 stays fully counted. +# 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: @@ -473,7 +480,8 @@ ok_liheap_gross_income: 1000 ok_liheap_net_income: 1000 -# C1pp4-5 IX-A/B: child-only1need193 gives3600-2316=1284; adult1need398 givesmax(3600-4776,0)=0. Existing is_adult age18 is the contracted schedule-classification approximation. +# 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: 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 index 0b440f82567..8872d48ece5 100644 --- 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 @@ -1,6 +1,7 @@ # Oklahoma independent fully qualified household components; no final eligibility or award is asserted. -# Register income rule and FY2026 plan source categories:12000+1200+2400+1200+2400=19200 before ordinary benefit deductions. +# 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 @@ -33,7 +34,9 @@ output: ok_liheap_gross_income: 19_200 -# Register340:20-1-11(a)-(b) ordinary regular receipts:12000+2400+1200+600+1200+600+1200+600+120+240+1200+600+600+600=23160. Estate/help inputs here are regular unrestricted receipts, not excluded nonrecurring principal. +# 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 @@ -74,7 +77,8 @@ output: ok_liheap_gross_income: 23_160 -# 6000 adult wages+1200 adult federalSSI+1200 childSSA+3600 annual familyOKTANF=12000. The school exception covers earnings, not childSSA; monthlyprogram receipts aggregate once. +# 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 @@ -111,7 +115,8 @@ output: ok_liheap_gross_income: 12_000 -# Registerp578 incorporates program exclusions; SNAP and housing subsidy are not added to ordinary grossincome. This does not assert categorical eligibility. +# 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 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 index 326c6b2baa1..01acbbe175b 100644 --- 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 @@ -1,7 +1,9 @@ -# Source-derived Oklahoma ordinary heating cases under contract v1.3. -# Current C1 need and C7 earned amounts are tested in2027. +# Oklahoma LIHEAP regular heating cases. +# Cases dated 2027 use the current Appendix C-1 need standards and Appendix C-7 earned income deduction. -# Current340:20-1-11(c), C7p1: earned allowance=min(earnings,2880). First1200+300=1500 (age40nondisabledmedical excluded); second2880+600+400=3880; third2880+700+500=4080. Household floor is applied later, so person deductions may exceed income. +# 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: @@ -10,7 +12,7 @@ heating_type: [NATURAL_GAS, NATURAL_GAS, NATURAL_GAS] immigration_status: [CITIZEN, CITIZEN, CITIZEN] ok_liheap_countable_earned_income: [1200, 12000, 12000] - is_disabled: [false, false, true] + is_usda_disabled: [false, false, true] other_medical_expenses: [500, 600, 700] child_support_expense: [300, 400, 500] output: @@ -32,3 +34,29 @@ 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 index 5e10f2bd188..842bb3ab04c 100644 --- 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 @@ -1,6 +1,7 @@ # Oklahoma independent fully qualified household components; no final eligibility or award is asserted. -# C7 dated2026-10-01:240monthly*12=2880 for each of two workers.24000-2880-2880=18240; worker1 has two sources but gets one allowance. +# 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 @@ -39,7 +40,8 @@ ok_liheap_gross_income: 24_000 ok_liheap_net_income: 18_240 -# C7 FY2027 per-worker earned allowance limited to actual1200 earnings.7200-min(1200,2880)=6000; remaining allowance does not reduce pension. +# 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 @@ -102,7 +104,8 @@ ok_liheap_income_limit: 20_748 ok_liheap_net_income: 17_874 -# Registerpp580-581 permits age60+ or disabled person costs.30000-2880 workerallowance-2400 eldermedical-1200 disabledmedical=23520. Age59 nondisabled medical3600 is not deductible. +# 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 @@ -133,7 +136,7 @@ is_in_k12_school: false is_disabled: true ssi: 0 - social_security: 6_000 + social_security_disability: 6_000 other_medical_expenses: 1_200 spm_units: spm_unit: @@ -151,7 +154,7 @@ ok_liheap_gross_income: 30_000 ok_liheap_net_income: 23_520 -# Registerp581 and C7FY2027:12000-2880 earnedallowance-1200 supportpaid=7920. +# 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 @@ -182,7 +185,7 @@ ok_liheap_gross_income: 12_000 ok_liheap_net_income: 7_920 -# Earned deduction first limited to1200; further legallymandated support2400 cannot make finalnetincome negative. +# 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 @@ -213,7 +216,8 @@ ok_liheap_gross_income: 1_200 ok_liheap_net_income: 0 -# Registerp581 allowsOKDHSCCS copay for actualrecipients. Annualcopay1200 (100monthly) is deductedonce withpositivesubsidy:12000-2880-1200=7920. +# 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 @@ -250,7 +254,8 @@ ok_liheap_gross_income: 12_000 ok_liheap_net_income: 7_920 -# Registerp581 receipt condition: withzeroCCSsubsidy, a scheduledcopay1200 is not a deductibleactualrecipient expense.12000-2880=9120. +# 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 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 index 58cec262bb8..f91a4cb6946 100644 --- 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 @@ -1,7 +1,8 @@ -# Source-derived Oklahoma ordinary heating cases under contract v1.3. -# Current C1 need and C7 earned amounts are tested in2027. +# Oklahoma LIHEAP regular heating cases. +# Cases dated 2027 use the current Appendix C-1 need standards and Appendix C-7 earned income deduction. -# Current340:20-1-11(a)(4), C1p4/C7p1:13200-2880-4776=5544=462monthly. C7Ap1 ordinaryfuel,size1-3,401-700=>265 despite10annual bill. Regular heating schedule has no actual-expense cap. +# 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: @@ -51,7 +52,8 @@ ok_liheap_eligible: true ok_liheap: 265 -# C7p1 allowance12000-2880=9120=760monthly; C7Ap1 deliveredfuel,size1-3,701orhigher pays280. The10primary bill does not cap the ordinary scheduled award. +# 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: @@ -113,7 +115,10 @@ ok_liheap_eligible: [false, false, true, false] ok_liheap: [0, 0, 150, 0] -# Current340:20-1-11(a)(4),(c), C1p4/C7p1: ineligible12000-2880-600medical-1200support-4776need=2544. Gross2544+6000eligible+1200annualTANF=9744. Net9744-2880eligibleallowance-600eligiblesupport-600annualCCScopay=5664=472monthly; C7Ap1 ordinary,size2=>265. No duplicate ineligible deductions or SPM transfers. +# 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: @@ -179,7 +184,8 @@ ok_liheap_eligible: true ok_liheap: 265 -# Current340:20-1-11(a)(1),(4),(c):18000+4344deemed=22344gross exceeds20748size1limit. Net22344-2880=19464 does not restore eligibility. +# 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: @@ -232,7 +238,8 @@ ok_liheap_eligible: false ok_liheap: 0 -# Current340:20-1-10 and C7Ap1 ordinaryfuel,size1,0net=>365. OutsideOK or explicitNONE gives0; no cooling/crisis award substituted. +# 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: @@ -249,11 +256,10 @@ output: ok_liheap: [365, 0, 0] -# Plan Section 1.9 counts Social Security "Excluding MediCare deduction". Both retirees get $1,780/mo (21,360/yr). -# Person 1 pays the 2026 standard Part B premium 202.90 x 12 = 2,434.80: countable 21,360 - 2,434.80 = 18,925.20 -# -> 1,577.10/mo rounds to 1,577 <= 1,696 (2026 size 1 limit 20,352/yr); no deductions, net band 3 -> natural gas 235. -# Person 2 pays no premium: 21,360/12 = 1,780 > 1,696 -> ineligible, 0. -- name: Case 7, Social Security net of the Medicare Part B premium decides eligibility for a retiree. +# 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: @@ -269,12 +275,12 @@ ok_child_care_subsidies: [0, 0] ok_ccs_copay: [0, 0] output: - ok_liheap_countable_income: [18_925.20, 21_360] - ok_liheap_gross_income: [18_925.20, 21_360] + 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: [true, false] + ok_liheap_eligible: [false, false] ok_liheap_net_income: [18_925.20, 21_360] - ok_liheap: [235, 0] + 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. @@ -349,10 +355,10 @@ 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. -# With no Social Security to net it from, the full 2026 Part B premium 202.90 x 12 = 2,434.80 is deducted. +# 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 without Social Security deducts the full Medicare Part B premium. +- 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: @@ -385,12 +391,11 @@ ok_liheap_net_income: 6_565.20 ok_liheap: 265 -# Social Security 1,000/mo (12,000) absorbs the whole 2026 Part B premium 202.90 x 12 = 2,434.80 in countable income: -# 12,000 - 2,434.80 = 9,565.20 -> 797.10/mo rounds to 797 <= 1,696, eligible. The Part B deduction is -# max(2,434.80 - 12,000, 0) = 0, so only the 150/mo Medigap premium (1,800) is deducted. -# Net 9,565.20 - 1,800 = 7,765.20 -> 647.10/mo rounds to 647, band 2 (401-700) -> natural gas 265. -- name: Case 12, a retiree deducts another health premium while the Part B premium is only netted from Social - Security. +# 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: @@ -416,9 +421,39 @@ members: [person1] state_code: OK output: - ok_liheap_countable_income: 9_565.20 - ok_liheap_gross_income: 9_565.20 - ok_liheap_income_deductions: 1_800 + 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 index 09226f970a1..426e283c3c9 100644 --- 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 @@ -1,5 +1,4 @@ -# Source-derived Oklahoma ordinary heating cases under contract v1.3. -# Current C1 need and C7 earned amounts are tested in2027. +# 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 @@ -71,7 +70,7 @@ ok_liheap_immigration_eligible: [true, false, false, false] ok_liheap_household_size: 1 -# Current340:20-1-10(h)(3) requires at least one eligible member; zero size has no one-person income allowance. +# 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: 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 index 99fe601647c..86c04d3343e 100644 --- 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 @@ -1,6 +1,8 @@ # Oklahoma independent fully qualified household components; no final eligibility or award is asserted. -# C7A p1 and matchingFY2026matrix literal36cells:4tables*3monthlybands*3sizegroups. Directbill10 doesnotcapfixedmatrix. HIRunknownfuel is supportedallfuels;roomer4+ zerosretained. Ungatedamountonly. +# 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 @@ -12,8 +14,6 @@ PROPANE, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED, UNSPECIFIED] - gas_expense: [10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 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] @@ -26,8 +26,6 @@ 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] - bottled_gas_expense: [0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 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] @@ -43,47 +41,41 @@ 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] - gas_expense: [1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200, 1_200] 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] -# C7A ordinaryfuelmonthly500 row: sizes1-3=>265,4-6=>292,7+=>312. +# 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] - gas_expense: [1_200, 1_200, 1_200, 1_200] 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] -# C7Aheaders explicitlymap ordinarygas/electricity/wood/coal anddeliveredLPG/oil/kerosene. ROOMERchangesonlyheat-in-rentschedule; directfuelrowsremainunchanged. +# 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] - gas_expense: [10, 0, 0, 0, 0, 0, 0] 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] - pre_subsidy_electricity_expense: [0, 10, 0, 0, 0, 0, 0] - wood_expense: [0, 0, 10, 0, 0, 0, 0] - coal_expense: [0, 0, 0, 10, 0, 0, 0] - bottled_gas_expense: [0, 0, 0, 0, 10, 0, 0] - fuel_oil_expense: [0, 0, 0, 0, 0, 10, 10] output: ok_liheap_matrix_amount: [365, 365, 365, 365, 425, 425, 425] -# C7A allenergysourcesHIRtables give150standard/70roomer atzero income,size1. ExplicitNONE hasnoheat; unknownfuelpermittedHIR. No finalhousingeligibility assertion. +# 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 @@ -91,7 +83,6 @@ input: state_code: [OK, OK, OK] heating_type: [UNSPECIFIED, UNSPECIFIED, NONE] - gas_expense: [0, 0, 0] heat_expense_included_in_rent: [true, true, true] ok_liheap_dwelling_type: [STANDARD, ROOMER, STANDARD] ok_liheap_household_size: [1, 1, 1] @@ -99,14 +90,13 @@ output: ok_liheap_matrix_amount: [150, 70, 0] -# Matrix guardszero size and state; doesnotassertmixedstatusdeemingorfinaleligibility. +# 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] - gas_expense: [1_200, 1_200] ok_liheap_household_size: [0, 1] ok_liheap_net_income: [0, 0] output: @@ -121,9 +111,6 @@ input: state_code: [OK, OK, OK, OK] heating_type: [OTHER, SOLAR, UNSPECIFIED, NATURAL_GAS] - other_heating_fuel_expense: [600, 0, 0, 0] - pre_subsidy_electricity_expense: [0, 600, 0, 0] - gas_expense: [0, 0, 0, 600] 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] 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 index 34b133ff7f7..7a9a415c080 100644 --- 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 @@ -26,21 +26,27 @@ def formula(spm_unit, period, parameters): 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 (d)(2) verifies - # "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. + # 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. 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 index 718adeb401c..3da403ab4b4 100644 --- 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 @@ -10,6 +10,7 @@ class ok_liheap_income_limit(Variable): 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", ) 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 index 71e1e42b512..6f1a75f2898 100644 --- 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 @@ -12,7 +12,8 @@ class ok_liheap_countable_earned_income(Variable): # 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", - "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-50-7-22", + # 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): 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 index 7923503dd98..942ab1e7d3f 100644 --- 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 @@ -27,13 +27,5 @@ def formula(person, period, parameters): # 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) - # Plan Section 1.9 checks "Excluding MediCare deduction" for Social - # Security in FY2025-FY2027, so the benefit is counted net of the - # Part B premium the person pays. medicare_part_b_premium is zero for - # a person who is not enrolled and excludes the share a Medicare - # Savings Program pays. OAC 340:20-1-11(a) uses gross income before - # recoupment or garnishment and is silent on premium withholding. - premium = person("medicare_part_b_premium", period) - social_security = max_(person("social_security", period) - premium, 0) # TANF is an SPM aggregate and is counted separately once. - return income + social_security + return income 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 index 8399435ad3d..0a4451b0858 100644 --- 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 @@ -9,10 +9,9 @@ class ok_liheap_income_deductions(Variable): label = "Oklahoma LIHEAP personal income deductions" defined_for = StateCode.OK reference = ( - # OAC 340:20-1-11(a)(4), (c): these person deductions apply to - # ineligible-member deeming and eligible members' net income. - # OAC 340:50-7-31(a)(3)(A)(v)-(vi) lists health insurance and - # Medicare premiums as allowable medical expenses. + # 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", ) @@ -23,21 +22,18 @@ def formula(person, period, parameters): # 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_disabled", period + "is_usda_disabled", period ) - # is_disabled approximates the incorporated SNAP disability test. - # Countable income nets the Part B premium from Social Security, - # floored at zero, so only the premium that Social Security does not - # cover is deducted here; no premium dollar is counted twice. - part_b_premium = person("medicare_part_b_premium", period) - social_security = max_(person("social_security", period), 0) - unnetted_part_b_premium = max_(part_b_premium - social_security, 0) - other_premiums = max_( - person("health_insurance_premiums_without_medicare_part_b", period), 0 - ) - other_expenses = max_(person("other_medical_expenses", period), 0) - medical_expenses = other_expenses + other_premiums + unnetted_part_b_premium + # 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. 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 index e636c3d9088..08eb2e7b64f 100644 --- a/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap.py +++ b/policyengine_us/variables/gov/states/ok/dhs/liheap/ok_liheap.py @@ -11,7 +11,7 @@ class ok_liheap(Variable): 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", + "https://oklahoma.gov/content/dam/ok/en/okdhs/documents/searchcenter/okdhsformresults/c-7-a.pdf#page=1", ) def formula(spm_unit, period, parameters):