From ecb80769e5c4d93fb64ce798f00a84e5d8ad2cf7 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Tue, 12 May 2026 11:59:45 -0400 Subject: [PATCH 01/10] Implement Oklahoma Unemployment Insurance (ref #8264) Co-Authored-By: Claude Opus 4.7 (1M context) --- changelog.d/ok-ui.added.md | 1 + .../eligibility/min_taxable_wages.yaml | 12 + .../min_total_wages_multiplier.yaml | 12 + .../ok/oesc/unemployment_insurance/index.yaml | 4 + .../unemployment_insurance/mba/max_weeks.yaml | 17 + .../partial/disregard.yaml | 12 + .../unemployment_insurance/wba/divisor.yaml | 12 + .../wba/max_amount.yaml | 20 + .../wba/min_amount.yaml | 12 + .../unemployment/taxable_wage_base.yaml | 17 +- .../unemployment_insurance/edge_cases.yaml | 505 ++++++++++++++++++ .../unemployment_insurance/integration.yaml | 209 ++++++++ .../ok/oesc/unemployment_insurance/ok_ui.yaml | 83 +++ .../ok_ui_maximum_benefit_amount.yaml | 44 ++ .../ok_ui_meets_alternate_wages_test.yaml | 65 +++ .../ok_ui_meets_high_quarter_test.yaml | 84 +++ .../ok_ui_monetarily_eligible.yaml | 74 +++ .../ok_ui_weekly_benefit_rate.yaml | 101 ++++ .../ok_ui_weekly_payable.yaml | 98 ++++ .../ok/oesc/unemployment_insurance/ok_ui.py | 36 ++ .../ok_ui_base_period_taxable_wages.py | 23 + .../ok_ui_base_period_total_wages.py | 22 + .../ok_ui_gross_weekly_earnings.py | 20 + .../ok_ui_high_quarter_taxable_wages.py | 22 + .../ok_ui_maximum_benefit_amount.py | 24 + .../ok_ui_meets_alternate_wages_test.py | 22 + .../ok_ui_meets_high_quarter_test.py | 23 + .../ok_ui_monetarily_eligible.py | 17 + .../ok_ui_weekly_benefit_rate.py | 23 + .../ok_ui_weekly_payable.py | 23 + 30 files changed, 1633 insertions(+), 4 deletions(-) create mode 100644 changelog.d/ok-ui.added.md create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/index.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py diff --git a/changelog.d/ok-ui.added.md b/changelog.d/ok-ui.added.md new file mode 100644 index 00000000000..95dae71528a --- /dev/null +++ b/changelog.d/ok-ui.added.md @@ -0,0 +1 @@ +Add Oklahoma Unemployment Insurance. diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml new file mode 100644 index 00000000000..9d5366c0245 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml @@ -0,0 +1,12 @@ +description: Oklahoma sets the minimum taxable base period wages at this amount for monetary eligibility under the Unemployment Insurance program. + +values: + 1980-07-01: 1_500 + +metadata: + unit: currency-USD + period: year + label: Oklahoma UI minimum taxable base period wages + reference: + - title: 40 O.S. §2-207(A) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml new file mode 100644 index 00000000000..81bcccc57d1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml @@ -0,0 +1,12 @@ +description: Oklahoma uses this share of high quarter wages as the minimum total base period wages for monetary eligibility under the Unemployment Insurance program. + +values: + 1980-07-01: 1.5 + +metadata: + unit: /1 + period: year + label: Oklahoma UI minimum total wages multiplier + reference: + - title: 40 O.S. §2-207(A) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/index.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/index.yaml new file mode 100644 index 00000000000..cb39cde8a79 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/index.yaml @@ -0,0 +1,4 @@ +metadata: + propagate_metadata_to_children: true + economy: false + household: true diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml new file mode 100644 index 00000000000..8aeb073b58f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml @@ -0,0 +1,17 @@ +description: Oklahoma limits unemployment compensation benefits to this number of weeks within a benefit year under the Unemployment Insurance program. + +values: + 0000-01-01: 26 + 2023-01-01: 16 + +metadata: + unit: week + period: year + label: Oklahoma UI maximum benefit weeks + reference: + - title: 40 O.S. §1-231 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=48 + - title: 40 O.S. §2-106 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + - title: Oklahoma House Bill 1933 (2022) + href: https://www.oklegislature.gov/cf_pdf/2021-22%20ENR/hB/HB1933%20ENR.PDF diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml new file mode 100644 index 00000000000..265820c4ca4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml @@ -0,0 +1,12 @@ +description: Oklahoma disregards this amount of weekly earnings before reducing the partial weekly benefit under the Unemployment Insurance program. + +values: + 1994-07-01: 100 + +metadata: + unit: currency-USD + period: week + label: Oklahoma UI partial benefit earnings disregard + reference: + - title: 40 O.S. §2-105 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml new file mode 100644 index 00000000000..dc18c9b6c3d --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml @@ -0,0 +1,12 @@ +description: Oklahoma uses this divisor on taxable high quarter wages to compute the weekly benefit amount under the Unemployment Insurance program. + +values: + 1980-07-01: 23 + +metadata: + unit: /1 + period: year + label: Oklahoma UI weekly benefit divisor + reference: + - title: 40 O.S. §2-104(A) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml new file mode 100644 index 00000000000..3198b60eca6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml @@ -0,0 +1,20 @@ +description: Oklahoma sets the maximum weekly benefit amount at this amount under the Unemployment Insurance program. + +values: + 2024-01-01: 519 + 2025-01-01: 541 + 2026-01-01: 649 + +metadata: + unit: currency-USD + period: week + label: Oklahoma UI maximum weekly benefit amount + reference: + - title: 40 O.S. §2-104(B) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49 + - title: OESC Claimant Handbook OES-339 (Rev. 05-2025), page 4 + href: https://oklahoma.gov/content/dam/ok/en/oesc/documents/forms/OES-339.pdf#page=4 + - title: OESC Important Numbers for 2025 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2025.pdf#page=1 + - title: OESC Important Numbers for 2026 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml new file mode 100644 index 00000000000..e552cf652d1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml @@ -0,0 +1,12 @@ +description: Oklahoma sets the minimum weekly benefit amount at this amount under the Unemployment Insurance program. + +values: + 1980-07-01: 16 + +metadata: + unit: currency-USD + period: week + label: Oklahoma UI minimum weekly benefit amount + reference: + - title: 40 O.S. §2-104(A) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49 diff --git a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml index aeec506fd45..2b897853cec 100644 --- a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml +++ b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml @@ -1,15 +1,24 @@ -description: Employer-side unemployment insurance taxable wage base for Oklahoma. +description: Oklahoma sets the annual unemployment insurance taxable wage base at this amount under the Unemployment Insurance program. + values: 0000-01-01: 27_000 + 2025-01-01: 28_200 + 2026-01-01: 25_000 metadata: period: year unit: currency-USD label: Oklahoma unemployment taxable wage base reference: - - title: Oklahoma Statutes Title 40 Section 1-223 - href: https://oksenate.gov/sites/default/files/2022-05/os40.pdf#page=32 - - title: Oklahoma Employment Security Commission important numbers for 2026 + - title: 40 O.S. §1-218 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=42 + - title: 40 O.S. §1-223 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44 + - title: 40 O.S. §2-207(B) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 + - title: Oklahoma Employment Security Commission Important Numbers for 2025 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2025.pdf#page=1 + - title: Oklahoma Employment Security Commission Important Numbers for 2026 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 - title: Tax Measures of State Unemployment Insurance Tax Systems, CY 2024 href: https://oui.doleta.gov/unemploy/pdf/sigmeasures/sigmeasuitaxsys24.pdf#page=46 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml new file mode 100644 index 00000000000..29df58d169a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml @@ -0,0 +1,505 @@ +# Edge case tests for Oklahoma Unemployment Insurance (OK UI). +# Boundary conditions for the monetary eligibility tests (§ 2-207), +# the WBA clamp (§ 2-104), the partial-benefit subtraction (§ 2-105), +# the MBA / max_weeks transition (§ 2-106, HB 1933), and the +# defined_for state gate. + +# --- Test A boundary (§ 2-207(A)): taxable >= $1,500 AND total >= 1.5 * HQW --- + +- name: Case 1, Test A taxable wages exactly at $1,500 threshold. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 1_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 1_500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A taxable prong: $1,500 >= $1,500 -> passes (>= operator). + # Test A multiplier prong: $1,500 >= 1.5 * $1,000 = $1,500 -> passes (>=). + # Test A: both prongs pass. + ok_ui_meets_high_quarter_test: true + # Test B: total $1,500 < $27,400 (2024 wage base) -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: true + +- name: Case 2, Test A taxable wages one dollar below threshold. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 1_000 + ok_ui_base_period_taxable_wages: 1_499 + ok_ui_base_period_total_wages: 1_500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A taxable prong: $1,499 < $1,500 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: $1,499 > 0 but total $1,500 < $27,400 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + +- name: Case 3, Test A total wages exactly at 1.5x HQW boundary. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 5_000 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A multiplier prong: $15,000 >= 1.5 * $10,000 = $15,000 -> passes (>= operator). + # Test A taxable prong: $5,000 >= $1,500 -> passes. + ok_ui_meets_high_quarter_test: true + ok_ui_monetarily_eligible: true + +- name: Case 4, Test A total wages one dollar below 1.5x HQW boundary. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 5_000 + ok_ui_base_period_total_wages: 14_999 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A multiplier prong: $14,999 < 1.5 * $10,000 = $15,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: total $14,999 < $27,400 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + +# --- Test B boundary (§ 2-207(B)): taxable > 0 AND total >= wage base --- + +- name: Case 5, Test B total wages exactly at 2025 taxable wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_200 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $28,200 < 1.5 * $20,000 = $30,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: taxable $2,000 > $0 AND $28,200 >= $28,200 (2025 wage base) -> passes (>=). + ok_ui_meets_alternate_wages_test: true + ok_ui_monetarily_eligible: true + +- name: Case 6, Test B total wages one dollar below 2025 taxable wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_199 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $28,199 < $30,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: $28,199 < $28,200 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + +# --- WBA clamp boundaries (§ 2-104(A): floor(HQW / 23), clamped to [$16, max]) --- + +- name: Case 7, WBA below minimum - HQW $367 clamped up to $16 floor. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 367 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 2_250 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($367 / 23) = floor($15.957) = $15 -> below $16 minimum -> clamped to $16. + ok_ui_weekly_benefit_rate: 16 + +- name: Case 8, WBA exactly at minimum - HQW $368 yields $16. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 368 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 2_250 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($368 / 23) = floor($16.0) = $16 -> exactly at minimum. + ok_ui_weekly_benefit_rate: 16 + +- name: Case 9, WBA exactly at 2024 maximum - HQW $11,937 yields $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_937 + ok_ui_base_period_taxable_wages: 11_937 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # 519 * 23 = $11,937 exactly; floor($11,937 / 23) = $519. + # 2024 max is $519 -> no clamp needed, exactly at boundary. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 10, WBA still at 2024 max - HQW $11,938 yields $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_938 + ok_ui_base_period_taxable_wages: 11_938 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($11,938 / 23) = floor($519.043) = $519 -> at 2024 max, no clamp. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 11, WBA clamped down at 2024 max - HQW $11,960 yields $520 raw, clamped to $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_960 + ok_ui_base_period_taxable_wages: 11_960 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # 520 * 23 = $11,960 exactly; floor($11,960 / 23) = $520. + # $520 > $519 (2024 max) -> clamped down to $519. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 12, very high HQW clamped to 2025 max $541. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 100_000 + ok_ui_base_period_taxable_wages: 100_000 + ok_ui_base_period_total_wages: 300_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($100,000 / 23) = floor($4,347.83) = $4,347 -> far above $541 (2025 max) -> clamped to $541. + ok_ui_weekly_benefit_rate: 541 + +# --- Zero income / zero weeks --- + +- name: Case 13, all wages zero - both tests fail, no benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 0 + ok_ui_base_period_taxable_wages: 0 + ok_ui_base_period_total_wages: 0 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $0 < $1,500 -> fails. Test B: $0 not > 0 -> fails. + ok_ui_monetarily_eligible: false + # defined_for gate -> $0. + ok_ui: 0 + +- name: Case 14, eligible but zero weeks unemployed - annual benefit zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 0 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + # WBA: floor($9,200 / 23) = $400. + ok_ui_weekly_benefit_rate: 400 + # MBA = $400 * 16 = $6,400 (defined regardless of weeks worked). + ok_ui_maximum_benefit_amount: 6_400 + # Annual: min($400 * 0, $6,400) = $0. + ok_ui: 0 + +# --- Partial benefit edge cases (§ 2-105) --- + +- name: Case 15, weekly earnings exactly at $100 disregard - full WBA paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 100 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $100 - $100) = $0; payable = max(0, $400 - 0) = $400. + ok_ui_weekly_payable: 400 + +- name: Case 16, weekly earnings one dollar above disregard - WBA reduced by $1. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 101 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $101 - $100) = $1; payable = max(0, $400 - $1) = $399. + ok_ui_weekly_payable: 399 + +- name: Case 17, weekly earnings exactly at WBA + disregard - payable zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $500 - $100) = $400; payable = max(0, $400 - $400) = $0. + ok_ui_weekly_payable: 0 + +- name: Case 18, weekly earnings above WBA + disregard - payable floored at zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 501 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $501 - $100) = $401; raw payable = $400 - $401 = -$1 -> max(0, -1) = $0. + ok_ui_weekly_payable: 0 + +# --- max_weeks transition (§ 2-106, HB 1933): 26 pre-2023, 16 from 2023-01-01 --- + +- name: Case 19, year 2022 - pre-2023 max_weeks of 26. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # 2022 max_weeks = 26; MBA = $300 * 26 = $7,800. + ok_ui_maximum_benefit_amount: 7_800 + +- name: Case 20, year 2024 - post-2023 max_weeks of 16. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # Same HQW as Case 19 to isolate the max_weeks change. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # 2024 max_weeks = 16; MBA = $300 * 16 = $4,800. + ok_ui_maximum_benefit_amount: 4_800 + +# --- State gate (defined_for = "ok_ui_monetarily_eligible" with StateCode.OK) --- + +- name: Case 21, non-OK state with otherwise eligible inputs - benefit zeroed. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: TX + output: + people: + person1: + # state_code TX: StateCode.OK gate on upstream variables and the + # ok_ui_monetarily_eligible defined_for cascade returns $0. + ok_ui: 0 + +- name: Case 22, OK state with same inputs as Case 21 - benefit positive. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + # WBA: floor($11,500 / 23) = $500; within 2024 [$16, $519] -> $500. + ok_ui_weekly_benefit_rate: 500 + # MBA = $500 * 16 = $8,000; annual = min($500 * 16, $8,000) = $8,000. + ok_ui: 8_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml new file mode 100644 index 00000000000..e134af4cce7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml @@ -0,0 +1,209 @@ +# Integration tests for Oklahoma Unemployment Insurance (OK UI). +# End-to-end scenarios checking ok_ui together with intermediate variables. +# References: 40 O.S. §§1-202, 1-218, 1-223, 1-231, 2-102, 2-104, 2-105, 2-106, 2-207; +# OESC Claimant Handbook OES-339 (Rev. 05-2025); OESC Important Numbers 2024/2025/2026. + +- name: Case 1, eligible single claimant with mid-range wages in 2024. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $11,500 >= $1,500 (ok); total $35,000 >= 1.5 * $11,500 = $17,250 -> passes. + ok_ui_meets_high_quarter_test: true + ok_ui_monetarily_eligible: true + # WBA: floor($11,500 / 23) = $500; within 2024 [$16, $519] -> $500. + ok_ui_weekly_benefit_rate: 500 + # Earnings $0 -> full WBA paid. + ok_ui_weekly_payable: 500 + # 2024 max_weeks = 16 (post-2023); MBA = $500 * 16 = $8,000. + ok_ui_maximum_benefit_amount: 8_000 + # Annual: min($500 * 16, $8,000) = $8,000. + ok_ui: 8_000 + +- name: Case 2, ineligible claimant - wages too low in 2024. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ok_ui_high_quarter_taxable_wages: 5_000 + ok_ui_base_period_taxable_wages: 500 + ok_ui_base_period_total_wages: 5_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 12 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $500 < $1,500 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: total $5,000 < $27,400 (2024 wage base) -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + # defined_for gate -> $0. + ok_ui: 0 + +- name: Case 3, high earner in 2025 capped at $541 max WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + ok_ui_high_quarter_taxable_wages: 30_000 + ok_ui_base_period_taxable_wages: 30_000 + ok_ui_base_period_total_wages: 90_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $30,000 >= $1,500; total $90,000 >= 1.5 * $30,000 = $45,000 -> passes. + ok_ui_monetarily_eligible: true + # WBA: floor($30,000 / 23) = floor($1,304.35) = $1,304; clamped to $541 (2025 max). + ok_ui_weekly_benefit_rate: 541 + ok_ui_weekly_payable: 541 + # MBA = $541 * 16 = $8,656. + ok_ui_maximum_benefit_amount: 8_656 + # Annual: min($541 * 16, $8,656) = $8,656. + ok_ui: 8_656 + +- name: Case 4, partial benefit week - claimant works part-time. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + # HQW $9,200 -> WBA = $400. + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 200 + weeks_unemployed: 10 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $9,200 >= $1,500; total $30,000 >= 1.5 * $9,200 = $13,800 -> passes. + ok_ui_monetarily_eligible: true + # WBA: floor($9,200 / 23) = $400; within 2025 [$16, $541] -> $400. + ok_ui_weekly_benefit_rate: 400 + # Earnings offset: max(0, $200 - $100) = $100. + # Partial: max(0, $400 - $100) = $300. + ok_ui_weekly_payable: 300 + # MBA = $400 * 16 = $6,400. + ok_ui_maximum_benefit_amount: 6_400 + # Annual: min($300 * 10, $6,400) = min($3,000, $6,400) = $3,000. + ok_ui: 3_000 + +- name: Case 5, pre-2023 regime - 26-week max_weeks doubles MBA. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + # HQW $6,900 -> WBA = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 26 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $6,900 >= $1,500; total $20,700 >= 1.5 * $6,900 = $10,350 -> passes. + ok_ui_monetarily_eligible: true + # WBA: floor($6,900 / 23) = $300. + ok_ui_weekly_benefit_rate: 300 + ok_ui_weekly_payable: 300 + # Pre-2023 max_weeks = 26; MBA = $300 * 26 = $7,800. + ok_ui_maximum_benefit_amount: 7_800 + # Annual: min($300 * 26, $7,800) = $7,800. + ok_ui: 7_800 + +- name: Case 6, Test B prong - low taxable but high total wages in 2025. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_500 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $2,000 >= $1,500 (ok); total $28,500 < 1.5 * $20,000 = $30,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: taxable $2,000 > $0 (ok); total $28,500 >= $28,200 (2025 wage base) -> passes. + ok_ui_meets_alternate_wages_test: true + ok_ui_monetarily_eligible: true + # WBA: floor($20,000 / 23) = floor($869.57) = $869; clamped to $541 (2025 max). + ok_ui_weekly_benefit_rate: 541 + ok_ui_weekly_payable: 541 + # MBA = $541 * 16 = $8,656. + ok_ui_maximum_benefit_amount: 8_656 + # Annual: min($541 * 16, $8,656) = $8,656. + ok_ui: 8_656 + +- name: Case 7, out-of-state claimant - state gate yields zero benefit. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: TX + output: + people: + person1: + # state_code TX != OK -> defined_for = StateCode.OK gate -> $0. + # Note: intermediate variables (eligibility, WBA, etc.) may still + # compute, but the top-level ok_ui is gated to OK households only. + ok_ui: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml new file mode 100644 index 00000000000..79bf70b11bc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml @@ -0,0 +1,83 @@ +# Tests for Oklahoma UI annual benefit (top-level variable). +# Annual benefit = min(partial_weekly_benefit * weeks_unemployed, MBA). +# Gated by ok_ui_monetarily_eligible (defined_for) and StateCode.OK. +# Reference: 40 O.S. §2-105, §2-106. + +- name: Case 1, eligible claimant - 10 weeks unemployed yields partial of MBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $9,200 -> WBA = $400 (within 2025 [$16, $541] range). + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 10 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $9,200 >= $1,500 AND total $30,000 >= 1.5 * $9,200 = $13,800 -> passes. + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 400 + ok_ui_weekly_payable: 400 + # MBA = $400 * 16 weeks = $6,400. + ok_ui_maximum_benefit_amount: 6_400 + # Annual = min($400 * 10, $6,400) = min($4,000, $6,400) = $4,000. + ok_ui: 4_000 + +- name: Case 2, eligible claimant - weeks exceed max_weeks - capped at MBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 20 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 400 + ok_ui_maximum_benefit_amount: 6_400 + # Annual = min($400 * 20, $6,400) = min($8,000, $6,400) = $6,400 (capped at MBA). + ok_ui: 6_400 + +- name: Case 3, monetarily ineligible - zero benefit regardless of weeks. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_000 + ok_ui_base_period_total_wages: 12_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $1,000 < $1,500 -> fails. + # Test B: total $12,000 < $28,200 (2025 wage base) -> fails. + ok_ui_monetarily_eligible: false + # defined_for gate -> $0. + ok_ui: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml new file mode 100644 index 00000000000..2a0ea54c2c9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml @@ -0,0 +1,44 @@ +# Tests for Oklahoma UI maximum benefit amount (40 O.S. §2-106). +# MBA = WBA * max_weeks. +# max_weeks: 26 before 2023-01-01, 16 from 2023-01-01. +# Reference: 40 O.S. §2-106; HB 1933 (2022). + +- name: Case 1, 2024 - WBA $400 yields MBA $6,400 over 16 weeks. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $9,200 -> floor($9,200 / 23) = $400 (within 2024 [$16, $519] range). + ok_ui_high_quarter_taxable_wages: 9_200 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # 2024 max_weeks = 16; MBA = $400 * 16 = $6,400. + ok_ui_maximum_benefit_amount: 6_400 + +- name: Case 2, pre-2023 - WBA $300 yields MBA $7,800 over 26 weeks. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # Pre-2023 max_weeks = 26; MBA = $300 * 26 = $7,800. + ok_ui_maximum_benefit_amount: 7_800 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml new file mode 100644 index 00000000000..f1a9d1cf37c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml @@ -0,0 +1,65 @@ +# Tests for Oklahoma UI monetary eligibility Test B (40 O.S. §2-207(B)). +# Both conditions must be met: +# 1. Base-period taxable wages > 0. +# 2. Total base-period wages >= annual taxable wage base for the claim year. +# 2025 taxable wage base = $28,200 (gov.states.ok.tax.payroll.unemployment.taxable_wage_base). +# Reference: 40 O.S. §2-207(B); 40 O.S. §1-223. + +- name: Case 1, both prongs pass with minimal taxable and total at wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 7_050 + ok_ui_base_period_taxable_wages: 1 + ok_ui_base_period_total_wages: 28_200 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $1 > $0 (passes prong 1). + # Total $28,200 >= $28,200 (2025 wage base) -> passes prong 2. + ok_ui_meets_alternate_wages_test: true + +- name: Case 2, fails taxable wages prong - zero taxable wages. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 0 + ok_ui_base_period_taxable_wages: 0 + ok_ui_base_period_total_wages: 50_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $0 is not > $0 -> fails prong 1. + ok_ui_meets_alternate_wages_test: false + +- name: Case 3, fails total-wages prong by one dollar below 2025 wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 7_000 + ok_ui_base_period_taxable_wages: 1_000 + ok_ui_base_period_total_wages: 28_199 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $1,000 > 0 (passes prong 1). + # Total $28,199 < $28,200 (2025 wage base) -> fails prong 2. + ok_ui_meets_alternate_wages_test: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml new file mode 100644 index 00000000000..973dce5260f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml @@ -0,0 +1,84 @@ +# Tests for Oklahoma UI monetary eligibility Test A (40 O.S. §2-207(A)). +# Both conditions must be met: +# 1. Base-period taxable wages >= $1,500. +# 2. Total base-period wages >= 1.5 x high-quarter taxable wages. +# Reference: 40 O.S. §2-207(A). + +- name: Case 1, both prongs pass with margin. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $1,500 >= $1,500 (passes prong 1). + # Total $15,000 >= 1.5 * $10,000 = $15,000 (passes prong 2). + ok_ui_meets_high_quarter_test: true + +- name: Case 2, fails taxable wages floor by one dollar. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_499 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $1,499 < $1,500 -> fails prong 1. + ok_ui_meets_high_quarter_test: false + +- name: Case 3, fails 1.5x high-quarter multiplier by one dollar. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 14_999 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $2,000 >= $1,500 (passes prong 1). + # Total $14,999 < 1.5 * $10,000 = $15,000 -> fails prong 2. + ok_ui_meets_high_quarter_test: false + +- name: Case 4, boundary - taxable exactly at floor and total exactly at 1.5 x HQW. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable exactly $1,500 (passes prong 1; >= test). + # Total exactly $15,000 = 1.5 * $10,000 (passes prong 2; >= test). + ok_ui_meets_high_quarter_test: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml new file mode 100644 index 00000000000..a51f5b8bd51 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml @@ -0,0 +1,74 @@ +# Tests for Oklahoma UI overall monetary eligibility (40 O.S. §2-207). +# Eligible if Test A OR Test B passes: +# Test A (§2-207(A)): taxable >= $1,500 AND total >= 1.5 x HQW. +# Test B (§2-207(B)): taxable > 0 AND total >= annual taxable wage base. +# Reference: 40 O.S. §2-207. + +- name: Case 1, Test A passes alone (Test B fails on total below wage base). + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 5_000 + ok_ui_base_period_total_wages: 20_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $5,000 >= $1,500 AND $20,000 >= 1.5 * $10,000 = $15,000 -> passes. + # Test B: total $20,000 < $27,400 (2024 wage base) -> fails. + # Overall: A OR B = true. + ok_ui_meets_high_quarter_test: true + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: true + +- name: Case 2, Test B passes alone (Test A fails on 1.5x prong). + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $2,000 >= $1,500 (ok); total $28,500 < 1.5 * $20,000 = $30,000 -> fails. + # Test B: taxable $2,000 > $0 (ok); total $28,500 >= $28,200 (2025 wage base) -> passes. + # Overall: A OR B = true. + ok_ui_meets_high_quarter_test: false + ok_ui_meets_alternate_wages_test: true + ok_ui_monetarily_eligible: true + +- name: Case 3, both tests fail. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_000 + ok_ui_base_period_total_wages: 12_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $1,000 < $1,500 -> fails. + # Test B: total $12,000 < $28,200 (2025 wage base) -> fails. + # Overall: A OR B = false. + ok_ui_meets_high_quarter_test: false + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml new file mode 100644 index 00000000000..969d061f63f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml @@ -0,0 +1,101 @@ +# Tests for Oklahoma UI weekly benefit amount (40 O.S. §2-104(A), §2-102). +# Formula: WBA = clamp(floor(HQW_taxable / 23), [min=$16, max=annual_cap]). +# Annual max WBA: 2024=$519, 2025=$541, 2026=$649. +# Min WBA $16 has been the statutory floor since 1980. +# Reference: 40 O.S. §2-104(A), §2-102; OESC Important Numbers. + +- name: Case 1, handbook example - HQW $14,000 in 2024 clamped to max $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 14_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($14,000 / 23) = floor($608.69) = $608. + # $608 > $519 (2024 max) -> clamped to $519. + # Matches OES-339 Rev. 05-2025 page 4 worked example. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 2, low HQW lifted to statutory minimum $16. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 200 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($200 / 23) = floor($8.70) = $8. + # $8 < $16 -> lifted to $16 minimum. + ok_ui_weekly_benefit_rate: 16 + +- name: Case 3, mid HQW within 2025 range. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($10,000 / 23) = floor($434.78) = $434. + # $16 <= $434 <= $541 (2025 max) -> WBA = $434. + ok_ui_weekly_benefit_rate: 434 + +- name: Case 4, mid HQW within 2026 range. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($10,000 / 23) = $434. + # $16 <= $434 <= $649 (2026 max) -> WBA = $434. + ok_ui_weekly_benefit_rate: 434 + +- name: Case 5, high HQW clamped to 2026 maximum. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ok_ui_high_quarter_taxable_wages: 20_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($20,000 / 23) = floor($869.57) = $869. + # $869 > $649 (2026 max) -> clamped to $649. + ok_ui_weekly_benefit_rate: 649 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml new file mode 100644 index 00000000000..101e2c51e51 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml @@ -0,0 +1,98 @@ +# Tests for Oklahoma UI partial weekly benefit (40 O.S. §2-105). +# Formula: weekly_payable = max(0, WBA - max(0, weekly_earnings - $100)). +# The first $100 of weekly earnings is disregarded; every dollar above $100 +# reduces WBA dollar-for-dollar; result is floored at $0. +# Reference: 40 O.S. §2-105. + +- name: Case 1, weekly earnings below disregard - full WBA paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $9,200 -> floor($9,200 / 23) = $400 WBA (within 2025 range). + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 50 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Earnings $50 < $100 disregard -> earnings_offset = max(0, 50 - 100) = $0. + # Payable = max(0, $400 - $0) = $400. + ok_ui_weekly_payable: 400 + +- name: Case 2, weekly earnings exactly at disregard - full WBA paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 100 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Earnings $100 = $100 disregard -> earnings_offset = max(0, 100 - 100) = $0. + # Payable = max(0, $400 - $0) = $400. + ok_ui_weekly_payable: 400 + +- name: Case 3, weekly earnings above disregard - dollar-for-dollar reduction. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 150 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Earnings $150 > $100 -> earnings_offset = $150 - $100 = $50. + # Payable = max(0, $400 - $50) = $350. + ok_ui_weekly_payable: 350 + +- name: Case 4, weekly earnings so high payable would be negative - floored at zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 600 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Earnings $600 > $100 -> earnings_offset = $600 - $100 = $500. + # Raw payable = $400 - $500 = -$100; max(0, -$100) = $0. + ok_ui_weekly_payable: 0 diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py new file mode 100644 index 00000000000..aa008c6e789 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py @@ -0,0 +1,36 @@ +from policyengine_us.model_api import * + + +class ok_ui(Variable): + """Annual Oklahoma Unemployment Insurance benefit. Implements the + monetary eligibility tests (§ 2-207), weekly benefit rate (§ 2-104), + partial benefit subtraction (§ 2-105), and benefit duration cap + (§ 2-106 / § 1-231). + + Not modeled: § 1-202.1 / § 1-202.2 alternative and extended base + periods; § 2-104(B) max-WBA percentage derivation by fund condition + (only the resulting maximum dollar amount is parameterized); § 1-231(A) + claim-volume duration escalation to 20 or 26 weeks; § 2-107 portion- + of-a-week proration; § 2-108 approved training waiver; § 2-202 / + § 2-205.1 able-available-seeking-work; § 2-206 one-week waiting period; + § 2-208 alien-status rules; § 2-109 10x WBA requalification; all + § 2-404 through § 2-422 disqualifications. + """ + + value_type = float + entity = Person + label = "Oklahoma unemployment insurance" + unit = USD + definition_period = YEAR + defined_for = "ok_ui_monetarily_eligible" + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51", + ) + + def formula(person, period, parameters): + weekly_payable = person("ok_ui_weekly_payable", period) + maximum_benefit_amount = person("ok_ui_maximum_benefit_amount", period) + weeks_unemployed = person("weeks_unemployed", period) + annual_benefit = weekly_payable * weeks_unemployed + return min_(annual_benefit, maximum_benefit_amount) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py new file mode 100644 index 00000000000..e905611f4ec --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ok_ui_base_period_taxable_wages(Variable): + """Sum of taxable wages (capped at the Oklahoma taxable wage base per + quarter) across all four quarters of the base period, per 40 O.S. § 1-223 + and § 1-202. Used in the monetary-eligibility tests in § 2-207(A) and + § 2-207(B). PolicyEngine cannot derive quarterly wages from annual data, + so this is a direct input rather than a computed value; populate via test + fixtures or reform. + """ + + value_type = float + entity = Person + label = "Oklahoma UI base period taxable wages" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=24", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py new file mode 100644 index 00000000000..eafcf7b91c4 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ok_ui_base_period_total_wages(Variable): + """Sum of total (uncapped) gross wages across all four quarters of the + base period, per 40 O.S. § 1-218 and § 1-202. Used in the monetary- + eligibility tests in § 2-207(A) and § 2-207(B). PolicyEngine cannot derive + quarterly wages from annual data, so this is a direct input rather than a + computed value; populate via test fixtures or reform. + """ + + value_type = float + entity = Person + label = "Oklahoma UI base period total wages" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=24", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=42", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py new file mode 100644 index 00000000000..e8169c18a94 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class ok_ui_gross_weekly_earnings(Variable): + """Gross earnings during a week of partial unemployment, used to compute + the partial weekly benefit reduction per 40 O.S. § 2-105. Stored at the + annual definition period to match other UI inputs; populate via test + fixtures or reform. + """ + + value_type = float + entity = Person + label = "Oklahoma UI gross weekly earnings" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50" + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py new file mode 100644 index 00000000000..86e26658d8e --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ok_ui_high_quarter_taxable_wages(Variable): + """Wages paid in the claimant's highest base-period quarter, capped at the + Oklahoma taxable wage base per quarter. Used as the input to the weekly + benefit amount formula per 40 O.S. § 2-104(A). PolicyEngine cannot derive + quarterly wages from annual data, so this is a direct input rather than a + computed value; populate via test fixtures or reform. + """ + + value_type = float + entity = Person + label = "Oklahoma UI high quarter taxable wages" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py new file mode 100644 index 00000000000..c3952b11041 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class ok_ui_maximum_benefit_amount(Variable): + value_type = float + entity = Person + label = "Oklahoma UI maximum benefit amount" + unit = USD + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=48", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51", + ) + + def formula(person, period, parameters): + # § 2-106 caps benefits in a benefit year. Only the weeks-times-WBR + # prong of the three-prong lesser-of test is modeled; the annual-wage + # and wage-share caps in § 2-106 are not modeled because they depend + # on the state-fund conditional factor that we do not track at + # runtime. + p = parameters(period).gov.states.ok.oesc.unemployment_insurance.mba + weekly_benefit_rate = person("ok_ui_weekly_benefit_rate", period) + return weekly_benefit_rate * p.max_weeks diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py new file mode 100644 index 00000000000..73719d86412 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ok_ui_meets_alternate_wages_test(Variable): + value_type = bool + entity = Person + label = "Meets the Oklahoma UI alternate monetary eligibility test" + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56" + ) + + def formula(person, period, parameters): + base_period_taxable_wages = person("ok_ui_base_period_taxable_wages", period) + base_period_total_wages = person("ok_ui_base_period_total_wages", period) + taxable_wage_base = parameters( + period + ).gov.states.ok.tax.payroll.unemployment.taxable_wage_base + has_taxable_wages = base_period_taxable_wages > 0 + meets_wage_base = base_period_total_wages >= taxable_wage_base + return has_taxable_wages & meets_wage_base diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py new file mode 100644 index 00000000000..a4e832983ea --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ok_ui_meets_high_quarter_test(Variable): + value_type = bool + entity = Person + label = "Meets the Oklahoma UI high-quarter monetary eligibility test" + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56" + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ok.oesc.unemployment_insurance.eligibility + base_period_taxable_wages = person("ok_ui_base_period_taxable_wages", period) + base_period_total_wages = person("ok_ui_base_period_total_wages", period) + high_quarter_taxable_wages = person("ok_ui_high_quarter_taxable_wages", period) + meets_taxable_minimum = base_period_taxable_wages >= p.min_taxable_wages + meets_multiplier = base_period_total_wages >= ( + p.min_total_wages_multiplier * high_quarter_taxable_wages + ) + return meets_taxable_minimum & meets_multiplier diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py new file mode 100644 index 00000000000..7b0f3a9c59c --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ok_ui_monetarily_eligible(Variable): + value_type = bool + entity = Person + label = "Monetarily eligible for Oklahoma Unemployment Insurance" + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56" + ) + + def formula(person, period, parameters): + high_quarter = person("ok_ui_meets_high_quarter_test", period) + alternate = person("ok_ui_meets_alternate_wages_test", period) + return high_quarter | alternate diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py new file mode 100644 index 00000000000..a41299642eb --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ok_ui_weekly_benefit_rate(Variable): + value_type = float + entity = Person + label = "Oklahoma UI weekly benefit rate" + unit = USD + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49" + ) + + def formula(person, period, parameters): + # § 2-104(A): WBA = floor(high quarter taxable wages / divisor), + # clamped to the statutory minimum and the annual maximum set under + # § 2-104(B). § 2-102 specifies that fractional results are rounded + # down to the next lower whole dollar. + p = parameters(period).gov.states.ok.oesc.unemployment_insurance.wba + high_quarter_taxable_wages = person("ok_ui_high_quarter_taxable_wages", period) + raw_weekly_benefit_rate = np.floor(high_quarter_taxable_wages / p.divisor) + return min_(max_(raw_weekly_benefit_rate, p.min_amount), p.max_amount) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py new file mode 100644 index 00000000000..7efd266f3ce --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ok_ui_weekly_payable(Variable): + value_type = float + entity = Person + label = "Oklahoma UI weekly payable amount" + unit = USD + definition_period = YEAR + defined_for = "ok_ui_monetarily_eligible" + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50" + ) + + def formula(person, period, parameters): + # § 2-105: weekly payable amount = WBR minus the portion of weekly + # earnings that exceeds the statutory earnings disregard, floored at + # zero. + p = parameters(period).gov.states.ok.oesc.unemployment_insurance.partial + weekly_benefit_rate = person("ok_ui_weekly_benefit_rate", period) + gross_weekly_earnings = person("ok_ui_gross_weekly_earnings", period) + earnings_reduction = max_(gross_weekly_earnings - p.disregard, 0) + return max_(weekly_benefit_rate - earnings_reduction, 0) From f222ac6141fe5e4440af256ca1fc16b7fc4ac892 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Tue, 12 May 2026 13:39:44 -0400 Subject: [PATCH 02/10] Review-fix round 1: address critical issues from /review-program MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace broken 2025 OESC PDF URL with working OMES PDF + OESC homepage - Fix section citation: §1-218 → §1-201(48) + §1-223 in taxable_wage_base - Add subsection specificity: §2-207(A) → §2-207(A)(1)/(A)(2) - Correct PDF page anchors: divisor/min_amount/max_amount #page=49→50; disregard #page=50→51 - Update stale $27,400 test comments to match actual $27,000 param - Replace 0000-01-01 sentinel with 1980-07-01 in mba/max_weeks - Add trailing comma to make single-element reference tuples valid Co-Authored-By: Claude Opus 4.7 (1M context) --- .../eligibility/min_taxable_wages.yaml | 2 +- .../eligibility/min_total_wages_multiplier.yaml | 2 +- .../ok/oesc/unemployment_insurance/mba/max_weeks.yaml | 2 +- .../ok/oesc/unemployment_insurance/partial/disregard.yaml | 2 +- .../ok/oesc/unemployment_insurance/wba/divisor.yaml | 2 +- .../ok/oesc/unemployment_insurance/wba/max_amount.yaml | 6 +++--- .../ok/oesc/unemployment_insurance/wba/min_amount.yaml | 2 +- .../ok/tax/payroll/unemployment/taxable_wage_base.yaml | 8 ++++---- .../states/ok/oesc/unemployment_insurance/edge_cases.yaml | 6 +++--- .../ok/oesc/unemployment_insurance/integration.yaml | 2 +- .../unemployment_insurance/ok_ui_monetarily_eligible.yaml | 2 +- .../unemployment_insurance/ok_ui_gross_weekly_earnings.py | 2 +- .../ok_ui_meets_alternate_wages_test.py | 2 +- .../ok_ui_meets_high_quarter_test.py | 2 +- .../unemployment_insurance/ok_ui_monetarily_eligible.py | 2 +- .../unemployment_insurance/ok_ui_weekly_benefit_rate.py | 2 +- .../oesc/unemployment_insurance/ok_ui_weekly_payable.py | 2 +- 17 files changed, 24 insertions(+), 24 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml index 9d5366c0245..655a9f9d1d0 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml @@ -8,5 +8,5 @@ metadata: period: year label: Oklahoma UI minimum taxable base period wages reference: - - title: 40 O.S. §2-207(A) + - title: 40 O.S. §2-207(A)(1) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml index 81bcccc57d1..2a796aad83a 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml @@ -8,5 +8,5 @@ metadata: period: year label: Oklahoma UI minimum total wages multiplier reference: - - title: 40 O.S. §2-207(A) + - title: 40 O.S. §2-207(A)(2) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml index 8aeb073b58f..72952e0bb3d 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml @@ -1,7 +1,7 @@ description: Oklahoma limits unemployment compensation benefits to this number of weeks within a benefit year under the Unemployment Insurance program. values: - 0000-01-01: 26 + 1980-07-01: 26 2023-01-01: 16 metadata: diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml index 265820c4ca4..376f12c2813 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml @@ -9,4 +9,4 @@ metadata: label: Oklahoma UI partial benefit earnings disregard reference: - title: 40 O.S. §2-105 - href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml index dc18c9b6c3d..121e9932471 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml @@ -9,4 +9,4 @@ metadata: label: Oklahoma UI weekly benefit divisor reference: - title: 40 O.S. §2-104(A) - href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml index 3198b60eca6..d0983f2107a 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml @@ -11,10 +11,10 @@ metadata: label: Oklahoma UI maximum weekly benefit amount reference: - title: 40 O.S. §2-104(B) - href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 - title: OESC Claimant Handbook OES-339 (Rev. 05-2025), page 4 href: https://oklahoma.gov/content/dam/ok/en/oesc/documents/forms/OES-339.pdf#page=4 - - title: OESC Important Numbers for 2025 - href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2025.pdf#page=1 + - title: Oklahoma Employment Security Commission (2025 maximum WBA $541 set by OESC Board determination per §2-104(B); no current OESC PDF lists the value — see OES-339 for 2024 history) + href: https://oklahoma.gov/oesc.html - title: OESC Important Numbers for 2026 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml index e552cf652d1..7ab58a396e7 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml @@ -9,4 +9,4 @@ metadata: label: Oklahoma UI minimum weekly benefit amount reference: - title: 40 O.S. §2-104(A) - href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 diff --git a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml index 2b897853cec..c3e53747689 100644 --- a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml +++ b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml @@ -10,14 +10,14 @@ metadata: unit: currency-USD label: Oklahoma unemployment taxable wage base reference: - - title: 40 O.S. §1-218 - href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=42 + - title: 40 O.S. §1-201(48) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=23 - title: 40 O.S. §1-223 href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44 - title: 40 O.S. §2-207(B) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 - - title: Oklahoma Employment Security Commission Important Numbers for 2025 - href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2025.pdf#page=1 + - title: Oklahoma OMES 2025 Rates and Maximums for FICA and Unemployment + href: https://oklahoma.gov/content/dam/ok/en/omes/documents/2025RatesMaximumsFICAUnemployment.pdf#page=1 - title: Oklahoma Employment Security Commission Important Numbers for 2026 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 - title: Tax Measures of State Unemployment Insurance Tax Systems, CY 2024 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml index 29df58d169a..448b726f318 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml @@ -26,7 +26,7 @@ # Test A multiplier prong: $1,500 >= 1.5 * $1,000 = $1,500 -> passes (>=). # Test A: both prongs pass. ok_ui_meets_high_quarter_test: true - # Test B: total $1,500 < $27,400 (2024 wage base) -> fails. + # Test B: total $1,500 < $27,000 (2024 wage base) -> fails. ok_ui_meets_alternate_wages_test: false ok_ui_monetarily_eligible: true @@ -48,7 +48,7 @@ person1: # Test A taxable prong: $1,499 < $1,500 -> fails. ok_ui_meets_high_quarter_test: false - # Test B: $1,499 > 0 but total $1,500 < $27,400 -> fails. + # Test B: $1,499 > 0 but total $1,500 < $27,000 -> fails. ok_ui_meets_alternate_wages_test: false ok_ui_monetarily_eligible: false @@ -91,7 +91,7 @@ person1: # Test A multiplier prong: $14,999 < 1.5 * $10,000 = $15,000 -> fails. ok_ui_meets_high_quarter_test: false - # Test B: total $14,999 < $27,400 -> fails. + # Test B: total $14,999 < $27,000 -> fails. ok_ui_meets_alternate_wages_test: false ok_ui_monetarily_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml index e134af4cce7..83750aa4486 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml @@ -55,7 +55,7 @@ person1: # Test A: taxable $500 < $1,500 -> fails. ok_ui_meets_high_quarter_test: false - # Test B: total $5,000 < $27,400 (2024 wage base) -> fails. + # Test B: total $5,000 < $27,000 (2024 wage base) -> fails. ok_ui_meets_alternate_wages_test: false ok_ui_monetarily_eligible: false # defined_for gate -> $0. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml index a51f5b8bd51..08c5f4c8c68 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml @@ -21,7 +21,7 @@ people: person1: # Test A: taxable $5,000 >= $1,500 AND $20,000 >= 1.5 * $10,000 = $15,000 -> passes. - # Test B: total $20,000 < $27,400 (2024 wage base) -> fails. + # Test B: total $20,000 < $27,000 (2024 wage base) -> fails. # Overall: A OR B = true. ok_ui_meets_high_quarter_test: true ok_ui_meets_alternate_wages_test: false diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py index e8169c18a94..748f9479071 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py @@ -16,5 +16,5 @@ class ok_ui_gross_weekly_earnings(Variable): default_value = 0 defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50" + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py index 73719d86412..c4e30b7ce6f 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py @@ -8,7 +8,7 @@ class ok_ui_meets_alternate_wages_test(Variable): definition_period = YEAR defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56" + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py index a4e832983ea..74104cad394 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py @@ -8,7 +8,7 @@ class ok_ui_meets_high_quarter_test(Variable): definition_period = YEAR defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56" + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py index 7b0f3a9c59c..0e931a3566f 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py @@ -8,7 +8,7 @@ class ok_ui_monetarily_eligible(Variable): definition_period = YEAR defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56" + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py index a41299642eb..5e209ca17da 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py @@ -9,7 +9,7 @@ class ok_ui_weekly_benefit_rate(Variable): definition_period = YEAR defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49" + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py index 7efd266f3ce..1763d12ef47 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py @@ -9,7 +9,7 @@ class ok_ui_weekly_payable(Variable): definition_period = YEAR defined_for = "ok_ui_monetarily_eligible" reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50" + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", ) def formula(person, period, parameters): From 30c3d1272ac9be4ac5b93591d893b58ed200c326 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Tue, 12 May 2026 13:48:41 -0400 Subject: [PATCH 03/10] Review-fix round 2: address critical issues from /review-program MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Change 0000-01-01 sentinel to 2024-01-01 in taxable_wage_base - Replace repealed §1-202 with current §1-201(4) in base-period docstrings - Add §2-207 reference to ok_ui_base_period_total_wages (where "total wages" qualifier comes from) - Update §2-104(B) title in max_amount to clarify OESC Board determination Co-Authored-By: Claude Opus 4.7 (1M context) --- .../oesc/unemployment_insurance/wba/max_amount.yaml | 4 ++-- .../tax/payroll/unemployment/taxable_wage_base.yaml | 2 +- .../ok_ui_base_period_taxable_wages.py | 4 ++-- .../ok_ui_base_period_total_wages.py | 12 +++++++----- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml index d0983f2107a..7edf1764d20 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml @@ -10,11 +10,11 @@ metadata: period: week label: Oklahoma UI maximum weekly benefit amount reference: - - title: 40 O.S. §2-104(B) + - title: 40 O.S. §2-104(B) (OESC Board determines maximum weekly benefit annually) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 - title: OESC Claimant Handbook OES-339 (Rev. 05-2025), page 4 href: https://oklahoma.gov/content/dam/ok/en/oesc/documents/forms/OES-339.pdf#page=4 - - title: Oklahoma Employment Security Commission (2025 maximum WBA $541 set by OESC Board determination per §2-104(B); no current OESC PDF lists the value — see OES-339 for 2024 history) + - title: Oklahoma Employment Security Commission href: https://oklahoma.gov/oesc.html - title: OESC Important Numbers for 2026 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml index c3e53747689..42e3375bd73 100644 --- a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml +++ b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml @@ -1,7 +1,7 @@ description: Oklahoma sets the annual unemployment insurance taxable wage base at this amount under the Unemployment Insurance program. values: - 0000-01-01: 27_000 + 2024-01-01: 27_000 2025-01-01: 28_200 2026-01-01: 25_000 diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py index e905611f4ec..3529d41dc1c 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py @@ -4,7 +4,7 @@ class ok_ui_base_period_taxable_wages(Variable): """Sum of taxable wages (capped at the Oklahoma taxable wage base per quarter) across all four quarters of the base period, per 40 O.S. § 1-223 - and § 1-202. Used in the monetary-eligibility tests in § 2-207(A) and + and § 1-201(4). Used in the monetary-eligibility tests in § 2-207(A) and § 2-207(B). PolicyEngine cannot derive quarterly wages from annual data, so this is a direct input rather than a computed value; populate via test fixtures or reform. @@ -18,6 +18,6 @@ class ok_ui_base_period_taxable_wages(Variable): default_value = 0 defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=24", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=20", "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py index eafcf7b91c4..76554a296bd 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py @@ -3,10 +3,11 @@ class ok_ui_base_period_total_wages(Variable): """Sum of total (uncapped) gross wages across all four quarters of the - base period, per 40 O.S. § 1-218 and § 1-202. Used in the monetary- - eligibility tests in § 2-207(A) and § 2-207(B). PolicyEngine cannot derive - quarterly wages from annual data, so this is a direct input rather than a - computed value; populate via test fixtures or reform. + base period, per 40 O.S. § 1-218 (wages definition), § 1-201(4) (base + period definition), and § 2-207 (where "total wages" is used). Used in + the monetary-eligibility tests in § 2-207(A) and § 2-207(B). PolicyEngine + cannot derive quarterly wages from annual data, so this is a direct input + rather than a computed value; populate via test fixtures or reform. """ value_type = float @@ -17,6 +18,7 @@ class ok_ui_base_period_total_wages(Variable): default_value = 0 defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=24", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=20", "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=42", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", ) From 80e950f3cc56afd0d07663a913b7f473f7be0ec6 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Tue, 12 May 2026 14:04:04 -0400 Subject: [PATCH 04/10] Add lessons from Oklahoma UI implementation Co-Authored-By: Claude Opus 4.7 (1M context) --- lessons/agent-lessons.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 lessons/agent-lessons.md diff --git a/lessons/agent-lessons.md b/lessons/agent-lessons.md new file mode 100644 index 00000000000..aedba4661a2 --- /dev/null +++ b/lessons/agent-lessons.md @@ -0,0 +1,23 @@ +# Agent Lessons Learned + +Accumulated from /encode-policy-v2 and /backdate-program runs across all contributors. +Loaded by implementation agents on future runs. + +## New Lessons from Oklahoma UI (2026-05-12) + +### PARAMETER +- Verify every parameter value against authoritative source PDFs before committing; do not let inferred or rounded values reach the YAML files. +- Keep parameter values and any test/comment references to those values in sync — when a value changes, grep for the old number across params, tests, and docstrings in one sweep. +- Reserve sentinel `0000-01-01` effective dates for parameters that genuinely have no historical variation; whenever the value reflects a real first-year-applicable date, use the actual effective date so future audits can trace it. +- When citing a statute that delegates the actual value to an agency (e.g. board-determined annual rates), put the delegating statute in the reference title rather than relying on a homepage URL that does not display the value. + +### REFERENCE +- A single-URL `reference` written as `(string)` is a parenthesized string, not a tuple — write `(string,)` with a trailing comma (or drop parens entirely) to match the multi-reference convention. +- PDF `#page=` anchors should target the file page that contains the cited value or operative text, not the table-of-contents or heading-only page; off-by-one is the common failure mode. +- Statutory citations should be as specific as the value warrants — cite `§X-XXX(A)(1)` when the floor lives in that subsection rather than the broader `§X-XXX(A)`. +- When a cited code section has been repealed, replace the citation with the active replacement section (e.g. updated definitions section) and update the page anchor accordingly; do not leave repealed-section URLs in active references. +- Verify every reference URL actually resolves (no 404s) before merge; keep an alternate authoritative source (e.g. companion agency PDF, statutory text) ready when one URL breaks. + +### WORKFLOW +- When parallel agents produce paired artifacts (variables + tests, params + variables), give each agent the same canonical variable-name and parameter-name list so the files line up — do not let one agent follow the spec and another follow the prompt independently. +- Before approving a new program, audit every parameter value against a manifest of source PDFs; do not rely solely on the implementer's claim that values match. From f39a91fcab339003ca23bed46777002701e38667 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Tue, 12 May 2026 14:27:54 -0400 Subject: [PATCH 05/10] Fix Oklahoma UI maximum benefit cap --- lessons/agent-lessons.md | 23 ---------------- .../mba/base_period_wages_share.yaml | 22 +++++++++++++++ .../mba/max_amount.yaml | 26 ++++++++++++++++++ .../wba/max_amount.yaml | 10 +++++++ .../unemployment/taxable_wage_base.yaml | 8 ++++++ .../unemployment_insurance/edge_cases.yaml | 27 ++++++++++++++++++- .../ok_ui_maximum_benefit_amount.yaml | 25 ++++++++++++++++- .../ok_ui_weekly_benefit_rate.yaml | 21 ++++++++++++++- .../ok_ui_maximum_benefit_amount.py | 14 +++++----- 9 files changed, 144 insertions(+), 32 deletions(-) delete mode 100644 lessons/agent-lessons.md create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml create mode 100644 policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml diff --git a/lessons/agent-lessons.md b/lessons/agent-lessons.md deleted file mode 100644 index aedba4661a2..00000000000 --- a/lessons/agent-lessons.md +++ /dev/null @@ -1,23 +0,0 @@ -# Agent Lessons Learned - -Accumulated from /encode-policy-v2 and /backdate-program runs across all contributors. -Loaded by implementation agents on future runs. - -## New Lessons from Oklahoma UI (2026-05-12) - -### PARAMETER -- Verify every parameter value against authoritative source PDFs before committing; do not let inferred or rounded values reach the YAML files. -- Keep parameter values and any test/comment references to those values in sync — when a value changes, grep for the old number across params, tests, and docstrings in one sweep. -- Reserve sentinel `0000-01-01` effective dates for parameters that genuinely have no historical variation; whenever the value reflects a real first-year-applicable date, use the actual effective date so future audits can trace it. -- When citing a statute that delegates the actual value to an agency (e.g. board-determined annual rates), put the delegating statute in the reference title rather than relying on a homepage URL that does not display the value. - -### REFERENCE -- A single-URL `reference` written as `(string)` is a parenthesized string, not a tuple — write `(string,)` with a trailing comma (or drop parens entirely) to match the multi-reference convention. -- PDF `#page=` anchors should target the file page that contains the cited value or operative text, not the table-of-contents or heading-only page; off-by-one is the common failure mode. -- Statutory citations should be as specific as the value warrants — cite `§X-XXX(A)(1)` when the floor lives in that subsection rather than the broader `§X-XXX(A)`. -- When a cited code section has been repealed, replace the citation with the active replacement section (e.g. updated definitions section) and update the page anchor accordingly; do not leave repealed-section URLs in active references. -- Verify every reference URL actually resolves (no 404s) before merge; keep an alternate authoritative source (e.g. companion agency PDF, statutory text) ready when one URL breaks. - -### WORKFLOW -- When parallel agents produce paired artifacts (variables + tests, params + variables), give each agent the same canonical variable-name and parameter-name list so the files line up — do not let one agent follow the spec and another follow the prompt independently. -- Before approving a new program, audit every parameter value against a manifest of source PDFs; do not rely solely on the implementer's claim that values match. diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml new file mode 100644 index 00000000000..bb7dc88a817 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml @@ -0,0 +1,22 @@ +description: Oklahoma limits unemployment compensation benefits to this share of base period wages under the Unemployment Insurance program. + +values: + 1980-07-01: 1 + 2023-01-01: 0.4 + 2026-01-01: 0.475 + +metadata: + unit: /1 + period: year + label: Oklahoma UI maximum benefit base period wages share + reference: + - title: 40 O.S. §2-106(3) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + - title: OESC Important Numbers for 2023 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 + - title: OESC Important Numbers for 2024 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 + - title: OESC Important Numbers for 2025 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2025.pdf#page=1 + - title: OESC Important Numbers for 2026 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml new file mode 100644 index 00000000000..1d520e18df8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml @@ -0,0 +1,26 @@ +description: Oklahoma limits unemployment compensation benefits to this amount within a benefit year under the Unemployment Insurance program. + +values: + 2022-01-01: 9_900 + 2023-01-01: 7_888 + 2024-01-01: 8_304 + 2025-01-01: 8_656 + 2026-01-01: 10_384 + +metadata: + unit: currency-USD + period: year + label: Oklahoma UI maximum benefit amount + reference: + - title: 40 O.S. §2-106 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021, page 2 + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 + - title: OESC Important Numbers for 2023 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 + - title: OESC Important Numbers for 2024 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 + - title: OESC Important Numbers for 2025 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2025.pdf#page=1 + - title: OESC Important Numbers for 2026 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml index 7edf1764d20..d52e11fe3d6 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml @@ -1,6 +1,8 @@ description: Oklahoma sets the maximum weekly benefit amount at this amount under the Unemployment Insurance program. values: + 2022-01-01: 476 + 2023-01-01: 493 2024-01-01: 519 2025-01-01: 541 2026-01-01: 649 @@ -12,6 +14,14 @@ metadata: reference: - title: 40 O.S. §2-104(B) (OESC Board determines maximum weekly benefit annually) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 + - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021, page 2 + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 + - title: OESC Important Numbers for 2023 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 + - title: OESC Important Numbers for 2024 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 + - title: OESC Important Numbers for 2025 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2025.pdf#page=1 - title: OESC Claimant Handbook OES-339 (Rev. 05-2025), page 4 href: https://oklahoma.gov/content/dam/ok/en/oesc/documents/forms/OES-339.pdf#page=4 - title: Oklahoma Employment Security Commission diff --git a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml index 42e3375bd73..8aacbe0b4ae 100644 --- a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml +++ b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml @@ -1,6 +1,8 @@ description: Oklahoma sets the annual unemployment insurance taxable wage base at this amount under the Unemployment Insurance program. values: + 2022-01-01: 24_800 + 2023-01-01: 25_700 2024-01-01: 27_000 2025-01-01: 28_200 2026-01-01: 25_000 @@ -16,6 +18,12 @@ metadata: href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44 - title: 40 O.S. §2-207(B) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 + - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021, page 2 + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 + - title: OESC Important Numbers for 2023 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 + - title: OESC Important Numbers for 2024 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 - title: Oklahoma OMES 2025 Rates and Maximums for FICA and Unemployment href: https://oklahoma.gov/content/dam/ok/en/omes/documents/2025RatesMaximumsFICAUnemployment.pdf#page=1 - title: Oklahoma Employment Security Commission Important Numbers for 2026 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml index 448b726f318..6ec94da98c9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml @@ -1,7 +1,7 @@ # Edge case tests for Oklahoma Unemployment Insurance (OK UI). # Boundary conditions for the monetary eligibility tests (§ 2-207), # the WBA clamp (§ 2-104), the partial-benefit subtraction (§ 2-105), -# the MBA / max_weeks transition (§ 2-106, HB 1933), and the +# the MBA lesser-of caps / max_weeks transition (§ 2-106, HB 1933), and the # defined_for state gate. # --- Test A boundary (§ 2-207(A)): taxable >= $1,500 AND total >= 1.5 * HQW --- @@ -503,3 +503,28 @@ ok_ui_weekly_benefit_rate: 500 # MBA = $500 * 16 = $8,000; annual = min($500 * 16, $8,000) = $8,000. ok_ui: 8_000 + +- name: Case 23, base-period wages share caps annual benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 15_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 434 + # Lesser of $434 * 16 = $6,944, statewide $8,656, and 40% * $15,000 = $6,000. + ok_ui_maximum_benefit_amount: 6_000 + ok_ui: 6_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml index 2a0ea54c2c9..ad503f630d9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml @@ -1,5 +1,5 @@ # Tests for Oklahoma UI maximum benefit amount (40 O.S. §2-106). -# MBA = WBA * max_weeks. +# MBA = min(WBA * max_weeks, statewide max benefit amount, base-period wages share cap). # max_weeks: 26 before 2023-01-01, 16 from 2023-01-01. # Reference: 40 O.S. §2-106; HB 1933 (2022). @@ -12,6 +12,7 @@ age: 35 # HQW $9,200 -> floor($9,200 / 23) = $400 (within 2024 [$16, $519] range). ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 households: household: members: [person1] @@ -32,6 +33,7 @@ age: 35 # HQW $6,900 -> floor($6,900 / 23) = $300. ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 households: household: members: [person1] @@ -42,3 +44,24 @@ ok_ui_weekly_benefit_rate: 300 # Pre-2023 max_weeks = 26; MBA = $300 * 26 = $7,800. ok_ui_maximum_benefit_amount: 7_800 + +- name: Case 3, 2025 - base-period wages share caps marginal Test A claimant. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $10,000 -> floor($10,000 / 23) = $434. + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 434 + # Lesser of $434 * 16 = $6,944, statewide $8,656, and 40% * $15,000 = $6,000. + ok_ui_maximum_benefit_amount: 6_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml index 969d061f63f..abb3d5247eb 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml @@ -1,6 +1,6 @@ # Tests for Oklahoma UI weekly benefit amount (40 O.S. §2-104(A), §2-102). # Formula: WBA = clamp(floor(HQW_taxable / 23), [min=$16, max=annual_cap]). -# Annual max WBA: 2024=$519, 2025=$541, 2026=$649. +# Annual max WBA: 2022=$476, 2023=$493, 2024=$519, 2025=$541, 2026=$649. # Min WBA $16 has been the statutory floor since 1980. # Reference: 40 O.S. §2-104(A), §2-102; OESC Important Numbers. @@ -99,3 +99,22 @@ # floor($20,000 / 23) = floor($869.57) = $869. # $869 > $649 (2026 max) -> clamped to $649. ok_ui_weekly_benefit_rate: 649 + +- name: Case 6, high HQW clamped to 2022 maximum. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ok_ui_high_quarter_taxable_wages: 20_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($20,000 / 23) = floor($869.57) = $869. + # $869 > $476 (2022 max) -> clamped to $476. + ok_ui_weekly_benefit_rate: 476 diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py index c3952b11041..e9e238918ca 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py @@ -14,11 +14,13 @@ class ok_ui_maximum_benefit_amount(Variable): ) def formula(person, period, parameters): - # § 2-106 caps benefits in a benefit year. Only the weeks-times-WBR - # prong of the three-prong lesser-of test is modeled; the annual-wage - # and wage-share caps in § 2-106 are not modeled because they depend - # on the state-fund conditional factor that we do not track at - # runtime. + # § 2-106 caps benefits in a benefit year at the lesser of the + # duration cap, the statewide maximum benefit amount, and the + # applicable share of base-period wages. p = parameters(period).gov.states.ok.oesc.unemployment_insurance.mba weekly_benefit_rate = person("ok_ui_weekly_benefit_rate", period) - return weekly_benefit_rate * p.max_weeks + base_period_total_wages = person("ok_ui_base_period_total_wages", period) + return min_( + min_(weekly_benefit_rate * p.max_weeks, p.max_amount), + base_period_total_wages * p.base_period_wages_share, + ) From 9a16eeca146758cacd344672d75f04978b261cd1 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 14 May 2026 10:53:16 -0400 Subject: [PATCH 06/10] Register Oklahoma UI program --- policyengine_us/programs.yaml | 11 +++++++++++ .../ok/oesc/unemployment_insurance/integration.yaml | 1 + .../variables/gov/states/unemployment_compensation.py | 1 + 3 files changed, 13 insertions(+) diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 88e0008d86b..3809b87d37f 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1344,6 +1344,17 @@ programs: variable: ny_drive_clean_rebate parameter_prefix: gov.states.ny.nyserda.drive_clean + - id: ok_ui + name: Oklahoma UI + full_name: Oklahoma Unemployment Insurance + category: Benefits + agency: Oklahoma Employment Security Commission + status: complete + coverage: OK + variable: ok_ui + parameter_prefix: gov.states.ok.oesc.unemployment_insurance + verified_years: "2022-2026" + - id: tx_fpp_benefit name: Texas FPP full_name: Texas Family Planning Program diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml index 83750aa4486..589cf24b50c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml @@ -33,6 +33,7 @@ ok_ui_maximum_benefit_amount: 8_000 # Annual: min($500 * 16, $8,000) = $8,000. ok_ui: 8_000 + unemployment_compensation: 8_000 - name: Case 2, ineligible claimant - wages too low in 2024. period: 2024 diff --git a/policyengine_us/variables/gov/states/unemployment_compensation.py b/policyengine_us/variables/gov/states/unemployment_compensation.py index 0857864ab17..2bdaeeac571 100644 --- a/policyengine_us/variables/gov/states/unemployment_compensation.py +++ b/policyengine_us/variables/gov/states/unemployment_compensation.py @@ -9,3 +9,4 @@ class unemployment_compensation(Variable): documentation = "Income from unemployment compensation programs." definition_period = YEAR uprating = "calibration.gov.irs.soi.unemployment_compensation" + adds = ["ok_ui"] From 8eb5c7b3b44d21d6b30426f628ce8f429ae9082a Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:29:01 -0400 Subject: [PATCH 07/10] Defer ok_ui income-flow integration to umbrella PR Remove the adds wiring into unemployment_compensation (newer core rejects adds combined with uprating, and the integration is deferred to #8303 pending policyengine-us-data support) and the coupled integration assertion. Co-Authored-By: Claude Fable 5 --- .../gov/states/ok/oesc/unemployment_insurance/integration.yaml | 1 - .../variables/gov/states/unemployment_compensation.py | 1 - 2 files changed, 2 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml index 589cf24b50c..83750aa4486 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml @@ -33,7 +33,6 @@ ok_ui_maximum_benefit_amount: 8_000 # Annual: min($500 * 16, $8,000) = $8,000. ok_ui: 8_000 - unemployment_compensation: 8_000 - name: Case 2, ineligible claimant - wages too low in 2024. period: 2024 diff --git a/policyengine_us/variables/gov/states/unemployment_compensation.py b/policyengine_us/variables/gov/states/unemployment_compensation.py index 2bdaeeac571..0857864ab17 100644 --- a/policyengine_us/variables/gov/states/unemployment_compensation.py +++ b/policyengine_us/variables/gov/states/unemployment_compensation.py @@ -9,4 +9,3 @@ class unemployment_compensation(Variable): documentation = "Income from unemployment compensation programs." definition_period = YEAR uprating = "calibration.gov.irs.soi.unemployment_compensation" - adds = ["ok_ui"] From 68139b5d12c768439ea122069e68e01dd70d744e Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Tue, 4 Aug 2026 12:03:22 -0400 Subject: [PATCH 08/10] Address program review: 2022 MBA share, wage-base anchor, citations, tests - Set 2022 base-period wages share to 0.4 (conditional factor D per 40 O.S. 2-106(3) and the OESC table); pre-2023 uncapped value was incorrect and overstated 2022 MBAs - Restore the pre-existing 0000-01-01: 27,000 taxable wage base anchor the PR had dropped, keeping pre-2022 OK payroll tax identical to main - Reconcile every os40.pdf page anchor to verified file pages; add stable OSCN per-section HTML references and HB 3596 citation for the 16-week duration; strip page numbers from reference titles - Document the taxable-wage proxy in the 1.5x eligibility test, the 16x-max-WBA proxy for the 2-106(2) cap, the calendar-year wage-base cap, the unmodeled duration escalator, and microsim-inert inputs - Guard maximum benefit amount against negative wages with max_(.., 0) - Dissolve the aggregate edge_cases.yaml into per-variable test files and add boundary tests (2026 wage-base step, WBA clamps, binding MBA caps by year, 16-week seam, negative wages) Co-Authored-By: Claude Fable 5 --- .../eligibility/min_taxable_wages.yaml | 2 + .../min_total_wages_multiplier.yaml | 4 +- .../mba/base_period_wages_share.yaml | 8 +- .../mba/max_amount.yaml | 12 +- .../unemployment_insurance/mba/max_weeks.yaml | 14 +- .../partial/disregard.yaml | 2 + .../unemployment_insurance/wba/divisor.yaml | 2 + .../wba/max_amount.yaml | 6 +- .../wba/min_amount.yaml | 2 + .../unemployment/taxable_wage_base.yaml | 9 +- .../unemployment_insurance/edge_cases.yaml | 530 ------------------ .../ok/oesc/unemployment_insurance/ok_ui.yaml | 186 ++++++ .../ok_ui_maximum_benefit_amount.yaml | 171 ++++++ .../ok_ui_meets_alternate_wages_test.yaml | 41 ++ .../ok_ui_monetarily_eligible.yaml | 137 +++++ .../ok_ui_weekly_benefit_rate.yaml | 164 ++++++ .../ok_ui_weekly_payable.yaml | 91 +++ .../ok/oesc/unemployment_insurance/ok_ui.py | 28 +- .../ok_ui_base_period_taxable_wages.py | 16 +- .../ok_ui_base_period_total_wages.py | 3 +- .../ok_ui_gross_weekly_earnings.py | 9 +- .../ok_ui_high_quarter_taxable_wages.py | 9 +- .../ok_ui_maximum_benefit_amount.py | 6 +- .../ok_ui_meets_high_quarter_test.py | 11 + .../ok_ui_weekly_benefit_rate.py | 2 +- .../ok_ui_weekly_payable.py | 2 +- 26 files changed, 903 insertions(+), 564 deletions(-) delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml index 655a9f9d1d0..b1dadd9bd04 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml @@ -10,3 +10,5 @@ metadata: reference: - title: 40 O.S. §2-207(A)(1) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 + - title: 40 O.S. §2-207 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77177 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml index 2a796aad83a..9f38530fbd2 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml @@ -1,4 +1,4 @@ -description: Oklahoma uses this share of high quarter wages as the minimum total base period wages for monetary eligibility under the Unemployment Insurance program. +description: Oklahoma uses this multiple of high quarter wages as the minimum total base period wages for monetary eligibility under the Unemployment Insurance program. values: 1980-07-01: 1.5 @@ -10,3 +10,5 @@ metadata: reference: - title: 40 O.S. §2-207(A)(2) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 + - title: 40 O.S. §2-207 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77177 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml index bb7dc88a817..2401d83d295 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml @@ -1,8 +1,10 @@ description: Oklahoma limits unemployment compensation benefits to this share of base period wages under the Unemployment Insurance program. values: - 1980-07-01: 1 - 2023-01-01: 0.4 + # 40 O.S. §2-106(3) base-period-wages percentages: (a) 50%, (b) 47.5%, + # (c) 45%, (d) 42.5%, (e) 40%, keyed to the conditional factor in place. + # 2022-2025 reflect condition "d" (40%); 2026 reflects condition "a" (47.5%). + 2022-01-01: 0.4 2026-01-01: 0.475 metadata: @@ -12,6 +14,8 @@ metadata: reference: - title: 40 O.S. §2-106(3) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + - title: 40 O.S. §2-106 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 - title: OESC Important Numbers for 2023 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 - title: OESC Important Numbers for 2024 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml index 1d520e18df8..35f6f268527 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml @@ -1,6 +1,12 @@ description: Oklahoma limits unemployment compensation benefits to this amount within a benefit year under the Unemployment Insurance program. values: + # 40 O.S. §2-106(2) defines the statutory cap as a conditional-factor + # percentage of the state's average annual wage. From 2023 onward the + # OESC-published values below are the 16 x maximum-WBA proxies OESC + # publishes rather than the statutory %-of-average-annual-wage figure; this + # parameter never binds after 2023 because the 16-week duration cap on WBA + # is the lesser amount. 2022-01-01: 9_900 2023-01-01: 7_888 2024-01-01: 8_304 @@ -12,9 +18,11 @@ metadata: period: year label: Oklahoma UI maximum benefit amount reference: - - title: 40 O.S. §2-106 + - title: 40 O.S. §2-106(2) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 - - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021, page 2 + - title: 40 O.S. §2-106 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 + - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021 href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 - title: OESC Important Numbers for 2023 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml index 72952e0bb3d..e36e99d296e 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml @@ -1,6 +1,12 @@ description: Oklahoma limits unemployment compensation benefits to this number of weeks within a benefit year under the Unemployment Insurance program. values: + # 40 O.S. §2-106(1) sets the times-WBA multiplier for the benefit-year cap. + # §1-231 sets the duration floor at 16 weeks from Jan. 1, 2025 (Laws 2024, + # c. 114 / HB 3596), escalating +2 weeks per 15,000-claim increment up to + # 20 weeks, and up to 26 weeks if continued claims exceed 40,000. The + # 16-to-26-week claim-volume escalator above the 16-week floor is not + # modeled, so 16 weeks remains operative for 2025 and 2026. 1980-07-01: 26 2023-01-01: 16 @@ -11,7 +17,13 @@ metadata: reference: - title: 40 O.S. §1-231 href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=48 - - title: 40 O.S. §2-106 + - title: 40 O.S. §1-231 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=492632 + - title: 40 O.S. §2-106(1) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + - title: 40 O.S. §2-106 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 - title: Oklahoma House Bill 1933 (2022) href: https://www.oklegislature.gov/cf_pdf/2021-22%20ENR/hB/HB1933%20ENR.PDF + - title: Oklahoma House Bill 3596 (Laws 2024, c. 114), eff. 2024-11-01 + href: https://www.oklegislature.gov/cf_pdf/2023-24%20ENR/hB/HB3596%20ENR.PDF diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml index 376f12c2813..e62162ce4f4 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml @@ -10,3 +10,5 @@ metadata: reference: - title: 40 O.S. §2-105 href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + - title: 40 O.S. §2-105 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77165 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml index 121e9932471..bb72053e0eb 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml @@ -10,3 +10,5 @@ metadata: reference: - title: 40 O.S. §2-104(A) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 + - title: 40 O.S. §2-104 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77164 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml index d52e11fe3d6..aca1f1a08ba 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml @@ -14,7 +14,9 @@ metadata: reference: - title: 40 O.S. §2-104(B) (OESC Board determines maximum weekly benefit annually) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 - - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021, page 2 + - title: 40 O.S. §2-104 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77164 + - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021 href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 - title: OESC Important Numbers for 2023 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 @@ -22,7 +24,7 @@ metadata: href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 - title: OESC Important Numbers for 2025 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2025.pdf#page=1 - - title: OESC Claimant Handbook OES-339 (Rev. 05-2025), page 4 + - title: OESC Claimant Handbook OES-339 (Rev. 05-2025) href: https://oklahoma.gov/content/dam/ok/en/oesc/documents/forms/OES-339.pdf#page=4 - title: Oklahoma Employment Security Commission href: https://oklahoma.gov/oesc.html diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml index 7ab58a396e7..ba5fe00aab0 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml @@ -10,3 +10,5 @@ metadata: reference: - title: 40 O.S. §2-104(A) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 + - title: 40 O.S. §2-104 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77164 diff --git a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml index 8aacbe0b4ae..d3a047ff773 100644 --- a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml +++ b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml @@ -1,6 +1,7 @@ description: Oklahoma sets the annual unemployment insurance taxable wage base at this amount under the Unemployment Insurance program. values: + 0000-01-01: 27_000 2022-01-01: 24_800 2023-01-01: 25_700 2024-01-01: 27_000 @@ -14,11 +15,17 @@ metadata: reference: - title: 40 O.S. §1-201(48) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=23 + - title: 40 O.S. §1-201 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77132 - title: 40 O.S. §1-223 href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44 + - title: 40 O.S. §1-223 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77157 - title: 40 O.S. §2-207(B) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 - - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021, page 2 + - title: 40 O.S. §2-207 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77177 + - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021 href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 - title: OESC Important Numbers for 2023 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml deleted file mode 100644 index 6ec94da98c9..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/edge_cases.yaml +++ /dev/null @@ -1,530 +0,0 @@ -# Edge case tests for Oklahoma Unemployment Insurance (OK UI). -# Boundary conditions for the monetary eligibility tests (§ 2-207), -# the WBA clamp (§ 2-104), the partial-benefit subtraction (§ 2-105), -# the MBA lesser-of caps / max_weeks transition (§ 2-106, HB 1933), and the -# defined_for state gate. - -# --- Test A boundary (§ 2-207(A)): taxable >= $1,500 AND total >= 1.5 * HQW --- - -- name: Case 1, Test A taxable wages exactly at $1,500 threshold. - period: 2024 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 1_000 - ok_ui_base_period_taxable_wages: 1_500 - ok_ui_base_period_total_wages: 1_500 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # Test A taxable prong: $1,500 >= $1,500 -> passes (>= operator). - # Test A multiplier prong: $1,500 >= 1.5 * $1,000 = $1,500 -> passes (>=). - # Test A: both prongs pass. - ok_ui_meets_high_quarter_test: true - # Test B: total $1,500 < $27,000 (2024 wage base) -> fails. - ok_ui_meets_alternate_wages_test: false - ok_ui_monetarily_eligible: true - -- name: Case 2, Test A taxable wages one dollar below threshold. - period: 2024 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 1_000 - ok_ui_base_period_taxable_wages: 1_499 - ok_ui_base_period_total_wages: 1_500 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # Test A taxable prong: $1,499 < $1,500 -> fails. - ok_ui_meets_high_quarter_test: false - # Test B: $1,499 > 0 but total $1,500 < $27,000 -> fails. - ok_ui_meets_alternate_wages_test: false - ok_ui_monetarily_eligible: false - -- name: Case 3, Test A total wages exactly at 1.5x HQW boundary. - period: 2024 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 10_000 - ok_ui_base_period_taxable_wages: 5_000 - ok_ui_base_period_total_wages: 15_000 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # Test A multiplier prong: $15,000 >= 1.5 * $10,000 = $15,000 -> passes (>= operator). - # Test A taxable prong: $5,000 >= $1,500 -> passes. - ok_ui_meets_high_quarter_test: true - ok_ui_monetarily_eligible: true - -- name: Case 4, Test A total wages one dollar below 1.5x HQW boundary. - period: 2024 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 10_000 - ok_ui_base_period_taxable_wages: 5_000 - ok_ui_base_period_total_wages: 14_999 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # Test A multiplier prong: $14,999 < 1.5 * $10,000 = $15,000 -> fails. - ok_ui_meets_high_quarter_test: false - # Test B: total $14,999 < $27,000 -> fails. - ok_ui_meets_alternate_wages_test: false - ok_ui_monetarily_eligible: false - -# --- Test B boundary (§ 2-207(B)): taxable > 0 AND total >= wage base --- - -- name: Case 5, Test B total wages exactly at 2025 taxable wage base. - period: 2025 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 20_000 - ok_ui_base_period_taxable_wages: 2_000 - ok_ui_base_period_total_wages: 28_200 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # Test A: $28,200 < 1.5 * $20,000 = $30,000 -> fails. - ok_ui_meets_high_quarter_test: false - # Test B: taxable $2,000 > $0 AND $28,200 >= $28,200 (2025 wage base) -> passes (>=). - ok_ui_meets_alternate_wages_test: true - ok_ui_monetarily_eligible: true - -- name: Case 6, Test B total wages one dollar below 2025 taxable wage base. - period: 2025 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 20_000 - ok_ui_base_period_taxable_wages: 2_000 - ok_ui_base_period_total_wages: 28_199 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # Test A: $28,199 < $30,000 -> fails. - ok_ui_meets_high_quarter_test: false - # Test B: $28,199 < $28,200 -> fails. - ok_ui_meets_alternate_wages_test: false - ok_ui_monetarily_eligible: false - -# --- WBA clamp boundaries (§ 2-104(A): floor(HQW / 23), clamped to [$16, max]) --- - -- name: Case 7, WBA below minimum - HQW $367 clamped up to $16 floor. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 367 - ok_ui_base_period_taxable_wages: 1_500 - ok_ui_base_period_total_wages: 2_250 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # floor($367 / 23) = floor($15.957) = $15 -> below $16 minimum -> clamped to $16. - ok_ui_weekly_benefit_rate: 16 - -- name: Case 8, WBA exactly at minimum - HQW $368 yields $16. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 368 - ok_ui_base_period_taxable_wages: 1_500 - ok_ui_base_period_total_wages: 2_250 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # floor($368 / 23) = floor($16.0) = $16 -> exactly at minimum. - ok_ui_weekly_benefit_rate: 16 - -- name: Case 9, WBA exactly at 2024 maximum - HQW $11,937 yields $519. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 11_937 - ok_ui_base_period_taxable_wages: 11_937 - ok_ui_base_period_total_wages: 30_000 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # 519 * 23 = $11,937 exactly; floor($11,937 / 23) = $519. - # 2024 max is $519 -> no clamp needed, exactly at boundary. - ok_ui_weekly_benefit_rate: 519 - -- name: Case 10, WBA still at 2024 max - HQW $11,938 yields $519. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 11_938 - ok_ui_base_period_taxable_wages: 11_938 - ok_ui_base_period_total_wages: 30_000 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # floor($11,938 / 23) = floor($519.043) = $519 -> at 2024 max, no clamp. - ok_ui_weekly_benefit_rate: 519 - -- name: Case 11, WBA clamped down at 2024 max - HQW $11,960 yields $520 raw, clamped to $519. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 11_960 - ok_ui_base_period_taxable_wages: 11_960 - ok_ui_base_period_total_wages: 30_000 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # 520 * 23 = $11,960 exactly; floor($11,960 / 23) = $520. - # $520 > $519 (2024 max) -> clamped down to $519. - ok_ui_weekly_benefit_rate: 519 - -- name: Case 12, very high HQW clamped to 2025 max $541. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 100_000 - ok_ui_base_period_taxable_wages: 100_000 - ok_ui_base_period_total_wages: 300_000 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # floor($100,000 / 23) = floor($4,347.83) = $4,347 -> far above $541 (2025 max) -> clamped to $541. - ok_ui_weekly_benefit_rate: 541 - -# --- Zero income / zero weeks --- - -- name: Case 13, all wages zero - both tests fail, no benefit. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 0 - ok_ui_base_period_taxable_wages: 0 - ok_ui_base_period_total_wages: 0 - ok_ui_gross_weekly_earnings: 0 - weeks_unemployed: 16 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - # Test A: $0 < $1,500 -> fails. Test B: $0 not > 0 -> fails. - ok_ui_monetarily_eligible: false - # defined_for gate -> $0. - ok_ui: 0 - -- name: Case 14, eligible but zero weeks unemployed - annual benefit zero. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 9_200 - ok_ui_base_period_taxable_wages: 9_200 - ok_ui_base_period_total_wages: 30_000 - ok_ui_gross_weekly_earnings: 0 - weeks_unemployed: 0 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_monetarily_eligible: true - # WBA: floor($9,200 / 23) = $400. - ok_ui_weekly_benefit_rate: 400 - # MBA = $400 * 16 = $6,400 (defined regardless of weeks worked). - ok_ui_maximum_benefit_amount: 6_400 - # Annual: min($400 * 0, $6,400) = $0. - ok_ui: 0 - -# --- Partial benefit edge cases (§ 2-105) --- - -- name: Case 15, weekly earnings exactly at $100 disregard - full WBA paid. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 9_200 - ok_ui_base_period_taxable_wages: 9_200 - ok_ui_base_period_total_wages: 30_000 - ok_ui_gross_weekly_earnings: 100 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_weekly_benefit_rate: 400 - # earnings_reduction = max(0, $100 - $100) = $0; payable = max(0, $400 - 0) = $400. - ok_ui_weekly_payable: 400 - -- name: Case 16, weekly earnings one dollar above disregard - WBA reduced by $1. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 9_200 - ok_ui_base_period_taxable_wages: 9_200 - ok_ui_base_period_total_wages: 30_000 - ok_ui_gross_weekly_earnings: 101 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_weekly_benefit_rate: 400 - # earnings_reduction = max(0, $101 - $100) = $1; payable = max(0, $400 - $1) = $399. - ok_ui_weekly_payable: 399 - -- name: Case 17, weekly earnings exactly at WBA + disregard - payable zero. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 9_200 - ok_ui_base_period_taxable_wages: 9_200 - ok_ui_base_period_total_wages: 30_000 - ok_ui_gross_weekly_earnings: 500 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_weekly_benefit_rate: 400 - # earnings_reduction = max(0, $500 - $100) = $400; payable = max(0, $400 - $400) = $0. - ok_ui_weekly_payable: 0 - -- name: Case 18, weekly earnings above WBA + disregard - payable floored at zero. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 9_200 - ok_ui_base_period_taxable_wages: 9_200 - ok_ui_base_period_total_wages: 30_000 - ok_ui_gross_weekly_earnings: 501 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_weekly_benefit_rate: 400 - # earnings_reduction = max(0, $501 - $100) = $401; raw payable = $400 - $401 = -$1 -> max(0, -1) = $0. - ok_ui_weekly_payable: 0 - -# --- max_weeks transition (§ 2-106, HB 1933): 26 pre-2023, 16 from 2023-01-01 --- - -- name: Case 19, year 2022 - pre-2023 max_weeks of 26. - period: 2022 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - # HQW $6,900 -> floor($6,900 / 23) = $300. - ok_ui_high_quarter_taxable_wages: 6_900 - ok_ui_base_period_taxable_wages: 6_900 - ok_ui_base_period_total_wages: 20_700 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_weekly_benefit_rate: 300 - # 2022 max_weeks = 26; MBA = $300 * 26 = $7,800. - ok_ui_maximum_benefit_amount: 7_800 - -- name: Case 20, year 2024 - post-2023 max_weeks of 16. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - # Same HQW as Case 19 to isolate the max_weeks change. - ok_ui_high_quarter_taxable_wages: 6_900 - ok_ui_base_period_taxable_wages: 6_900 - ok_ui_base_period_total_wages: 20_700 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_weekly_benefit_rate: 300 - # 2024 max_weeks = 16; MBA = $300 * 16 = $4,800. - ok_ui_maximum_benefit_amount: 4_800 - -# --- State gate (defined_for = "ok_ui_monetarily_eligible" with StateCode.OK) --- - -- name: Case 21, non-OK state with otherwise eligible inputs - benefit zeroed. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 11_500 - ok_ui_base_period_taxable_wages: 11_500 - ok_ui_base_period_total_wages: 35_000 - ok_ui_gross_weekly_earnings: 0 - weeks_unemployed: 16 - households: - household: - members: [person1] - state_code: TX - output: - people: - person1: - # state_code TX: StateCode.OK gate on upstream variables and the - # ok_ui_monetarily_eligible defined_for cascade returns $0. - ok_ui: 0 - -- name: Case 22, OK state with same inputs as Case 21 - benefit positive. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 11_500 - ok_ui_base_period_taxable_wages: 11_500 - ok_ui_base_period_total_wages: 35_000 - ok_ui_gross_weekly_earnings: 0 - weeks_unemployed: 16 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_monetarily_eligible: true - # WBA: floor($11,500 / 23) = $500; within 2024 [$16, $519] -> $500. - ok_ui_weekly_benefit_rate: 500 - # MBA = $500 * 16 = $8,000; annual = min($500 * 16, $8,000) = $8,000. - ok_ui: 8_000 - -- name: Case 23, base-period wages share caps annual benefit. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ok_ui_high_quarter_taxable_wages: 10_000 - ok_ui_base_period_taxable_wages: 10_000 - ok_ui_base_period_total_wages: 15_000 - ok_ui_gross_weekly_earnings: 0 - weeks_unemployed: 16 - households: - household: - members: [person1] - state_code: OK - output: - people: - person1: - ok_ui_monetarily_eligible: true - ok_ui_weekly_benefit_rate: 434 - # Lesser of $434 * 16 = $6,944, statewide $8,656, and 40% * $15,000 = $6,000. - ok_ui_maximum_benefit_amount: 6_000 - ok_ui: 6_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml index 79bf70b11bc..abcd4b01e25 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml @@ -81,3 +81,189 @@ ok_ui_monetarily_eligible: false # defined_for gate -> $0. ok_ui: 0 + +# --- End-to-end edge cases redistributed from edge_cases.yaml. --- + +- name: Case 4, all wages zero - both tests fail, no benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 0 + ok_ui_base_period_taxable_wages: 0 + ok_ui_base_period_total_wages: 0 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $0 < $1,500 -> fails. Test B: $0 not > 0 -> fails. + ok_ui_monetarily_eligible: false + # defined_for gate -> $0. + ok_ui: 0 + +- name: Case 5, eligible but zero weeks unemployed - annual benefit zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 0 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + # WBA: floor($9,200 / 23) = $400. + ok_ui_weekly_benefit_rate: 400 + # MBA = $400 * 16 = $6,400 (defined regardless of weeks worked). + ok_ui_maximum_benefit_amount: 6_400 + # Annual: min($400 * 0, $6,400) = $0. + ok_ui: 0 + +- name: Case 6, non-OK state with otherwise eligible inputs - benefit zeroed. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: TX + output: + people: + person1: + # state_code TX: StateCode.OK gate on upstream variables and the + # ok_ui_monetarily_eligible defined_for cascade returns $0. + ok_ui: 0 + +- name: Case 7, OK state with same inputs as Case 6 - benefit positive. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + # WBA: floor($11,500 / 23) = $500; within 2024 [$16, $519] -> $500. + ok_ui_weekly_benefit_rate: 500 + # MBA = $500 * 16 = $8,000; annual = min($500 * 16, $8,000) = $8,000. + ok_ui: 8_000 + +- name: Case 8, base-period wages share caps annual benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 15_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 434 + # Lesser of $434 * 16 = $6,944, statewide $8,656, and 40% * $15,000 = $6,000. + ok_ui_maximum_benefit_amount: 6_000 + ok_ui: 6_000 + +# --- Item 18(e): share-cap-derived MBA binds ok_ui even though weeks < 16. --- + +- name: Case 9, share cap binds annual benefit at 14 weeks (< 16). + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 15_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 14 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: total $15,000 >= 1.5 * $10,000 = $15,000 -> passes. + ok_ui_monetarily_eligible: true + # WBR: floor($10,000 / 23) = $434. + ok_ui_weekly_benefit_rate: 434 + # MBA = lesser of $434 * 16 = $6,944, statewide $8,656, and + # 40% * $15,000 = $6,000 -> share cap binds at $6,000. + ok_ui_maximum_benefit_amount: 6_000 + # Annual: min($434 * 14 = $6,076, $6,000) = $6,000 -> share-derived MBA + # binds despite only 14 weeks (< 16 max_weeks). + ok_ui: 6_000 + +# --- Item 19: negative base-period wages -> ok_ui $0 (monetary gate fails; the +# max_(..., 0) guard also prevents a negative MBA). --- + +- name: Case 10, negative base-period total wages - no benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: -5_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: total -$5,000 < 1.5 * $9,200 = $13,800 -> fails. + # Test B: total -$5,000 < $28,200 -> fails. + ok_ui_monetarily_eligible: false + # defined_for gate -> $0 (guard also keeps MBA >= 0). + ok_ui: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml index ad503f630d9..a1a0b22a0d2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml @@ -65,3 +65,174 @@ ok_ui_weekly_benefit_rate: 434 # Lesser of $434 * 16 = $6,944, statewide $8,656, and 40% * $15,000 = $6,000. ok_ui_maximum_benefit_amount: 6_000 + +# --- max_weeks transition cases redistributed from edge_cases.yaml (§2-106). --- + +- name: Case 4, year 2022 - pre-2023 max_weeks of 26. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # 2022: min(min($300 * 26 = $7,800, $9,900 max_amount), 0.4 * $20,700 = $8,280) = $7,800. + ok_ui_maximum_benefit_amount: 7_800 + +- name: Case 5, year 2024 - post-2023 max_weeks of 16. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # Same HQW as Case 4 to isolate the max_weeks change. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # 2024: min(min($300 * 16 = $4,800, $8,304 max_amount), 0.4 * $20,700 = $8,280) = $4,800. + ok_ui_maximum_benefit_amount: 4_800 + +# --- Item 17: 2022 base-period-wages-share (0.4) binding band. Confirms the +# restored 2022=0.4 share can be the binding cap under the 26-week regime. --- + +- name: Case 6, 2022 - 0.4 share binds under the 26-week regime. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 12_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # 26-week product $300 * 26 = $7,800 < $9,900 max_amount, but + # 0.4 * $12,000 = $4,800 share cap is the lesser -> MBA $4,800. + ok_ui_maximum_benefit_amount: 4_800 + +# --- Item 18(c): 2025 statewide max_amount binding vs the share cap. --- + +- name: Case 7, 2025 - statewide max amount binds against a large share cap. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $20,000 -> floor($20,000 / 23) = $869 -> clamped to $541 (2025 max WBA). + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 20_000 + ok_ui_base_period_total_wages: 100_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 541 + # min(min($541 * 16 = $8,656, $8,656 max_amount), 0.4 * $100,000 = $40,000) = $8,656. + ok_ui_maximum_benefit_amount: 8_656 + +# --- Item 18(d): 2026 share of 0.475 binding. --- + +- name: Case 8, 2026 - 0.475 share cap binds. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $10,000 -> floor($10,000 / 23) = $434 (within 2026 [$16, $649]). + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 12_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 434 + # min(min($434 * 16 = $6,944, $10,384 max_amount), 0.475 * $12,000 = $5,700) = $5,700. + ok_ui_maximum_benefit_amount: 5_700 + +# --- Item 18(f): 2023 16-week seam (first year at 16 weeks, share not binding). --- + +- name: Case 9, 2023 - first year at 16 weeks with non-binding share cap. + period: 2023 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 50_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # min(min($300 * 16 = $4,800, $7,888 max_amount), 0.4 * $50,000 = $20,000) = $4,800. + # Contrast Case 4 (2022, 26 weeks) -> $7,800: confirms the 16-week seam. + ok_ui_maximum_benefit_amount: 4_800 + +# --- Item 19: negative base-period wages exercise the max_(..., 0) guard so the +# share cap cannot drive MBA below zero. --- + +- name: Case 10, negative base-period total wages - share cap guarded to zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $9,200 -> WBA $400 (positive), but negative base-period total wages. + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: -5_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Guard: max(-$5,000, 0) = $0; share cap = 0.4 * $0 = $0. + # min(min($400 * 16 = $6,400, $8,656), $0) = $0 (not negative). + ok_ui_maximum_benefit_amount: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml index f1a9d1cf37c..8b5c4e316bc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml @@ -63,3 +63,44 @@ # Taxable $1,000 > 0 (passes prong 1). # Total $28,199 < $28,200 (2025 wage base) -> fails prong 2. ok_ui_meets_alternate_wages_test: false + +# --- Item 18(a): 2026 taxable wage base = $25,000; Test B step at that boundary. +# Test A cannot rescue (total < 1.5 x HQW), isolating the Test B threshold. --- + +- name: Case 4, 2026 total wages exactly at $25,000 wage base - passes Test B. + period: 2026 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 25_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $2,000 > $0 AND total $25,000 >= $25,000 (2026 wage base) -> passes (>=). + ok_ui_meets_alternate_wages_test: true + +- name: Case 5, 2026 total wages one dollar below $25,000 wage base - fails Test B. + period: 2026 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 24_999 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Total $24,999 < $25,000 (2026 wage base) -> fails prong 2. + ok_ui_meets_alternate_wages_test: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml index 08c5f4c8c68..3d56ae59b7a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml @@ -72,3 +72,140 @@ ok_ui_meets_high_quarter_test: false ok_ui_meets_alternate_wages_test: false ok_ui_monetarily_eligible: false + +# --- Boundary cases redistributed from edge_cases.yaml (Test A/Test B seams) --- +# These assert the two component tests plus the overall aggregator, all of which +# this file covers. + +- name: Case 1, Test A taxable wages exactly at $1,500 threshold. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 1_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 1_500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A taxable prong: $1,500 >= $1,500 -> passes (>= operator). + # Test A multiplier prong: $1,500 >= 1.5 * $1,000 = $1,500 -> passes (>=). + # Test A: both prongs pass. + ok_ui_meets_high_quarter_test: true + # Test B: total $1,500 < $27,000 (2024 wage base) -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: true + +- name: Case 2, Test A taxable wages one dollar below threshold. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 1_000 + ok_ui_base_period_taxable_wages: 1_499 + ok_ui_base_period_total_wages: 1_500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A taxable prong: $1,499 < $1,500 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: $1,499 > 0 but total $1,500 < $27,000 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + +- name: Case 3, Test A total wages exactly at 1.5x HQW boundary. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 5_000 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A multiplier prong: $15,000 >= 1.5 * $10,000 = $15,000 -> passes (>= operator). + # Test A taxable prong: $5,000 >= $1,500 -> passes. + ok_ui_meets_high_quarter_test: true + ok_ui_monetarily_eligible: true + +- name: Case 4, Test A total wages one dollar below 1.5x HQW boundary. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 5_000 + ok_ui_base_period_total_wages: 14_999 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A multiplier prong: $14,999 < 1.5 * $10,000 = $15,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: total $14,999 < $27,000 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + +- name: Case 5, Test B total wages exactly at 2025 taxable wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_200 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $28,200 < 1.5 * $20,000 = $30,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: taxable $2,000 > $0 AND $28,200 >= $28,200 (2025 wage base) -> passes (>=). + ok_ui_meets_alternate_wages_test: true + ok_ui_monetarily_eligible: true + +- name: Case 6, Test B total wages one dollar below 2025 taxable wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_199 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $28,199 < $30,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: $28,199 < $28,200 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml index abb3d5247eb..8b84b9ba818 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml @@ -118,3 +118,167 @@ # floor($20,000 / 23) = floor($869.57) = $869. # $869 > $476 (2022 max) -> clamped to $476. ok_ui_weekly_benefit_rate: 476 + +# --- WBA clamp boundaries redistributed from edge_cases.yaml (min $16 floor, +# annual max ceiling; §2-104(A)). --- + +- name: Case 7, WBA below minimum - HQW $367 clamped up to $16 floor. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 367 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 2_250 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($367 / 23) = floor($15.957) = $15 -> below $16 minimum -> clamped to $16. + ok_ui_weekly_benefit_rate: 16 + +- name: Case 8, WBA exactly at minimum - HQW $368 yields $16. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 368 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 2_250 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($368 / 23) = floor($16.0) = $16 -> exactly at minimum. + ok_ui_weekly_benefit_rate: 16 + +- name: Case 9, WBA exactly at 2024 maximum - HQW $11,937 yields $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_937 + ok_ui_base_period_taxable_wages: 11_937 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # 519 * 23 = $11,937 exactly; floor($11,937 / 23) = $519. + # 2024 max is $519 -> no clamp needed, exactly at boundary. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 10, WBA still at 2024 max - HQW $11,938 yields $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_938 + ok_ui_base_period_taxable_wages: 11_938 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($11,938 / 23) = floor($519.043) = $519 -> at 2024 max, no clamp. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 11, WBA clamped down at 2024 max - HQW $11,960 yields $520 raw, clamped to $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_960 + ok_ui_base_period_taxable_wages: 11_960 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # 520 * 23 = $11,960 exactly; floor($11,960 / 23) = $520. + # $520 > $519 (2024 max) -> clamped down to $519. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 12, very high HQW clamped to 2025 max $541. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 100_000 + ok_ui_base_period_taxable_wages: 100_000 + ok_ui_base_period_total_wages: 300_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($100,000 / 23) = floor($4,347.83) = $4,347 -> far above $541 (2025 max) -> clamped to $541. + ok_ui_weekly_benefit_rate: 541 + +# --- WBA annual-max clamp seams (item 18b) and negative-HQW floor (item 19). --- + +- name: Case 13, very high HQW clamped to 2023 max $493. + period: 2023 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 100_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($100,000 / 23) = $4,347 -> above $493 (2023 max) -> clamped to $493. + ok_ui_weekly_benefit_rate: 493 + +- name: Case 14, negative HQW lifted to $16 statutory floor. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: -1_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor(-$1,000 / 23) = floor(-$43.48) = -$44; max(-$44, $16) = $16; + # min($16, $541) = $16. The $16 min_amount floor absorbs negative HQW. + ok_ui_weekly_benefit_rate: 16 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml index 101e2c51e51..1075f0c5ea7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml @@ -96,3 +96,94 @@ # Earnings $600 > $100 -> earnings_offset = $600 - $100 = $500. # Raw payable = $400 - $500 = -$100; max(0, -$100) = $0. ok_ui_weekly_payable: 0 + +# --- Disregard boundaries redistributed from edge_cases.yaml (§2-105). All use +# 2025 HQW $9,200 -> WBA $400. --- + +- name: Case 5, weekly earnings exactly at $100 disregard - full WBA paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 100 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $100 - $100) = $0; payable = max(0, $400 - 0) = $400. + ok_ui_weekly_payable: 400 + +- name: Case 6, weekly earnings one dollar above disregard - WBA reduced by $1. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 101 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $101 - $100) = $1; payable = max(0, $400 - $1) = $399. + ok_ui_weekly_payable: 399 + +- name: Case 7, weekly earnings exactly at WBA + disregard - payable zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $500 - $100) = $400; payable = max(0, $400 - $400) = $0. + ok_ui_weekly_payable: 0 + +- name: Case 8, weekly earnings above WBA + disregard - payable floored at zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 501 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $501 - $100) = $401; raw payable = $400 - $401 = -$1 -> max(0, -1) = $0. + ok_ui_weekly_payable: 0 diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py index aa008c6e789..68c6e2e8b7c 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py @@ -7,19 +7,33 @@ class ok_ui(Variable): partial benefit subtraction (§ 2-105), and benefit duration cap (§ 2-106 / § 1-231). - Not modeled: § 1-202.1 / § 1-202.2 alternative and extended base + Not modeled: § 1-201(48) / § 1-217(B) alternative and extended base periods; § 2-104(B) max-WBA percentage derivation by fund condition - (only the resulting maximum dollar amount is parameterized); § 1-231(A) - claim-volume duration escalation to 20 or 26 weeks; § 2-107 portion- - of-a-week proration; § 2-108 approved training waiver; § 2-202 / - § 2-205.1 able-available-seeking-work; § 2-206 one-week waiting period; - § 2-208 alien-status rules; § 2-109 10x WBA requalification; all - § 2-404 through § 2-422 disqualifications. + (only the resulting maximum dollar amount is parameterized); § 2-106(2) + statutory %-of-average-annual-wage benefit-year cap (OESC-published proxy + used instead); § 1-217(B)(2) 15% wage/hour-loss unemployment prong; + § 1-231 16-to-26-week claim-volume duration escalation above the 16-week + floor; § 2-107 portion-of-a-week proration; § 2-108 approved training + waiver; § 2-202 / § 2-205.1 able-available-seeking-work; § 2-206 one-week + waiting period; § 2-208 alien-status rules; § 2-109 10x WBA + requalification; § 1-202.1 / § 1-202.2 alternative and extended base + periods; all § 2-404 through § 2-422 disqualifications. """ value_type = float entity = Person label = "Oklahoma unemployment insurance" + documentation = ( + "Annual Oklahoma Unemployment Insurance benefit. Not modeled: the " + "§ 2-106(2) statutory percentage-of-average-annual-wage benefit-year " + "cap (an OESC-published proxy is used); the § 1-231 claim-volume " + "duration escalation above the 16-week floor (up to 20 or 26 weeks); " + "the § 1-217(B)(2) 15% wage/hour-loss partial-unemployment prong; the " + "§ 2-206 one-week waiting period; the § 1-202.1 / § 1-202.2 " + "alternative and extended base periods; and the § 2-404 through " + "§ 2-422 nonmonetary disqualifications, waiting week, and " + "able-available-seeking-work requirements." + ) unit = USD definition_period = YEAR defined_for = "ok_ui_monetarily_eligible" diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py index 3529d41dc1c..2a90e1bd243 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py @@ -2,12 +2,14 @@ class ok_ui_base_period_taxable_wages(Variable): - """Sum of taxable wages (capped at the Oklahoma taxable wage base per - quarter) across all four quarters of the base period, per 40 O.S. § 1-223 - and § 1-201(4). Used in the monetary-eligibility tests in § 2-207(A) and - § 2-207(B). PolicyEngine cannot derive quarterly wages from annual data, - so this is a direct input rather than a computed value; populate via test - fixtures or reform. + """Sum of taxable wages across all four quarters of the base period, each + capped at the Oklahoma taxable wage base. Per 40 O.S. § 1-201(48) the + taxable-wage cap applies per CALENDAR YEAR, not per quarter, per 40 O.S. + § 1-223 and § 1-201(4). Used in the monetary-eligibility tests in + § 2-207(A) and § 2-207(B). PolicyEngine cannot derive quarterly wages from + annual data, so this is a direct input rather than a computed value; + populate via test fixtures or reform. Defaults to zero, so it is inert in + microsimulation until supplied. """ value_type = float @@ -18,6 +20,6 @@ class ok_ui_base_period_taxable_wages(Variable): default_value = 0 defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=20", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=19", "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py index 76554a296bd..87b10da685c 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py @@ -8,6 +8,7 @@ class ok_ui_base_period_total_wages(Variable): the monetary-eligibility tests in § 2-207(A) and § 2-207(B). PolicyEngine cannot derive quarterly wages from annual data, so this is a direct input rather than a computed value; populate via test fixtures or reform. + Defaults to zero, so it is inert in microsimulation until supplied. """ value_type = float @@ -18,7 +19,7 @@ class ok_ui_base_period_total_wages(Variable): default_value = 0 defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=20", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=19", "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=42", "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py index 748f9479071..6929eb0f95b 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py @@ -4,17 +4,18 @@ class ok_ui_gross_weekly_earnings(Variable): """Gross earnings during a week of partial unemployment, used to compute the partial weekly benefit reduction per 40 O.S. § 2-105. Stored at the - annual definition period to match other UI inputs; populate via test - fixtures or reform. + annual definition period but holds an average WEEKLY figure; populate via + test fixtures or reform. Defaults to zero, so it is inert in + microsimulation until supplied. """ value_type = float entity = Person - label = "Oklahoma UI gross weekly earnings" + label = "Oklahoma UI average weekly earnings (year-period input)" unit = USD definition_period = YEAR default_value = 0 defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py index 86e26658d8e..81f97077e02 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py @@ -3,10 +3,13 @@ class ok_ui_high_quarter_taxable_wages(Variable): """Wages paid in the claimant's highest base-period quarter, capped at the - Oklahoma taxable wage base per quarter. Used as the input to the weekly + Oklahoma taxable wage base. Per 40 O.S. § 1-201(48) the taxable-wage cap + applies per CALENDAR YEAR, not per quarter; test fixtures should supply + the already-capped high-quarter figure. Used as the input to the weekly benefit amount formula per 40 O.S. § 2-104(A). PolicyEngine cannot derive quarterly wages from annual data, so this is a direct input rather than a - computed value; populate via test fixtures or reform. + computed value; populate via test fixtures or reform. Defaults to zero, so + it is inert in microsimulation until supplied. """ value_type = float @@ -18,5 +21,5 @@ class ok_ui_high_quarter_taxable_wages(Variable): defined_for = StateCode.OK reference = ( "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py index e9e238918ca..a859890e1fc 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py @@ -19,7 +19,11 @@ def formula(person, period, parameters): # applicable share of base-period wages. p = parameters(period).gov.states.ok.oesc.unemployment_insurance.mba weekly_benefit_rate = person("ok_ui_weekly_benefit_rate", period) - base_period_total_wages = person("ok_ui_base_period_total_wages", period) + # Guard against negative base-period wages so the share-of-wages cap + # cannot drive the maximum benefit amount below zero. + base_period_total_wages = max_( + person("ok_ui_base_period_total_wages", period), 0 + ) return min_( min_(weekly_benefit_rate * p.max_weeks, p.max_amount), base_period_total_wages * p.base_period_wages_share, diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py index 74104cad394..ec315b5e1ec 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py @@ -2,6 +2,17 @@ class ok_ui_meets_high_quarter_test(Variable): + """Oklahoma UI high-quarter monetary eligibility test (§ 2-207(A)). + + Note: § 2-207(A)(2) applies the 1.5x multiplier to the claimant's + unqualified (total) wages. This implementation uses taxable high-quarter + wages as a proxy for the high-quarter figure driving the test. The + deviation matters only for high-quarter earners whose wages are capped at + the taxable wage base; in the cases PolicyEngine models, the alternate + wages test (Test B) rescues final eligibility, so the proxy does not + change the modeled monetary-eligibility outcome. + """ + value_type = bool entity = Person label = "Meets the Oklahoma UI high-quarter monetary eligibility test" diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py index 5e209ca17da..9aea9b7001b 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py @@ -9,7 +9,7 @@ class ok_ui_weekly_benefit_rate(Variable): definition_period = YEAR defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py index 1763d12ef47..43d76589d8e 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py @@ -9,7 +9,7 @@ class ok_ui_weekly_payable(Variable): definition_period = YEAR defined_for = "ok_ui_monetarily_eligible" reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51", ) def formula(person, period, parameters): From 522a41535161aa2819b957609e71a854407559bb Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Fri, 14 Aug 2026 13:36:20 -0400 Subject: [PATCH 09/10] Address review: fix conditional-factor legend and label wage-definition citations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct the base_period_wages_share comment so 40% maps to factor (e) and 47.5% to (b) (was 'd'/'a'); the 0.4/0.475 values are unchanged. Add section labels (§1-201/§1-218/§2-207, §1-223) to the previously bare os40.pdf page anchors on the two base-period wage variables. Documentation only, no value or logic change — OK suite 328/328 pass. Co-Authored-By: Claude Opus 4.8 --- .../unemployment_insurance/mba/base_period_wages_share.yaml | 2 +- .../unemployment_insurance/ok_ui_base_period_taxable_wages.py | 2 ++ .../unemployment_insurance/ok_ui_base_period_total_wages.py | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml index 2401d83d295..4272bc0f72a 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml @@ -3,7 +3,7 @@ description: Oklahoma limits unemployment compensation benefits to this share of values: # 40 O.S. §2-106(3) base-period-wages percentages: (a) 50%, (b) 47.5%, # (c) 45%, (d) 42.5%, (e) 40%, keyed to the conditional factor in place. - # 2022-2025 reflect condition "d" (40%); 2026 reflects condition "a" (47.5%). + # 2022-2025 reflect condition "e" (40%); 2026 reflects condition "b" (47.5%). 2022-01-01: 0.4 2026-01-01: 0.475 diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py index 2a90e1bd243..32119eaa95d 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py @@ -20,6 +20,8 @@ class ok_ui_base_period_taxable_wages(Variable): default_value = 0 defined_for = StateCode.OK reference = ( + # 40 O.S. §1-201(48) — Taxable wages / base period definitions "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=19", + # 40 O.S. §1-223 — Taxable wage base "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py index 87b10da685c..19f7ccb8aef 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py @@ -19,7 +19,10 @@ class ok_ui_base_period_total_wages(Variable): default_value = 0 defined_for = StateCode.OK reference = ( + # 40 O.S. §1-201(4) — Base period definition "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=19", + # 40 O.S. §1-218 — Wages definition "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=42", + # 40 O.S. §2-207 — Total wages used in monetary-eligibility tests "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", ) From 5f04838a6a078c8e1537ab3b23da421c6aeb57ab Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Fri, 14 Aug 2026 15:33:20 -0400 Subject: [PATCH 10/10] Address @hua7450 review: use total wages in the high-quarter test, fix citations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C1 (behavioral): the §2-207(A)(2) high-quarter eligibility multiplier read capped TAXABLE wages, wrongly passing an ineligible claimant. Add a ok_ui_high_quarter_total_wages input and apply the 1.5x prong to total wages per the statute; remove the false Test-B-rescue docstring. Add a divergence test that inverts if reverted, plus MBA-binding and 2023/2026 end-to-end cases. - C2: correct the os40.pdf #page anchors across the MBA/WBA/wage-base refs and the base-period wage variables (values were already right). - A5-A10: taxable_wage_base §1-223 vintage note; drop the stale handbook Rev-05-2025 label and the 'OESC Board determines' phrasing; correct max_weeks' §1-231 attribution (Laws 2022 c.287) and reframe the escalator as operative- but-non-binding; disclose the employer payroll-tax effect in the changelog; guard weeks_unemployed with max_(...,0); reference cleanups. No parameter value changed. OK UI suite 335/335 pass. Co-Authored-By: Claude Opus 4.8 --- changelog.d/ok-ui.added.md | 1 + .../mba/base_period_wages_share.yaml | 2 +- .../mba/max_amount.yaml | 6 +- .../unemployment_insurance/mba/max_weeks.yaml | 20 +-- .../wba/max_amount.yaml | 10 +- .../unemployment/taxable_wage_base.yaml | 11 +- .../unemployment_insurance/integration.yaml | 8 +- .../ok/oesc/unemployment_insurance/ok_ui.yaml | 148 ++++++++++++++++++ .../ok_ui_maximum_benefit_amount.yaml | 30 ++++ .../ok_ui_meets_high_quarter_test.yaml | 42 ++++- .../ok_ui_monetarily_eligible.yaml | 9 ++ .../ok_ui_weekly_benefit_rate.yaml | 2 +- .../ok/oesc/unemployment_insurance/ok_ui.py | 28 ++-- .../ok_ui_base_period_taxable_wages.py | 2 +- .../ok_ui_base_period_total_wages.py | 2 +- .../ok_ui_gross_weekly_earnings.py | 6 +- .../ok_ui_high_quarter_taxable_wages.py | 4 +- .../ok_ui_high_quarter_total_wages.py | 24 +++ .../ok_ui_maximum_benefit_amount.py | 3 +- .../ok_ui_meets_high_quarter_test.py | 15 +- .../ok_ui_weekly_benefit_rate.py | 3 + 21 files changed, 318 insertions(+), 58 deletions(-) create mode 100644 policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_total_wages.py diff --git a/changelog.d/ok-ui.added.md b/changelog.d/ok-ui.added.md index 95dae71528a..619d7d92233 100644 --- a/changelog.d/ok-ui.added.md +++ b/changelog.d/ok-ui.added.md @@ -1 +1,2 @@ Add Oklahoma Unemployment Insurance. +The Oklahoma taxable wage base is now dated 2022-2026, which corrects ok_employer_state_unemployment_tax in four of five years. diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml index 4272bc0f72a..d53f84fff0f 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml @@ -13,7 +13,7 @@ metadata: label: Oklahoma UI maximum benefit base period wages share reference: - title: 40 O.S. §2-106(3) - href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=53 - title: 40 O.S. §2-106 href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 - title: OESC Important Numbers for 2023 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml index 35f6f268527..2cf413b22a0 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml @@ -19,11 +19,11 @@ metadata: label: Oklahoma UI maximum benefit amount reference: - title: 40 O.S. §2-106(2) - href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=52 - title: 40 O.S. §2-106 href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 - - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021 - href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 + - title: Oklahoma Unemployment Insurance Tax Rates by Industry, Size, and County (2022 column) + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=6 - title: OESC Important Numbers for 2023 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 - title: OESC Important Numbers for 2024 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml index e36e99d296e..f8fc4141db8 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml @@ -1,12 +1,14 @@ description: Oklahoma limits unemployment compensation benefits to this number of weeks within a benefit year under the Unemployment Insurance program. values: - # 40 O.S. §2-106(1) sets the times-WBA multiplier for the benefit-year cap. - # §1-231 sets the duration floor at 16 weeks from Jan. 1, 2025 (Laws 2024, - # c. 114 / HB 3596), escalating +2 weeks per 15,000-claim increment up to - # 20 weeks, and up to 26 weeks if continued claims exceed 40,000. The - # 16-to-26-week claim-volume escalator above the 16-week floor is not - # modeled, so 16 weeks remains operative for 2025 and 2026. + # 40 O.S. §2-106(1) sets the times-WBA multiplier for the benefit-year cap; + # the 2023-01-01 key rests on §2-106(1)(b). §1-231 (Laws 2022, c. 287 / + # HB 1933) sets the duration floor at 16 weeks, escalating +2 weeks per + # 15,000-claim increment up to 20 weeks, and up to 26 weeks if continued + # claims exceed 40,000. That escalator is operative but does not bind here: + # the 13-week continued-claim averages (roughly 10,266 in 2025 and 11,393 in + # 2026) sit below the first 15,000-claim increment, so 16 weeks remains the + # applicable duration. 1980-07-01: 26 2023-01-01: 16 @@ -20,10 +22,8 @@ metadata: - title: 40 O.S. §1-231 href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=492632 - title: 40 O.S. §2-106(1) - href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=52 - title: 40 O.S. §2-106 href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 - - title: Oklahoma House Bill 1933 (2022) + - title: Oklahoma House Bill 1933 (Laws 2022, c. 287) href: https://www.oklegislature.gov/cf_pdf/2021-22%20ENR/hB/HB1933%20ENR.PDF - - title: Oklahoma House Bill 3596 (Laws 2024, c. 114), eff. 2024-11-01 - href: https://www.oklegislature.gov/cf_pdf/2023-24%20ENR/hB/HB3596%20ENR.PDF diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml index aca1f1a08ba..65589dee88d 100644 --- a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml @@ -12,21 +12,19 @@ metadata: period: week label: Oklahoma UI maximum weekly benefit amount reference: - - title: 40 O.S. §2-104(B) (OESC Board determines maximum weekly benefit annually) + - title: 40 O.S. §2-104(B) href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 - title: 40 O.S. §2-104 href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77164 - - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021 - href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 + - title: Oklahoma Unemployment Insurance Tax Rates by Industry, Size, and County (2022 column) + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=6 - title: OESC Important Numbers for 2023 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 - title: OESC Important Numbers for 2024 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 - title: OESC Important Numbers for 2025 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2025.pdf#page=1 - - title: OESC Claimant Handbook OES-339 (Rev. 05-2025) + - title: OESC Claimant Handbook OES-339 href: https://oklahoma.gov/content/dam/ok/en/oesc/documents/forms/OES-339.pdf#page=4 - - title: Oklahoma Employment Security Commission - href: https://oklahoma.gov/oesc.html - title: OESC Important Numbers for 2026 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml index d3a047ff773..6db22f2bea2 100644 --- a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml +++ b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml @@ -1,6 +1,13 @@ description: Oklahoma sets the annual unemployment insurance taxable wage base at this amount under the Unemployment Insurance program. values: + # 40 O.S. §1-223 sets the taxable wage base as a conditional-factor share of + # the state's average annual wage. The pre-Laws-2025 ladder ran 40 / 42.5 / + # 45 / 47.5 / 50% across factors A-D; conditional factor "D" applies for + # 2022-2025 and factor "A" for 2026. The Laws 2025 ladder (effective + # Nov. 1, 2025) resets these shares, which is why the 2026 base falls below + # the 2025 base rather than rising. Values below are the OESC-published + # taxable wage bases, so no recomputation from the ladder is required. 0000-01-01: 27_000 2022-01-01: 24_800 2023-01-01: 25_700 @@ -25,8 +32,8 @@ metadata: href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 - title: 40 O.S. §2-207 href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77177 - - title: Oklahoma UI Tax Rates by Industry, Size, and County, 2021 - href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=2 + - title: Oklahoma Unemployment Insurance Tax Rates by Industry, Size, and County (2022 column) + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=6 - title: OESC Important Numbers for 2023 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 - title: OESC Important Numbers for 2024 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml index 83750aa4486..c776e6375d4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml @@ -1,7 +1,7 @@ # Integration tests for Oklahoma Unemployment Insurance (OK UI). # End-to-end scenarios checking ok_ui together with intermediate variables. # References: 40 O.S. §§1-202, 1-218, 1-223, 1-231, 2-102, 2-104, 2-105, 2-106, 2-207; -# OESC Claimant Handbook OES-339 (Rev. 05-2025); OESC Important Numbers 2024/2025/2026. +# OESC Claimant Handbook OES-339; OESC Important Numbers 2024/2025/2026. - name: Case 1, eligible single claimant with mid-range wages in 2024. period: 2024 @@ -11,6 +11,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_high_quarter_total_wages: 11_500 ok_ui_base_period_taxable_wages: 11_500 ok_ui_base_period_total_wages: 35_000 ok_ui_gross_weekly_earnings: 0 @@ -42,6 +43,7 @@ person1: age: 40 ok_ui_high_quarter_taxable_wages: 5_000 + ok_ui_high_quarter_total_wages: 5_000 ok_ui_base_period_taxable_wages: 500 ok_ui_base_period_total_wages: 5_000 ok_ui_gross_weekly_earnings: 0 @@ -69,6 +71,7 @@ person1: age: 45 ok_ui_high_quarter_taxable_wages: 30_000 + ok_ui_high_quarter_total_wages: 30_000 ok_ui_base_period_taxable_wages: 30_000 ok_ui_base_period_total_wages: 90_000 ok_ui_gross_weekly_earnings: 0 @@ -99,6 +102,7 @@ age: 32 # HQW $9,200 -> WBA = $400. ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_high_quarter_total_wages: 9_200 ok_ui_base_period_taxable_wages: 9_200 ok_ui_base_period_total_wages: 30_000 ok_ui_gross_weekly_earnings: 200 @@ -131,6 +135,7 @@ age: 38 # HQW $6,900 -> WBA = $300. ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_high_quarter_total_wages: 6_900 ok_ui_base_period_taxable_wages: 6_900 ok_ui_base_period_total_wages: 20_700 ok_ui_gross_weekly_earnings: 0 @@ -160,6 +165,7 @@ person1: age: 50 ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 ok_ui_base_period_taxable_wages: 2_000 ok_ui_base_period_total_wages: 28_500 ok_ui_gross_weekly_earnings: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml index abcd4b01e25..1cb30f16ab1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml @@ -267,3 +267,151 @@ ok_ui_monetarily_eligible: false # defined_for gate -> $0 (guard also keeps MBA >= 0). ok_ui: 0 + +# --- C3 (end-to-end): statewide max_amount $9,900 binds ok_ui in 2022 under the +# 26-week regime, where WBR*26 overshoots the cap. --- + +- name: Case 11, 2022 - statewide max_amount caps annual benefit at $9,900. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $20,000 -> floor($20,000 / 23) = $869 -> clamped to $476 (2022 max WBA). + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_base_period_taxable_wages: 20_000 + ok_ui_base_period_total_wages: 100_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 26 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $20,000 >= $1,500; total $100,000 >= 1.5 * $20,000 = $30,000 -> passes. + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 476 + # MBA = min(min($476 * 26 = $12,376, $9,900 max_amount), 0.4 * $100,000 = $40,000) = $9,900. + ok_ui_maximum_benefit_amount: 9_900 + # Annual: min($476 * 26 = $12,376, $9,900) = $9,900 (statewide max_amount binds). + ok_ui: 9_900 + +# --- C4: end-to-end year coverage for 2023 and 2026 (publishes verified_years +# 2022-2026). --- + +- name: Case 12, 2023 - first 16-week year yields ok_ui $4,800. + period: 2023 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300 (within 2023 [$16, $493]). + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_high_quarter_total_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 50_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $6,900 >= $1,500; total $50,000 >= 1.5 * $6,900 = $10,350 -> passes. + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 300 + # MBA = min(min($300 * 16 = $4,800, $7,888 max_amount), 0.4 * $50,000 = $20,000) = $4,800. + ok_ui_maximum_benefit_amount: 4_800 + # Annual: min($300 * 16 = $4,800, $4,800) = $4,800. + ok_ui: 4_800 + +- name: Case 13, 2026 - 16 x max WBA equals max_amount, ok_ui $10,384. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $20,000 -> floor($20,000 / 23) = $869 -> clamped to $649 (2026 max WBA). + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_base_period_taxable_wages: 20_000 + ok_ui_base_period_total_wages: 100_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $20,000 >= $1,500; total $100,000 >= 1.5 * $20,000 = $30,000 -> passes. + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 649 + # MBA = min(min($649 * 16 = $10,384, $10,384 max_amount), 0.475 * $100,000 = $47,500) = $10,384. + # ($649 * 16 ties the $10,384 max_amount because max_amount is published as 16 x max WBA.) + ok_ui_maximum_benefit_amount: 10_384 + # Annual: min($649 * 16 = $10,384, $10,384) = $10,384. + ok_ui: 10_384 + +# --- A3/A9 hardening: minimum WBA floor and negative-weeks guard. --- + +- name: Case 14, zero high-quarter taxable wages - WBR floored at statutory $16 minimum. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW taxable $0 -> floor($0 / 23) = $0 -> floored up to the $16 minimum. + ok_ui_high_quarter_taxable_wages: 0 + ok_ui_high_quarter_total_wages: 1_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 10 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $1,500 >= $1,500; total $30,000 >= 1.5 * $1,000 = $1,500 -> passes. + ok_ui_monetarily_eligible: true + # max(floor($0 / 23), $16) = $16 (statutory minimum floor). + ok_ui_weekly_benefit_rate: 16 + # Annual: min($16 * 10 = $160, MBA $256) = $160. + ok_ui: 160 + +- name: Case 15, negative weeks unemployed - guarded to zero benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_high_quarter_total_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: -5 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + # max(-5, 0) = 0 weeks; annual = min($400 * 0, $6,400) = $0 (not negative). + ok_ui: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml index a1a0b22a0d2..60e6db334a3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml @@ -236,3 +236,33 @@ # Guard: max(-$5,000, 0) = $0; share cap = 0.4 * $0 = $0. # min(min($400 * 16 = $6,400, $8,656), $0) = $0 (not negative). ok_ui_maximum_benefit_amount: 0 + +# --- C3: statewide max_amount ($9,900) actually BINDS in 2022 under the 26-week +# regime. Because the 2023-2026 max_amount values are published as 16 x maximum +# WBA, WBR*max_weeks can never exceed max_amount once max_weeks = 16, so +# max_amount is structurally unfalsifiable after 2022. 2022 is the only year the +# suite can demonstrate it binding, since 26 weeks lets WBR*max_weeks overshoot. --- + +- name: Case 11, 2022 - statewide max_amount $9,900 binds under the 26-week regime. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $20,000 -> floor($20,000 / 23) = $869 -> clamped to $476 (2022 max WBA). + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 20_000 + ok_ui_base_period_total_wages: 100_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 476 + # 26-week product $476 * 26 = $12,376 exceeds the $9,900 max_amount, and + # the share cap 0.4 * $100,000 = $40,000 is larger still, so the + # statewide $9,900 max_amount is the binding constraint. + ok_ui_maximum_benefit_amount: 9_900 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml index 973dce5260f..5a2b5197af5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml @@ -1,7 +1,7 @@ # Tests for Oklahoma UI monetary eligibility Test A (40 O.S. §2-207(A)). # Both conditions must be met: # 1. Base-period taxable wages >= $1,500. -# 2. Total base-period wages >= 1.5 x high-quarter taxable wages. +# 2. Total base-period wages >= 1.5 x high-quarter total wages. # Reference: 40 O.S. §2-207(A). - name: Case 1, both prongs pass with margin. @@ -10,7 +10,7 @@ people: person1: age: 35 - ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 ok_ui_base_period_taxable_wages: 1_500 ok_ui_base_period_total_wages: 15_000 households: @@ -30,7 +30,7 @@ people: person1: age: 35 - ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 ok_ui_base_period_taxable_wages: 1_499 ok_ui_base_period_total_wages: 15_000 households: @@ -49,7 +49,7 @@ people: person1: age: 35 - ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 ok_ui_base_period_taxable_wages: 2_000 ok_ui_base_period_total_wages: 14_999 households: @@ -69,7 +69,7 @@ people: person1: age: 35 - ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 ok_ui_base_period_taxable_wages: 1_500 ok_ui_base_period_total_wages: 15_000 households: @@ -82,3 +82,35 @@ # Taxable exactly $1,500 (passes prong 1; >= test). # Total exactly $15,000 = 1.5 * $10,000 (passes prong 2; >= test). ok_ui_meets_high_quarter_test: true + +# --- C1 regression guard: prong 2 must multiply TOTAL high-quarter wages, not +# the taxable-capped figure (§2-207(A)(2) uses bare "wages"). This case is in +# the divergence zone where high-quarter taxable wages are capped BELOW total +# high-quarter wages, so the old (taxable) reference and the new (total) +# reference give OPPOSITE eligibility results. It fails if C1 is reverted. --- + +- name: Case 5, divergence zone - taxable HQW capped below total HQW flips prong 2. + period: 2024 + input: + people: + person1: + age: 35 + # Total high-quarter wages $20,000; taxable high-quarter wages capped + # at $10,000 (below total). Old code multiplied the $10,000 taxable + # figure; correct code multiplies the $20,000 total figure. + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 25_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Prong 1: taxable $2,000 >= $1,500 -> passes. + # Prong 2 (NEW, total): $25,000 < 1.5 * $20,000 = $30,000 -> FAILS. + # Prong 2 (OLD, taxable): $25,000 >= 1.5 * $10,000 = $15,000 -> would PASS. + # Correct result is false; a revert to taxable wages would return true. + ok_ui_meets_high_quarter_test: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml index 3d56ae59b7a..e012bf9ede1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml @@ -11,6 +11,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 ok_ui_base_period_taxable_wages: 5_000 ok_ui_base_period_total_wages: 20_000 households: @@ -34,6 +35,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 ok_ui_base_period_taxable_wages: 2_000 ok_ui_base_period_total_wages: 28_500 households: @@ -57,6 +59,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 ok_ui_base_period_taxable_wages: 1_000 ok_ui_base_period_total_wages: 12_000 households: @@ -84,6 +87,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 1_000 + ok_ui_high_quarter_total_wages: 1_000 ok_ui_base_period_taxable_wages: 1_500 ok_ui_base_period_total_wages: 1_500 households: @@ -108,6 +112,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 1_000 + ok_ui_high_quarter_total_wages: 1_000 ok_ui_base_period_taxable_wages: 1_499 ok_ui_base_period_total_wages: 1_500 households: @@ -130,6 +135,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 ok_ui_base_period_taxable_wages: 5_000 ok_ui_base_period_total_wages: 15_000 households: @@ -151,6 +157,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 ok_ui_base_period_taxable_wages: 5_000 ok_ui_base_period_total_wages: 14_999 households: @@ -173,6 +180,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 ok_ui_base_period_taxable_wages: 2_000 ok_ui_base_period_total_wages: 28_200 households: @@ -195,6 +203,7 @@ person1: age: 35 ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 ok_ui_base_period_taxable_wages: 2_000 ok_ui_base_period_total_wages: 28_199 households: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml index 8b84b9ba818..ba477007cdc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml @@ -21,7 +21,7 @@ person1: # floor($14,000 / 23) = floor($608.69) = $608. # $608 > $519 (2024 max) -> clamped to $519. - # Matches OES-339 Rev. 05-2025 page 4 worked example. + # Matches OES-339 page 4 worked example. ok_ui_weekly_benefit_rate: 519 - name: Case 2, low HQW lifted to statutory minimum $16. diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py index 68c6e2e8b7c..3251f6492f8 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py @@ -7,17 +7,16 @@ class ok_ui(Variable): partial benefit subtraction (§ 2-105), and benefit duration cap (§ 2-106 / § 1-231). - Not modeled: § 1-201(48) / § 1-217(B) alternative and extended base - periods; § 2-104(B) max-WBA percentage derivation by fund condition - (only the resulting maximum dollar amount is parameterized); § 2-106(2) - statutory %-of-average-annual-wage benefit-year cap (OESC-published proxy - used instead); § 1-217(B)(2) 15% wage/hour-loss unemployment prong; - § 1-231 16-to-26-week claim-volume duration escalation above the 16-week - floor; § 2-107 portion-of-a-week proration; § 2-108 approved training - waiver; § 2-202 / § 2-205.1 able-available-seeking-work; § 2-206 one-week - waiting period; § 2-208 alien-status rules; § 2-109 10x WBA - requalification; § 1-202.1 / § 1-202.2 alternative and extended base - periods; all § 2-404 through § 2-422 disqualifications. + Not modeled: § 1-202.1 alternative and extended base periods; § 2-104(B) + max-WBA percentage derivation by fund condition (only the resulting + maximum dollar amount is parameterized); § 2-106(2) statutory + %-of-average-annual-wage benefit-year cap (OESC-published proxy used + instead); § 1-217(B)(2) 15% wage/hour-loss unemployment prong; § 1-231 + 16-to-26-week claim-volume duration escalation above the 16-week floor; + § 2-107 portion-of-a-week proration; § 2-108 approved training waiver; + § 2-202 / § 2-205.1 able-available-seeking-work; § 2-206 one-week waiting + period; § 2-208 alien-status rules; § 2-109 10x WBA requalification; all + § 2-404 through § 2-422 disqualifications. """ value_type = float @@ -29,8 +28,8 @@ class ok_ui(Variable): "cap (an OESC-published proxy is used); the § 1-231 claim-volume " "duration escalation above the 16-week floor (up to 20 or 26 weeks); " "the § 1-217(B)(2) 15% wage/hour-loss partial-unemployment prong; the " - "§ 2-206 one-week waiting period; the § 1-202.1 / § 1-202.2 " - "alternative and extended base periods; and the § 2-404 through " + "§ 2-206 one-week waiting period; the § 1-202.1 alternative and " + "extended base periods; and the § 2-404 through " "§ 2-422 nonmonetary disqualifications, waiting week, and " "able-available-seeking-work requirements." ) @@ -45,6 +44,7 @@ class ok_ui(Variable): def formula(person, period, parameters): weekly_payable = person("ok_ui_weekly_payable", period) maximum_benefit_amount = person("ok_ui_maximum_benefit_amount", period) - weeks_unemployed = person("weeks_unemployed", period) + # Guard against negative weeks so the benefit cannot go below zero. + weeks_unemployed = max_(person("weeks_unemployed", period), 0) annual_benefit = weekly_payable * weeks_unemployed return min_(annual_benefit, maximum_benefit_amount) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py index 32119eaa95d..8a2a77bbb8a 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py @@ -21,7 +21,7 @@ class ok_ui_base_period_taxable_wages(Variable): defined_for = StateCode.OK reference = ( # 40 O.S. §1-201(48) — Taxable wages / base period definitions - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=19", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=23", # 40 O.S. §1-223 — Taxable wage base "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py index 19f7ccb8aef..99750a0b6f7 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py @@ -20,7 +20,7 @@ class ok_ui_base_period_total_wages(Variable): defined_for = StateCode.OK reference = ( # 40 O.S. §1-201(4) — Base period definition - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=19", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=20", # 40 O.S. §1-218 — Wages definition "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=42", # 40 O.S. §2-207 — Total wages used in monetary-eligibility tests diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py index 6929eb0f95b..bc6095b88c4 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py @@ -11,7 +11,11 @@ class ok_ui_gross_weekly_earnings(Variable): value_type = float entity = Person - label = "Oklahoma UI average weekly earnings (year-period input)" + label = "Oklahoma UI average weekly earnings" + documentation = ( + "Stored at the annual definition period but holds an average WEEKLY " + "figure, populated via test fixtures or reform." + ) unit = USD definition_period = YEAR default_value = 0 diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py index 81f97077e02..aec03181519 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py @@ -20,6 +20,8 @@ class ok_ui_high_quarter_taxable_wages(Variable): default_value = 0 defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", + # 40 O.S. §1-201(48) — per-calendar-year taxable-wage cap + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=23", + # 40 O.S. §2-104(A) — weekly benefit amount input "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_total_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_total_wages.py new file mode 100644 index 00000000000..035488db66c --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_total_wages.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class ok_ui_high_quarter_total_wages(Variable): + """Total (uncapped) gross wages paid in the claimant's highest base-period + quarter, per 40 O.S. § 2-207(A)(2), which applies the 1.5x multiplier to + the claimant's total high-quarter wages rather than the taxable-capped + figure. PolicyEngine cannot derive quarterly wages from annual data, so + this is a direct input rather than a computed value; populate via test + fixtures or reform. Defaults to zero, so it is inert in microsimulation + until supplied. + """ + + value_type = float + entity = Person + label = "Oklahoma UI high quarter total wages" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + # 40 O.S. §2-207(A)(2) — total high-quarter wages used in the 1.5x test + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py index a859890e1fc..4b6a6ca45bc 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py @@ -9,8 +9,7 @@ class ok_ui_maximum_benefit_amount(Variable): definition_period = YEAR defined_for = StateCode.OK reference = ( - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=48", - "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=52", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py index ec315b5e1ec..bab4e2aeff8 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py @@ -4,13 +4,10 @@ class ok_ui_meets_high_quarter_test(Variable): """Oklahoma UI high-quarter monetary eligibility test (§ 2-207(A)). - Note: § 2-207(A)(2) applies the 1.5x multiplier to the claimant's - unqualified (total) wages. This implementation uses taxable high-quarter - wages as a proxy for the high-quarter figure driving the test. The - deviation matters only for high-quarter earners whose wages are capped at - the taxable wage base; in the cases PolicyEngine models, the alternate - wages test (Test B) rescues final eligibility, so the proxy does not - change the modeled monetary-eligibility outcome. + Prong 1 (§ 2-207(A)(1)) requires base-period taxable wages of at least the + statutory minimum. Prong 2 (§ 2-207(A)(2)) requires total base-period + wages of at least 1.5x the claimant's total high-quarter wages; the statute + uses total (uncapped) wages, not the taxable-capped figure. """ value_type = bool @@ -26,9 +23,9 @@ def formula(person, period, parameters): p = parameters(period).gov.states.ok.oesc.unemployment_insurance.eligibility base_period_taxable_wages = person("ok_ui_base_period_taxable_wages", period) base_period_total_wages = person("ok_ui_base_period_total_wages", period) - high_quarter_taxable_wages = person("ok_ui_high_quarter_taxable_wages", period) + high_quarter_total_wages = person("ok_ui_high_quarter_total_wages", period) meets_taxable_minimum = base_period_taxable_wages >= p.min_taxable_wages meets_multiplier = base_period_total_wages >= ( - p.min_total_wages_multiplier * high_quarter_taxable_wages + p.min_total_wages_multiplier * high_quarter_total_wages ) return meets_taxable_minimum & meets_multiplier diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py index 9aea9b7001b..f15b4cbdb48 100644 --- a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py @@ -9,7 +9,10 @@ class ok_ui_weekly_benefit_rate(Variable): definition_period = YEAR defined_for = StateCode.OK reference = ( + # 40 O.S. §2-104 — weekly benefit amount "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", + # 40 O.S. §2-102 — rounding down to the next lower whole dollar + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49", ) def formula(person, period, parameters):