From 4aab5c5e0cad9eac05aff24237f175cd9ad64786 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 13 May 2026 13:27:28 -0400 Subject: [PATCH 1/6] Implement Utah Unemployment Insurance (ut_ui) (ref #8280) --- .../benefit/duration/max_weeks.yaml | 12 + .../benefit/duration/min_weeks.yaml | 12 + .../benefit/duration/multiplier.yaml | 12 + .../partial/earnings_disregard_rate.yaml | 14 + .../benefit/partial/hours_threshold.yaml | 14 + .../benefit/wba/divisor.yaml | 12 + .../benefit/wba/max_amount.yaml | 16 + .../benefit/wba/subtraction.yaml | 12 + .../base_period_to_high_quarter_ratio.yaml | 14 + .../eligibility/min_base_period_wages.yaml | 14 + .../eligibility/min_quarters_with_wages.yaml | 12 + .../ut/dwf/unemployment_insurance/index.yaml | 4 + policyengine_us/programs.yaml | 11 + .../unemployment_insurance/integration.yaml | 231 ++++++ .../ut_ui_duration_weeks.yaml | 102 +++ .../ut_ui_edge_cases.yaml | 679 ++++++++++++++++++ .../ut_ui_maximum_benefit_amount.yaml | 48 ++ .../ut_ui_monetarily_eligible.yaml | 84 +++ .../ut_ui_weekly_benefit_amount.yaml | 92 +++ .../ut_ui_weekly_payable_amount.yaml | 130 ++++ .../ut/dwf/unemployment_insurance/ut_ui.py | 28 + .../ut_ui_base_period_wages.py | 18 + .../ut_ui_duration_weeks.py | 31 + .../ut_ui_gross_weekly_earnings.py | 17 + .../ut_ui_high_quarter_wages.py | 14 + .../ut_ui_maximum_benefit_amount.py | 18 + .../ut_ui_monetarily_eligible.py | 32 + .../ut_ui_quarters_with_wages.py | 15 + .../ut_ui_weekly_benefit_amount.py | 27 + .../ut_ui_weekly_hours_worked.py | 15 + .../ut_ui_weekly_payable_amount.py | 35 + .../ut_ui_weeks_unemployed.py | 15 + 32 files changed, 1790 insertions(+) create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/max_weeks.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/min_weeks.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/multiplier.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/divisor.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/max_amount.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/subtraction.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml create mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/index.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_base_period_wages.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_gross_weekly_earnings.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_high_quarter_wages.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_quarters_with_wages.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py create mode 100644 policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weeks_unemployed.py diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/max_weeks.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/max_weeks.yaml new file mode 100644 index 00000000000..36c38194051 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/max_weeks.yaml @@ -0,0 +1,12 @@ +description: Utah limits the potential benefit duration to this threshold under the Unemployment Insurance program. + +values: + 2024-01-01: 26 + +metadata: + unit: week + period: year + label: Utah UI maximum potential duration + reference: + - title: Utah Code § 35A-4-401(4)(b) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/min_weeks.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/min_weeks.yaml new file mode 100644 index 00000000000..6df01045be6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/min_weeks.yaml @@ -0,0 +1,12 @@ +description: Utah sets the minimum potential benefit duration to this threshold under the Unemployment Insurance program. + +values: + 2024-01-01: 10 + +metadata: + unit: week + period: year + label: Utah UI minimum potential duration + reference: + - title: Utah Code § 35A-4-401(4)(b) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/multiplier.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/multiplier.yaml new file mode 100644 index 00000000000..aebc8bb45eb --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/multiplier.yaml @@ -0,0 +1,12 @@ +description: Utah uses this multiplier on total base-period wages when computing the potential benefit duration under the Unemployment Insurance program. + +values: + 2024-01-01: 0.27 + +metadata: + unit: /1 + period: year + label: Utah UI duration wage multiplier + reference: + - title: Utah Code § 35A-4-401(4)(b) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml new file mode 100644 index 00000000000..b0445256b2f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml @@ -0,0 +1,14 @@ +description: Utah excludes this share of the weekly benefit amount from countable earnings during partial unemployment under the Unemployment Insurance program. + +values: + 2024-01-01: 0.3 + +metadata: + unit: /1 + period: year + label: Utah UI partial benefit earnings disregard rate + reference: + - title: Utah Code § 35A-4-401(3)(a) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html + - title: Utah Admin Code R994-401-301 + href: https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-301 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml new file mode 100644 index 00000000000..fd0c77a37a1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml @@ -0,0 +1,14 @@ +description: Utah limits weekly hours worked to less than this threshold for benefit eligibility under the Unemployment Insurance program. + +values: + 2024-01-01: 40 + +metadata: + unit: hour + period: week + label: Utah UI weekly hours threshold + reference: + - title: Utah Code § 35A-4-207 + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S207.html + - title: Utah DWS Claimant Guide (Jan 2025) + href: https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=11 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/divisor.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/divisor.yaml new file mode 100644 index 00000000000..e5b8d64bb94 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/divisor.yaml @@ -0,0 +1,12 @@ +description: Utah uses this divisor on high-quarter wages when computing the weekly benefit amount under the Unemployment Insurance program. + +values: + 2024-01-01: 26 + +metadata: + unit: /1 + period: year + label: Utah UI weekly benefit amount divisor + reference: + - title: Utah Code § 35A-4-401(2)(a)(ii) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/max_amount.yaml new file mode 100644 index 00000000000..520397469b9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/max_amount.yaml @@ -0,0 +1,16 @@ +description: Utah limits the weekly benefit amount to this amount under the Unemployment Insurance program. + +values: + 2024-01-01: 712 + 2025-01-01: 777 + 2026-01-01: 806 + +metadata: + unit: currency-USD + period: week + label: Utah UI maximum weekly benefit amount + reference: + - title: Utah Code § 35A-4-401(2)(b)(ii) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html + - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0126) + href: https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/subtraction.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/subtraction.yaml new file mode 100644 index 00000000000..2a318ca8fce --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/subtraction.yaml @@ -0,0 +1,12 @@ +description: Utah deducts this amount from the high-quarter-derived weekly benefit amount under the Unemployment Insurance program. + +values: + 2024-01-01: 5 + +metadata: + unit: currency-USD + period: year + label: Utah UI weekly benefit amount subtraction + reference: + - title: Utah Code § 35A-4-401(2)(a)(ii) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml new file mode 100644 index 00000000000..95ada15a217 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml @@ -0,0 +1,14 @@ +description: Utah requires total base-period wages to be at least this multiple of high-quarter wages under the Unemployment Insurance program. + +values: + 2024-01-01: 1.5 + +metadata: + unit: /1 + period: year + label: Utah UI base period to high quarter wage ratio + reference: + - title: Utah Code § 35A-4-403(1)(f)(i) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html + - title: Utah Admin Code R994-401-202 + href: https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml new file mode 100644 index 00000000000..4b49be7cc88 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml @@ -0,0 +1,14 @@ +description: Utah limits monetary eligibility to claimants with total base-period wages of at least this amount under the Unemployment Insurance program. + +values: + 2024-01-01: 5_500 + +metadata: + unit: currency-USD + period: year + label: Utah UI minimum base-period wages + reference: + - title: Utah Code § 35A-4-201(16) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html + - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0126) + href: https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml new file mode 100644 index 00000000000..c1d7155625b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml @@ -0,0 +1,12 @@ +description: Utah sets the minimum number of base-period quarters with wages to this threshold under the Unemployment Insurance program. + +values: + 2024-01-01: 2 + +metadata: + unit: int + period: year + label: Utah UI minimum quarters with wages + reference: + - title: Utah Admin Code R994-401-202 + href: https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/index.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/index.yaml new file mode 100644 index 00000000000..cb39cde8a79 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/index.yaml @@ -0,0 +1,4 @@ +metadata: + propagate_metadata_to_children: true + economy: false + household: true diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 88e0008d86b..5225fe29b7d 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: ut_ui + name: Utah UI + full_name: Utah Unemployment Insurance + category: Benefits + agency: State + status: complete + coverage: UT + verified_years: "2024-2026" + variable: ut_ui + parameter_prefix: gov.states.ut.dwf.unemployment_insurance + - id: tx_fpp_benefit name: Texas FPP full_name: Texas Family Planning Program diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml new file mode 100644 index 00000000000..1155584fd23 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml @@ -0,0 +1,231 @@ +# Integration tests for Utah Unemployment Insurance (UT UI). +# End-to-end scenarios that exercise the headline ut_ui variable together +# with the intermediate WBA, duration, MBA, and weekly-payable variables. +# References: +# - Utah Code § 35A-4-401 (https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html) +# - Utah Code § 35A-4-403 (https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html) +# - Utah Admin Code R994-401-301 (partial benefits) +# - Utah DWS 2026 Benefit Schedule (Form 04-13-0126), Claimant Guide (Jan 2025) + +- name: Case 1, no base-period wages yields zero benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 0 + ut_ui_high_quarter_wages: 0 + ut_ui_quarters_with_wages: 0 + ut_ui_weeks_unemployed: 0 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # All inputs zero -> fails $5,500 minimum -> not monetarily eligible. + ut_ui_monetarily_eligible: false + ut_ui_weekly_benefit_amount: 0 + ut_ui_duration_weeks: 0 + ut_ui_maximum_benefit_amount: 0 + ut_ui_weekly_payable_amount: 0 + ut_ui: 0 + +- name: Case 2, full-year unemployment yields max benefit in 2024. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 80_000 + ut_ui_high_quarter_wages: 25_000 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 26 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $80,000 >= 1.5 * $25,000 = $37,500. + ut_ui_monetarily_eligible: true + # Raw WBA = floor($25,000 / 26) - $5 = $961 - $5 = $956. + # 2024 cap = $712, so WBA = $712. + ut_ui_weekly_benefit_amount: 712 + # Raw duration = floor(floor(0.27 * $80,000) / $712) + # = floor($21,600 / $712) = floor(30.34) = 30, clamp 26. + ut_ui_duration_weeks: 26 + # MBA = $712 * 26 = $18,512. + ut_ui_maximum_benefit_amount: 18_512 + # Weekly payable = WBA when no earnings/hours. + ut_ui_weekly_payable_amount: 712 + # Annual = $712 * 26 = $18,512; MBA cap = $18,512. + ut_ui: 18_512 + +- name: Case 3, full-year unemployment hits 2026 max WBA cap. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 80_000 + ut_ui_high_quarter_wages: 25_000 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 26 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible. + ut_ui_monetarily_eligible: true + # Raw WBA = floor($25,000 / 26) - $5 = $956. + # 2026 cap = $806, so WBA = $806. + ut_ui_weekly_benefit_amount: 806 + # Raw duration = floor(floor(0.27 * $80,000) / $806) + # = floor($21,600 / $806) = floor(26.80) = 26. + # At max -> 26 weeks. + ut_ui_duration_weeks: 26 + # MBA = $806 * 26 = $20,956 (matches 2026 published max MBA). + ut_ui_maximum_benefit_amount: 20_956 + ut_ui_weekly_payable_amount: 806 + # Annual = $806 * 26 = $20,956. + ut_ui: 20_956 + +- name: Case 4, minimum-eligibility base wages produce 10-week duration. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ut_ui_base_period_wages: 15_600 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 10 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible at the 1.5x boundary: + # $15,600 >= $5,500 minimum. + # $15,600 = 1.5 * $10,400. + ut_ui_monetarily_eligible: true + # WBA = floor($10,400 / 26) - $5 = $400 - $5 = $395. + ut_ui_weekly_benefit_amount: 395 + # Raw duration = floor(floor(0.27 * $15,600) / $395) + # = floor($4,212 / $395) = floor(10.66) = 10. + # At the 10-week floor. + ut_ui_duration_weeks: 10 + # MBA = $395 * 10 = $3,950. + ut_ui_maximum_benefit_amount: 3_950 + ut_ui_weekly_payable_amount: 395 + # Annual = $395 * 10 = $3,950. + ut_ui: 3_950 + +- name: Case 5, partial-week earnings reduce the weekly payable amount. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 15 + ut_ui_gross_weekly_earnings: 200 + ut_ui_weekly_hours_worked: 20 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $25,000 >= 1.5 * $10,400 = $15,600. + ut_ui_monetarily_eligible: true + # WBA = $395. + ut_ui_weekly_benefit_amount: 395 + # Duration = floor(floor(0.27 * $25,000) / $395) = floor(17.09) = 17. + ut_ui_duration_weeks: 17 + # MBA = $395 * 17 = $6,715. + ut_ui_maximum_benefit_amount: 6_715 + # 30% disregard = $118.50; excess = $200 - $118.50 = $81.50. + # Weekly payable = floor($395 - $81.50) = floor($313.50) = $313. + ut_ui_weekly_payable_amount: 313 + # Annual = $313 * 15 = $4,695; well below MBA cap. + ut_ui: 4_695 + +- name: Case 6, weekly hours of 40 or more produce zero benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 20 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 40 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible. + ut_ui_monetarily_eligible: true + # WBA = $395; duration = 17; MBA = $6,715. + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 17 + ut_ui_maximum_benefit_amount: 6_715 + # Hours 40 >= 40-hour threshold -> disqualified -> weekly payable = $0. + ut_ui_weekly_payable_amount: 0 + # Annual = $0 * 20 = $0. + ut_ui: 0 + +- name: Case 7, out-of-state household (Texas) yields zero Utah UI benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 26 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: TX + output: + people: + person1: + # ut_ui has defined_for = StateCode.UT -> zero for non-UT households, + # regardless of monetary inputs. + ut_ui: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml new file mode 100644 index 00000000000..76a170ac34e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml @@ -0,0 +1,102 @@ +# Tests for Utah UI potential duration in weeks. +# Formula (§ 35A-4-401(4)(b)): +# raw_weeks = floor(floor(0.27 * base_period_wages) / WBA) +# duration_weeks = clip(raw_weeks, 10, 26) +# Duration is 0 when WBA = 0 (e.g., not monetarily eligible). + +- name: Case 1, high base wages clamped to 26-week maximum. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 50_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $50,000 >= 1.5 * $10,400 = $15,600. + # WBA = floor($10,400 / 26) - $5 = $400 - $5 = $395. + # Raw weeks = floor(floor(0.27 * $50,000) / $395) + # = floor($13,500 / $395) = floor(34.18) = 34. + # Clamp to max 26 weeks. + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 26 + +- name: Case 2, minimum-eligibility base wages produce 10-week floor. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 15_600 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible at the 1.5x boundary: $15,600 = 1.5 * $10,400. + # WBA = $395. + # Raw weeks = floor(floor(0.27 * $15,600) / $395) + # = floor($4,212 / $395) = floor(10.66) = 10. + # At the 10-week floor. + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 10 + +- name: Case 3, mid-range base wages produce 17-week duration. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $25,000 >= 1.5 * $10,400 = $15,600. + # WBA = $395. + # Raw weeks = floor(floor(0.27 * $25,000) / $395) + # = floor($6,750 / $395) = floor(17.09) = 17. + # Between 10 and 26 -> no clamping. + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 17 + +- name: Case 4, WBA equals zero yields zero duration. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_000 + ut_ui_high_quarter_wages: 2_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # $5,000 < $5,500 minimum -> not monetarily eligible -> WBA = 0. + # Duration = 0 (bypasses 10-week floor when WBA = 0). + ut_ui_weekly_benefit_amount: 0 + ut_ui_duration_weeks: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml new file mode 100644 index 00000000000..cc1bc0d951f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml @@ -0,0 +1,679 @@ +# Edge case tests for Utah Unemployment Insurance (UT UI). +# +# Covers boundary conditions for the three monetary eligibility tests, +# the WBA formula and cap, the duration clamp, partial-benefit +# disregard/hour rules, annual MBA cap, and the StateCode.UT gate. +# +# References: +# - Utah Code § 35A-4-201(16) (minimum base-period wages) +# https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html +# - Utah Code § 35A-4-401 (WBA, duration, MBA, partial benefit) +# https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html +# - Utah Code § 35A-4-403(1)(f)(i) (1.5x ratio test) +# https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html +# - Utah Admin Code R994-401-202 (quarters test) +# https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202 +# - Utah Admin Code R994-401-301 (partial benefit) +# https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-301 +# +# --------------------------------------------------------------------------- +# THRESHOLD BOUNDARIES — minimum base-period wages ($5,500) +# --------------------------------------------------------------------------- + +- name: Case 1, base wages one dollar below $5,500 floor fails minimum test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_499 + ut_ui_high_quarter_wages: 3_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,499 < $5,500 minimum -> fails. + # (Tests 2 and 3 would pass: 4 quarters >= 2; 5499 >= 1.5*3000=4500.) + ut_ui_monetarily_eligible: false + +- name: Case 2, base wages exactly at $5,500 floor pass the minimum test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_500 + ut_ui_high_quarter_wages: 3_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,500 >= $5,500 minimum (>=, not strict). + # Test 2: 4 quarters >= 2. + # Test 3: $5,500 >= 1.5*$3,000 = $4,500. + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true + +- name: Case 3, base wages one dollar above $5,500 floor pass the minimum test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_501 + ut_ui_high_quarter_wages: 3_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,501 >= $5,500 minimum. + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true + +# --------------------------------------------------------------------------- +# THRESHOLD BOUNDARIES — 1.5x high-quarter ratio +# --------------------------------------------------------------------------- + +- name: Case 4, base wages exactly 1.5 times high quarter pass the ratio test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 15_000 + ut_ui_high_quarter_wages: 10_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $15,000 >= $5,500 minimum. + # Test 2: 4 quarters >= 2. + # Test 3: $15,000 = 1.5 * $10,000 exactly (>=, not strict). + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true + +- name: Case 5, base wages one cent below 1.5x high quarter fails the ratio test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 14_999.99 + ut_ui_high_quarter_wages: 10_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 3: $14,999.99 < 1.5 * $10,000 = $15,000.00 -> fails. + ut_ui_monetarily_eligible: false + +# --------------------------------------------------------------------------- +# THRESHOLD BOUNDARIES — quarters with wages +# --------------------------------------------------------------------------- + +- name: Case 6, only one quarter of wages fails the quarter-count test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 15_000 + ut_ui_high_quarter_wages: 10_000 + ut_ui_quarters_with_wages: 1 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 2: 1 quarter < 2 required -> fails. + ut_ui_monetarily_eligible: false + +- name: Case 7, exactly two quarters of wages pass the quarter-count test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 15_000 + ut_ui_high_quarter_wages: 10_000 + ut_ui_quarters_with_wages: 2 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 2: 2 quarters >= 2 required (>=, not strict). + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true + +# --------------------------------------------------------------------------- +# WBA EDGE CASES — zero, negative-protected, and at-max boundaries +# --------------------------------------------------------------------------- + +- name: Case 8, zero high-quarter wages with monetary failure yields zero WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 0 + ut_ui_high_quarter_wages: 0 + ut_ui_quarters_with_wages: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Raw WBA = floor(0/26) - 5 = -5 -> max_(.,0) = 0 (no negative WBA). + # Also not monetarily eligible, so WBA forced to 0. + ut_ui_monetarily_eligible: false + ut_ui_weekly_benefit_amount: 0 + +- name: Case 9, very low high quarter with floor(HQ/26)<5 still yields zero WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_500 + ut_ui_high_quarter_wages: 100 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $5,500 >= $5,500 min; 4 quarters >= 2; + # $5,500 >= 1.5*$100 = $150. + ut_ui_monetarily_eligible: true + # Raw WBA = floor(100/26) - 5 = 3 - 5 = -2 -> max_(.,0) = 0. + # Tests negative-protection: WBA must never be negative. + ut_ui_weekly_benefit_amount: 0 + +- name: Case 10, high quarter at exact lower boundary of 2024 WBA cap. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 50_000 + ut_ui_high_quarter_wages: 18_642 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $50,000 >= 1.5 * $18,642 = $27,963. + # Raw WBA = floor(18,642/26) - 5 = floor(717.0) - 5 = 717 - 5 = $712. + # 2024 cap = $712 -> WBA exactly hits the cap with no clipping. + ut_ui_weekly_benefit_amount: 712 + +- name: Case 11, high quarter just above 2024 cap threshold is capped to 712. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 50_000 + ut_ui_high_quarter_wages: 18_668 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Raw WBA = floor(18,668/26) - 5 = floor(718.0) - 5 = 718 - 5 = $713. + # 2024 cap = $712 -> capped down to $712. + ut_ui_weekly_benefit_amount: 712 + +- name: Case 12, high quarter at exact lower boundary of 2025 WBA cap. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 50_000 + ut_ui_high_quarter_wages: 20_332 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $50,000 >= 1.5 * $20,332 = $30,498. + # Raw WBA = floor(20,332/26) - 5 = floor(782.0) - 5 = 782 - 5 = $777. + # 2025 cap = $777 -> WBA exactly hits the cap with no clipping. + ut_ui_weekly_benefit_amount: 777 + +- name: Case 13, high quarter at exact lower boundary of 2026 WBA cap. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 50_000 + ut_ui_high_quarter_wages: 21_086 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $50,000 >= 1.5 * $21,086 = $31,629. + # Raw WBA = floor(21,086/26) - 5 = floor(811.0) - 5 = 811 - 5 = $806. + # 2026 cap = $806 -> WBA exactly hits the cap with no clipping. + ut_ui_weekly_benefit_amount: 806 + +# --------------------------------------------------------------------------- +# DURATION EDGE CASES — clamps and divide-by-zero guard +# --------------------------------------------------------------------------- + +- name: Case 14, zero WBA yields zero duration (divide-by-zero guard). + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_500 + ut_ui_high_quarter_wages: 100 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = 0 (see Case 9). Duration formula short-circuits to 0 + # rather than dividing by zero or returning the 10-week floor. + ut_ui_weekly_benefit_amount: 0 + ut_ui_duration_weeks: 0 + +- name: Case 15, base wages exactly at 1.5x ratio produce 10-week minimum duration. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ut_ui_base_period_wages: 15_600 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible at the 1.5x boundary: $15,600 = 1.5 * $10,400. + # WBA = floor($10,400/26) - 5 = $400 - $5 = $395. + # Raw weeks = floor(floor(0.27 * $15,600) / $395) + # = floor($4,212 / $395) = floor(10.66) = 10. + # At the 10-week floor (in practice, the 1.5x monetary boundary + # forces raw_weeks asymptotically toward 10; the floor clamp is a + # safety guarantee even though it rarely binds). + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 10 + +- name: Case 16, ratio of base*0.27/WBA at exactly 26 yields 26-week duration. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 9_630 + ut_ui_high_quarter_wages: 2_730 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $9,630 >= $5,500 min; 4 quarters >= 2; + # $9,630 >= 1.5 * $2,730 = $4,095. + # WBA = floor($2,730/26) - 5 = $105 - $5 = $100. + # Step 1: floor(0.27 * $9,630) = floor($2,600.10) = $2,600. + # Step 2: $2,600 / $100 = 26.0 -> floor = 26. + # Exactly at the 26-week cap with no clamping. + ut_ui_weekly_benefit_amount: 100 + ut_ui_duration_weeks: 26 + +- name: Case 17, ratio of base*0.27/WBA at 26.5 floors to 26-week duration. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 9_815 + ut_ui_high_quarter_wages: 2_730 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $100 (same HQ as Case 16). + # Step 1: floor(0.27 * $9,815) = floor($2,650.05) = $2,650. + # Step 2: $2,650 / $100 = 26.5 -> floor = 26. + # Hit the 26-week cap through clamping. + ut_ui_weekly_benefit_amount: 100 + ut_ui_duration_weeks: 26 + +# --------------------------------------------------------------------------- +# PARTIAL BENEFIT EDGE CASES — 30% disregard, WBA floor, 40-hour rule +# --------------------------------------------------------------------------- + +- name: Case 18, earnings exactly at WBA disqualify the week. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 395 + ut_ui_weekly_hours_worked: 20 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395 (HQ $10,400). Earnings $395 >= WBA $395 -> disqualified. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 0 + +- name: Case 19, earnings just below the 30% disregard preserve full WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 118 + ut_ui_weekly_hours_worked: 10 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395. Disregard = 0.30 * $395 = $118.50. + # Earnings = $118 (just below $118.50 disregard). + # Excess = max(0, $118 - $118.50) = max(0, -$0.50) = $0. + # Payable = floor(max(0, $395 - $0)) = $395. + # NB: testing exactly $118.50 is avoided due to IEEE-754 imprecision + # in 0.30 * WBA, which would yield a sub-cent positive excess and + # floor the result to $394. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 395 + +- name: Case 20, earnings just above 30% disregard yield a small reduction. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 120 + ut_ui_weekly_hours_worked: 10 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395. Disregard = $118.50. + # Excess = $120 - $118.50 = $1.50. + # Payable = floor(max(0, $395 - $1.50)) = floor($393.50) = $393. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 393 + +- name: Case 21, weekly hours of 39 do not trigger the 40-hour disqualification. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 39 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395. 39 hours < 40-hour threshold -> not disqualified. + # Earnings $0 < disregard $118.50 -> excess $0 -> payable = $395. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 395 + +- name: Case 22, weekly hours exactly at 40 trigger the disqualification. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 40 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395. 40 hours >= 40-hour threshold (>=, not strict) -> + # disqualified -> weekly payable = $0. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 0 + +- name: Case 23, weekly hours of 41 trigger the disqualification. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 41 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # 41 hours > 40-hour threshold -> disqualified -> payable = $0. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 0 + +- name: Case 24, negative weekly earnings (data error) do not inflate payable above WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: -100 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395. Disregard = $118.50. + # Excess = max(0, -$100 - $118.50) = max(0, -$218.50) = $0. + # Payable = floor(max(0, $395 - $0)) = $395. + # Critical: negative earnings cannot push payable above WBA via the + # max_() clamps on both the excess and the final payable. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 395 + +# --------------------------------------------------------------------------- +# ANNUAL BENEFIT (MBA cap) EDGE CASES +# --------------------------------------------------------------------------- + +- name: Case 25, zero weeks unemployed produce zero annual benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 0 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395; duration = 17; MBA = $6,715; payable = $395. + # Annual = min($395 * 0, $6,715) = min($0, $6,715) = $0. + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 17 + ut_ui_maximum_benefit_amount: 6_715 + ut_ui_weekly_payable_amount: 395 + ut_ui: 0 + +- name: Case 26, weeks unemployed exceeding duration weeks cap at MBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 26 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395; duration = 17; MBA = $395 * 17 = $6,715. + # Uncapped annual = $395 * 26 = $10,270. + # min($10,270, $6,715) = $6,715 -> capped at MBA. + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 17 + ut_ui_maximum_benefit_amount: 6_715 + ut_ui_weekly_payable_amount: 395 + ut_ui: 6_715 + +# --------------------------------------------------------------------------- +# STATE GATE — defined_for = StateCode.UT +# --------------------------------------------------------------------------- + +- name: Case 27, out-of-state household (California) yields zero Utah UI benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 80_000 + ut_ui_high_quarter_wages: 25_000 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 26 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: CA + output: + people: + person1: + # ut_ui has defined_for = StateCode.UT -> zero for non-UT households, + # regardless of all monetary and benefit inputs. + ut_ui: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml new file mode 100644 index 00000000000..84440f7bf9d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml @@ -0,0 +1,48 @@ +# Tests for Utah UI maximum benefit amount. +# Formula (§ 35A-4-401(4)(a)): MBA = WBA * duration_weeks. + +- name: Case 1, standard MBA equals WBA times duration weeks. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395; duration = 17 weeks (see ut_ui_duration_weeks Case 3). + # MBA = $395 * 17 = $6,715. + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 17 + ut_ui_maximum_benefit_amount: 6_715 + +- name: Case 2, MBA equals zero when WBA equals zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_000 + ut_ui_high_quarter_wages: 2_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Not monetarily eligible -> WBA = 0 -> duration = 0. + # MBA = 0 * 0 = $0. + ut_ui_weekly_benefit_amount: 0 + ut_ui_duration_weeks: 0 + ut_ui_maximum_benefit_amount: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml new file mode 100644 index 00000000000..d7f96a6dde7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml @@ -0,0 +1,84 @@ +# Tests for Utah UI monetary eligibility. +# A claimant is monetarily eligible only if ALL THREE base-period tests pass: +# 1. Total base-period wages >= $5,500 (Utah Code § 35A-4-201(16)). +# 2. Wages paid in at least 2 calendar quarters (Utah Admin Code R994-401-202). +# 3. Total base-period wages >= 1.5 x high-quarter wages (§ 35A-4-403(1)(f)(i)). + +- name: Case 1, all three monetary tests pass. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 8_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $25,000 >= $5,500 minimum. + # Test 2: 4 quarters >= 2 required. + # Test 3: $25,000 >= 1.5 * $8,000 = $12,000. + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true + +- name: Case 2, base wages below $5,500 floor fails minimum-wage test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_000 + ut_ui_high_quarter_wages: 2_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,000 < $5,500 minimum -> fails. + ut_ui_monetarily_eligible: false + +- name: Case 3, only one quarter of wages fails quarter-count test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 8_000 + ut_ui_quarters_with_wages: 1 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 2: only 1 quarter with wages < 2 required -> fails. + ut_ui_monetarily_eligible: false + +- name: Case 4, base wages 1.4x high quarter fails ratio test. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 14_000 + ut_ui_high_quarter_wages: 10_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 3: $14,000 < 1.5 * $10,000 = $15,000 -> fails. + ut_ui_monetarily_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml new file mode 100644 index 00000000000..a8c64da619b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml @@ -0,0 +1,92 @@ +# Tests for Utah UI weekly benefit amount. +# Formula: WBA = floor(high_quarter_wages / 26) - $5 (§ 35A-4-401(2)(a)(ii)). +# Then capped at the annual max WBA (§ 35A-4-401(2)(b)(ii)): +# 2024: $712; 2025: $777; 2026: $806. +# WBA = 0 when claimant is not monetarily eligible. + +- name: Case 1, standard WBA from $10,000 high quarter. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $25,000 >= $5,500 and >= 1.5 * $10,000 = $15,000. + # WBA = floor($10,000 / 26) - $5 = $384 - $5 = $379. + # $379 below 2025 cap of $777, so no cap applies. + ut_ui_weekly_benefit_amount: 379 + +- name: Case 2, WBA capped at 2024 max of $712. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 50_000 + ut_ui_high_quarter_wages: 20_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $50,000 >= 1.5 * $20,000 = $30,000. + # Raw WBA = floor($20,000 / 26) - $5 = $769 - $5 = $764. + # 2024 cap = $712, so WBA = $712. + ut_ui_weekly_benefit_amount: 712 + +- name: Case 3, WBA capped at 2026 max of $806. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 80_000 + ut_ui_high_quarter_wages: 25_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $80,000 >= 1.5 * $25,000 = $37,500. + # Raw WBA = floor($25,000 / 26) - $5 = $961 - $5 = $956. + # 2026 cap = $806, so WBA = $806. + ut_ui_weekly_benefit_amount: 806 + +- name: Case 4, monetarily ineligible yields zero WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_000 + ut_ui_high_quarter_wages: 2_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # $5,000 < $5,500 minimum -> not monetarily eligible. + # WBA = 0 regardless of high-quarter calculation. + ut_ui_weekly_benefit_amount: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml new file mode 100644 index 00000000000..1b31816b6af --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml @@ -0,0 +1,130 @@ +# Tests for Utah UI weekly payable amount. +# Combines weekly benefit amount with the partial-benefit rules: +# - 30% earnings disregard: first 0.30 * WBA of weekly earnings is disregarded +# (Utah Code § 35A-4-401(3)(a); Utah Admin Code R994-401-301). +# - Excess earnings (above 0.30 * WBA) reduce WBA dollar-for-dollar. +# - Earnings >= WBA disqualify the week (Claimant Guide p. 11). +# - Weekly hours >= 40 disqualify the week (Claimant Guide p. 11; § 35A-4-207). +# Result is floored to a whole dollar per § 35A-4-401(3)(b). +# +# All cases below use WBA = $395 (HQ = $10,400, base = $25,000, 4 quarters). +# 30% disregard = 0.30 * $395 = $118.50. + +- name: Case 1, zero earnings yields full WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Earnings $0 < disregard $118.50 -> excess = 0. + # Payable = floor($395 - $0) = $395. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 395 + +- name: Case 2, earnings below 30% disregard yield full WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 100 + ut_ui_weekly_hours_worked: 20 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Earnings $100 < disregard $118.50 -> excess = 0. + # Payable = floor($395 - $0) = $395. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 395 + +- name: Case 3, earnings above disregard but below WBA produce partial reduction. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 200 + ut_ui_weekly_hours_worked: 20 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Earnings $200 > disregard $118.50. + # Excess = $200 - $118.50 = $81.50. + # Raw payable = floor($395 - $81.50) = floor($313.50) = $313. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 313 + +- name: Case 4, earnings at or above WBA disqualify the week. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 400 + ut_ui_weekly_hours_worked: 20 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Earnings $400 >= WBA $395 -> disqualified. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 0 + +- name: Case 5, weekly hours of 40 or more disqualify the week. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 40 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Earnings $0 < WBA, BUT hours 40 >= 40-hour threshold -> disqualified. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 0 diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui.py new file mode 100644 index 00000000000..a2442042b31 --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class ut_ui(Variable): + value_type = float + entity = Person + label = "Utah Unemployment Insurance" + unit = USD + definition_period = YEAR + reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html" + defined_for = StateCode.UT + # Annual Utah Unemployment Insurance benefit. Computed as the weekly + # payable amount times weeks unemployed, capped at the maximum benefit + # amount (WBA x duration) per Utah Code § 35A-4-401(4)(a). + # + # Not modeled (future work): + # - REQ-023: 100% retirement income offset for pensions maintained or + # contributed to by a base-period employer (Utah Code + # § 35A-4-401(2)(c)(i)-(iii); Utah Admin Code R994-401-203). Modeling + # requires base-period-employer attribution that is not available in + # the underlying microdata. + + def formula(person, period, parameters): + weekly_payable_amount = person("ut_ui_weekly_payable_amount", period) + weeks_unemployed = person("ut_ui_weeks_unemployed", period) + maximum_benefit_amount = person("ut_ui_maximum_benefit_amount", period) + annual_benefit = weekly_payable_amount * weeks_unemployed + return min_(annual_benefit, maximum_benefit_amount) diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_base_period_wages.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_base_period_wages.py new file mode 100644 index 00000000000..c3d46b3ca87 --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_base_period_wages.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ut_ui_base_period_wages(Variable): + value_type = float + entity = Person + label = "Utah UI base period wages" + unit = USD + definition_period = YEAR + default_value = 0 + reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html" + # Per Utah Code § 35A-4-201(1)(a), the base period is the first four of the + # last five completed calendar quarters preceding the first day of the + # benefit year. Per § 35A-4-201(1)(b), claims effective on or after + # 2011-01-02 may use the alternate base period (last four completed + # quarters) when the standard base period fails monetary eligibility. + # Caller should supply the more favorable of standard or alternate base + # period wages. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.py new file mode 100644 index 00000000000..ff317de6e1b --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class ut_ui_duration_weeks(Variable): + value_type = int + entity = Person + label = "Utah UI potential duration in weeks" + unit = "week" + definition_period = YEAR + reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ut.dwf.unemployment_insurance + base_period_wages = person("ut_ui_base_period_wages", period) + weekly_benefit_amount = person("ut_ui_weekly_benefit_amount", period) + + # § 35A-4-401(4)(b): potential duration = + # floor(floor(0.27 × total base-period wages) / WBA), + # clamped to [min_weeks, max_weeks] (10-26 weeks). + # Guard against divide-by-zero when WBA = 0 (not monetarily eligible + # or WBA capped to zero). + has_wba = weekly_benefit_amount > 0 + numerator = np.floor(p.benefit.duration.multiplier * base_period_wages) + # Use a safe divisor of 1 where WBA is zero; the where() below + # overrides the result with 0 in that case. + safe_wba = where(has_wba, weekly_benefit_amount, 1) + raw_weeks = np.floor(numerator / safe_wba) + clamped_weeks = np.clip( + raw_weeks, p.benefit.duration.min_weeks, p.benefit.duration.max_weeks + ) + return where(has_wba, clamped_weeks, 0) diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_gross_weekly_earnings.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_gross_weekly_earnings.py new file mode 100644 index 00000000000..35707de9fa7 --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_gross_weekly_earnings.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ut_ui_gross_weekly_earnings(Variable): + value_type = float + entity = Person + label = "Utah UI gross weekly earnings while claiming" + unit = USD + definition_period = YEAR + default_value = 0 + reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html" + # Gross weekly earnings during a partial-unemployment week used to apply + # the partial-benefit deduction in Utah Code § 35A-4-401(3)(a). Per + # § 35A-4-401(3)(c), public assistance grants and similar government + # payments are excluded from "wages" for this calculation, so the caller + # is responsible for providing only countable earnings here (excluding + # public assistance benefits). diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_high_quarter_wages.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_high_quarter_wages.py new file mode 100644 index 00000000000..a7795a12a14 --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_high_quarter_wages.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class ut_ui_high_quarter_wages(Variable): + value_type = float + entity = Person + label = "Utah UI high quarter wages" + unit = USD + definition_period = YEAR + default_value = 0 + reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html" + # Wages paid during the calendar quarter of the base period in which the + # claimant's wages were highest, used to compute the weekly benefit amount + # under Utah Code § 35A-4-401(2)(a)(ii). diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.py new file mode 100644 index 00000000000..2e22f2edce8 --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ut_ui_maximum_benefit_amount(Variable): + value_type = float + entity = Person + label = "Utah UI maximum benefit amount" + unit = USD + definition_period = YEAR + reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html" + + def formula(person, period, parameters): + # § 35A-4-401(4)(a): maximum benefit amount equals the weekly benefit + # amount times the potential duration in weeks. Returns zero when the + # claimant is not monetarily eligible (WBA = 0 or duration = 0). + weekly_benefit_amount = person("ut_ui_weekly_benefit_amount", period) + duration_weeks = person("ut_ui_duration_weeks", period) + return weekly_benefit_amount * duration_weeks diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.py new file mode 100644 index 00000000000..348f85967ef --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.py @@ -0,0 +1,32 @@ +from policyengine_us.model_api import * + + +class ut_ui_monetarily_eligible(Variable): + value_type = bool + entity = Person + label = "Monetarily eligible for Utah Unemployment Insurance" + definition_period = YEAR + reference = ( + "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html", + "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html", + "https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ut.dwf.unemployment_insurance + base_period_wages = person("ut_ui_base_period_wages", period) + high_quarter_wages = person("ut_ui_high_quarter_wages", period) + quarters_with_wages = person("ut_ui_quarters_with_wages", period) + + # § 35A-4-201(16): minimum total base-period wages. + meets_minimum_wages = base_period_wages >= p.eligibility.min_base_period_wages + # R994-401-202: wages in at least two base-period quarters. + meets_quarters_test = ( + quarters_with_wages >= p.eligibility.min_quarters_with_wages + ) + # § 35A-4-403(1)(f)(i): total base-period wages must be at least + # 1.5 times high-quarter wages. + meets_ratio_test = base_period_wages >= ( + p.eligibility.base_period_to_high_quarter_ratio * high_quarter_wages + ) + return meets_minimum_wages & meets_quarters_test & meets_ratio_test diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_quarters_with_wages.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_quarters_with_wages.py new file mode 100644 index 00000000000..8060d2f008a --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_quarters_with_wages.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class ut_ui_quarters_with_wages(Variable): + value_type = int + entity = Person + label = "Utah UI base-period quarters with wages" + definition_period = YEAR + default_value = 0 + reference = ( + "https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202" + ) + # Number of base-period calendar quarters (0-4) in which the claimant + # earned wages. Utah Admin Code R994-401-202 requires wages in at least + # two base-period quarters. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.py new file mode 100644 index 00000000000..f3c27c7e30e --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ut_ui_weekly_benefit_amount(Variable): + value_type = float + entity = Person + label = "Utah UI weekly benefit amount" + unit = USD + definition_period = YEAR + reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ut.dwf.unemployment_insurance + high_quarter_wages = person("ut_ui_high_quarter_wages", period) + monetarily_eligible = person("ut_ui_monetarily_eligible", period) + + # § 35A-4-401(2)(a)(ii): WBA = floor(high quarter wages / 26) - $5. + # Utah has no statutory minimum WBA, so the raw amount is floored at + # zero rather than at a positive minimum. + raw_wba = ( + np.floor(high_quarter_wages / p.benefit.wba.divisor) + - p.benefit.wba.subtraction + ) + # § 35A-4-401(2)(b)(ii): WBA is capped at the annual maximum. + capped_wba = min_(max_(raw_wba, 0), p.benefit.wba.max_amount) + # Zero out when the claimant is not monetarily eligible. + return capped_wba * monetarily_eligible diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py new file mode 100644 index 00000000000..bb18ab3d3c0 --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class ut_ui_weekly_hours_worked(Variable): + value_type = float + entity = Person + label = "Utah UI weekly hours worked while claiming" + unit = "hour" + definition_period = YEAR + default_value = 0 + reference = "https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=11" + # Hours worked during a claim week. A claimant who works at least the + # full-time hours threshold (40 hours) in a week is not eligible for + # benefits that week per Utah DWS Claimant Guide page 11 and the + # "total unemployment" definition in Utah Code § 35A-4-207. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py new file mode 100644 index 00000000000..43bad21663c --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py @@ -0,0 +1,35 @@ +from policyengine_us.model_api import * + + +class ut_ui_weekly_payable_amount(Variable): + value_type = float + entity = Person + label = "Utah UI weekly payable amount" + unit = USD + definition_period = YEAR + reference = ( + "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html", + "https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-301", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ut.dwf.unemployment_insurance + weekly_benefit_amount = person("ut_ui_weekly_benefit_amount", period) + gross_weekly_earnings = person("ut_ui_gross_weekly_earnings", period) + weekly_hours_worked = person("ut_ui_weekly_hours_worked", period) + + # § 35A-4-401(3)(a): the first 30% of WBA in weekly earnings is + # disregarded; earnings above that reduce the WBA dollar-for-dollar. + earnings_disregard = ( + p.benefit.partial.earnings_disregard_rate * weekly_benefit_amount + ) + excess_earnings = max_(gross_weekly_earnings - earnings_disregard, 0) + raw_payable = max_(np.floor(weekly_benefit_amount - excess_earnings), 0) + + # § 35A-4-401(3)(a): earnings at or above the WBA disqualify the + # week. Claimant Guide page 11 / § 35A-4-207: working at least the + # full-time hours threshold (40 hours) in a week also disqualifies. + disqualified = (gross_weekly_earnings >= weekly_benefit_amount) | ( + weekly_hours_worked >= p.benefit.partial.hours_threshold + ) + return where(disqualified, 0, raw_payable) diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weeks_unemployed.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weeks_unemployed.py new file mode 100644 index 00000000000..eb463115674 --- /dev/null +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weeks_unemployed.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class ut_ui_weeks_unemployed(Variable): + value_type = int + entity = Person + label = "Utah UI weeks unemployed" + unit = "week" + definition_period = YEAR + default_value = 0 + reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html" + # Number of weeks during the year the claimant collected (or would + # collect) Utah Unemployment Insurance benefits. Used to convert the + # weekly payable amount into an annual benefit, capped by the maximum + # benefit amount per Utah Code § 35A-4-401(4)(a). From f20beeba54267d7fbbb8d2d1a7ff33556fc2e444 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 13 May 2026 13:28:29 -0400 Subject: [PATCH 2/6] Add changelog fragment for Utah UI --- changelog.d/ut-ui.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/ut-ui.added.md diff --git a/changelog.d/ut-ui.added.md b/changelog.d/ut-ui.added.md new file mode 100644 index 00000000000..81645e72ddd --- /dev/null +++ b/changelog.d/ut-ui.added.md @@ -0,0 +1 @@ +Added Utah Unemployment Insurance (UI), including weekly benefit amount, duration, and maximum benefit calculation using the High Quarter Wage formula. From 5fe95b37123e1a3499e24a51cd9fa0f64309056a Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 13 May 2026 13:48:03 -0400 Subject: [PATCH 3/6] Review-fix round 1: address critical issues from /review-program - Split min_base_period_wages into 2024/2025 ($5,300) and 2026 ($5,500) entries - Fix Claimant Guide page references (printed p.11 = file p.13) - Update test boundary cases to match new $5,300 threshold --- .../benefit/partial/hours_threshold.yaml | 2 +- .../eligibility/min_base_period_wages.yaml | 10 ++++++- .../unemployment_insurance/integration.yaml | 4 +-- .../ut_ui_duration_weeks.yaml | 2 +- .../ut_ui_edge_cases.yaml | 30 +++++++++---------- .../ut_ui_monetarily_eligible.yaml | 9 +++--- .../ut_ui_weekly_benefit_amount.yaml | 4 +-- .../ut_ui_weekly_hours_worked.py | 2 +- 8 files changed, 36 insertions(+), 27 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml index fd0c77a37a1..bf2ecec68c8 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml @@ -11,4 +11,4 @@ metadata: - title: Utah Code § 35A-4-207 href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S207.html - title: Utah DWS Claimant Guide (Jan 2025) - href: https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=11 + href: https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=13 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml index 4b49be7cc88..a02be8eae6b 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml @@ -1,7 +1,13 @@ description: Utah limits monetary eligibility to claimants with total base-period wages of at least this amount under the Unemployment Insurance program. +# The floor is recomputed annually per Utah Code § 35A-4-201(16): +# 8% of the insured average fiscal-year wage for the preceding fiscal year, +# rounded up to the next higher multiple of $100. The 2024 entry mirrors the +# adjacent 2025 value because DWS no longer publishes the 2024 schedule PDF. values: - 2024-01-01: 5_500 + 2024-01-01: 5_300 + 2025-01-01: 5_300 + 2026-01-01: 5_500 metadata: unit: currency-USD @@ -10,5 +16,7 @@ metadata: reference: - title: Utah Code § 35A-4-201(16) href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html + - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0125) + href: https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0126) href: https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml index 1155584fd23..7dfa986448c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml @@ -27,7 +27,7 @@ output: people: person1: - # All inputs zero -> fails $5,500 minimum -> not monetarily eligible. + # All inputs zero -> fails $5,300 minimum -> not monetarily eligible. ut_ui_monetarily_eligible: false ut_ui_weekly_benefit_amount: 0 ut_ui_duration_weeks: 0 @@ -126,7 +126,7 @@ people: person1: # Monetarily eligible at the 1.5x boundary: - # $15,600 >= $5,500 minimum. + # $15,600 >= $5,300 minimum. # $15,600 = 1.5 * $10,400. ut_ui_monetarily_eligible: true # WBA = floor($10,400 / 26) - $5 = $400 - $5 = $395. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml index 76a170ac34e..846a6540e8f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml @@ -96,7 +96,7 @@ output: people: person1: - # $5,000 < $5,500 minimum -> not monetarily eligible -> WBA = 0. + # $5,000 < $5,300 minimum -> not monetarily eligible -> WBA = 0. # Duration = 0 (bypasses 10-week floor when WBA = 0). ut_ui_weekly_benefit_amount: 0 ut_ui_duration_weeks: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml index cc1bc0d951f..428cf7fd5f7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml @@ -17,16 +17,16 @@ # https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-301 # # --------------------------------------------------------------------------- -# THRESHOLD BOUNDARIES — minimum base-period wages ($5,500) +# THRESHOLD BOUNDARIES — minimum base-period wages ($5,300 in 2025) # --------------------------------------------------------------------------- -- name: Case 1, base wages one dollar below $5,500 floor fails minimum test. +- name: Case 1, base wages one dollar below $5,300 floor fails minimum test. period: 2025 input: people: person1: age: 35 - ut_ui_base_period_wages: 5_499 + ut_ui_base_period_wages: 5_299 ut_ui_high_quarter_wages: 3_000 ut_ui_quarters_with_wages: 4 households: @@ -36,17 +36,17 @@ output: people: person1: - # Test 1: $5,499 < $5,500 minimum -> fails. - # (Tests 2 and 3 would pass: 4 quarters >= 2; 5499 >= 1.5*3000=4500.) + # Test 1: $5,299 < $5,300 minimum -> fails. + # (Tests 2 and 3 would pass: 4 quarters >= 2; 5299 >= 1.5*3000=4500.) ut_ui_monetarily_eligible: false -- name: Case 2, base wages exactly at $5,500 floor pass the minimum test. +- name: Case 2, base wages exactly at $5,300 floor pass the minimum test. period: 2025 input: people: person1: age: 35 - ut_ui_base_period_wages: 5_500 + ut_ui_base_period_wages: 5_300 ut_ui_high_quarter_wages: 3_000 ut_ui_quarters_with_wages: 4 households: @@ -56,19 +56,19 @@ output: people: person1: - # Test 1: $5,500 >= $5,500 minimum (>=, not strict). + # Test 1: $5,300 >= $5,300 minimum (>=, not strict). # Test 2: 4 quarters >= 2. - # Test 3: $5,500 >= 1.5*$3,000 = $4,500. + # Test 3: $5,300 >= 1.5*$3,000 = $4,500. # All tests pass -> monetarily eligible. ut_ui_monetarily_eligible: true -- name: Case 3, base wages one dollar above $5,500 floor pass the minimum test. +- name: Case 3, base wages one dollar above $5,300 floor pass the minimum test. period: 2025 input: people: person1: age: 35 - ut_ui_base_period_wages: 5_501 + ut_ui_base_period_wages: 5_301 ut_ui_high_quarter_wages: 3_000 ut_ui_quarters_with_wages: 4 households: @@ -78,7 +78,7 @@ output: people: person1: - # Test 1: $5,501 >= $5,500 minimum. + # Test 1: $5,301 >= $5,300 minimum. # All tests pass -> monetarily eligible. ut_ui_monetarily_eligible: true @@ -102,7 +102,7 @@ output: people: person1: - # Test 1: $15,000 >= $5,500 minimum. + # Test 1: $15,000 >= $5,300 minimum. # Test 2: 4 quarters >= 2. # Test 3: $15,000 = 1.5 * $10,000 exactly (>=, not strict). # All tests pass -> monetarily eligible. @@ -213,7 +213,7 @@ output: people: person1: - # Monetarily eligible: $5,500 >= $5,500 min; 4 quarters >= 2; + # Monetarily eligible: $5,500 >= $5,300 min; 4 quarters >= 2; # $5,500 >= 1.5*$100 = $150. ut_ui_monetarily_eligible: true # Raw WBA = floor(100/26) - 5 = 3 - 5 = -2 -> max_(.,0) = 0. @@ -377,7 +377,7 @@ output: people: person1: - # Monetarily eligible: $9,630 >= $5,500 min; 4 quarters >= 2; + # Monetarily eligible: $9,630 >= $5,300 min; 4 quarters >= 2; # $9,630 >= 1.5 * $2,730 = $4,095. # WBA = floor($2,730/26) - 5 = $105 - $5 = $100. # Step 1: floor(0.27 * $9,630) = floor($2,600.10) = $2,600. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml index d7f96a6dde7..f8c774c8d25 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml @@ -1,6 +1,7 @@ # Tests for Utah UI monetary eligibility. # A claimant is monetarily eligible only if ALL THREE base-period tests pass: -# 1. Total base-period wages >= $5,500 (Utah Code § 35A-4-201(16)). +# 1. Total base-period wages >= the annual minimum ($5,300 in 2024-2025; +# $5,500 in 2026), per Utah Code § 35A-4-201(16). # 2. Wages paid in at least 2 calendar quarters (Utah Admin Code R994-401-202). # 3. Total base-period wages >= 1.5 x high-quarter wages (§ 35A-4-403(1)(f)(i)). @@ -20,13 +21,13 @@ output: people: person1: - # Test 1: $25,000 >= $5,500 minimum. + # Test 1: $25,000 >= $5,300 minimum. # Test 2: 4 quarters >= 2 required. # Test 3: $25,000 >= 1.5 * $8,000 = $12,000. # All tests pass -> monetarily eligible. ut_ui_monetarily_eligible: true -- name: Case 2, base wages below $5,500 floor fails minimum-wage test. +- name: Case 2, base wages below $5,300 floor fails minimum-wage test. period: 2025 input: people: @@ -42,7 +43,7 @@ output: people: person1: - # Test 1: $5,000 < $5,500 minimum -> fails. + # Test 1: $5,000 < $5,300 minimum -> fails. ut_ui_monetarily_eligible: false - name: Case 3, only one quarter of wages fails quarter-count test. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml index a8c64da619b..2890890b9b7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml @@ -21,7 +21,7 @@ output: people: person1: - # Monetarily eligible: $25,000 >= $5,500 and >= 1.5 * $10,000 = $15,000. + # Monetarily eligible: $25,000 >= $5,300 and >= 1.5 * $10,000 = $15,000. # WBA = floor($10,000 / 26) - $5 = $384 - $5 = $379. # $379 below 2025 cap of $777, so no cap applies. ut_ui_weekly_benefit_amount: 379 @@ -87,6 +87,6 @@ output: people: person1: - # $5,000 < $5,500 minimum -> not monetarily eligible. + # $5,000 < $5,300 minimum -> not monetarily eligible. # WBA = 0 regardless of high-quarter calculation. ut_ui_weekly_benefit_amount: 0 diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py index bb18ab3d3c0..00d577d2347 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py @@ -8,7 +8,7 @@ class ut_ui_weekly_hours_worked(Variable): unit = "hour" definition_period = YEAR default_value = 0 - reference = "https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=11" + reference = "https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=13" # Hours worked during a claim week. A claimant who works at least the # full-time hours threshold (40 hours) in a week is not eligible for # benefits that week per Utah DWS Claimant Guide page 11 and the From 02903fe3f9ce38a348f54eddb067449ae3485953 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 13 May 2026 14:21:51 -0400 Subject: [PATCH 4/6] Review-fix round 2: address critical issues from /review-program - Replace misleading 2025 form URL with Wayback Machine archive snapshot - Clarify Claimant Guide page references (printed p.11 = file p.13) - Add 2024/2026 boundary tests for min_base_period_wages (Cases 28-32) - Use canonical verb in base_period_to_high_quarter_ratio description - Pair statute and admin rule citations on min_quarters_with_wages --- .../base_period_to_high_quarter_ratio.yaml | 2 +- .../eligibility/min_base_period_wages.yaml | 6 +- .../eligibility/min_quarters_with_wages.yaml | 2 + .../ut_ui_edge_cases.yaml | 110 +++++++++++++++++- .../ut_ui_weekly_payable_amount.yaml | 4 +- .../ut_ui_weekly_hours_worked.py | 4 +- .../ut_ui_weekly_payable_amount.py | 5 +- 7 files changed, 122 insertions(+), 11 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml index 95ada15a217..2d140d16fd5 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml @@ -1,4 +1,4 @@ -description: Utah requires total base-period wages to be at least this multiple of high-quarter wages under the Unemployment Insurance program. +description: Utah uses this multiple of high-quarter wages as the minimum total base-period wages under the Unemployment Insurance program. values: 2024-01-01: 1.5 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml index a02be8eae6b..dba0c7b2361 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml @@ -16,7 +16,7 @@ metadata: reference: - title: Utah Code § 35A-4-201(16) href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html - - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0125) - href: https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 - - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0126) + - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0125, archived 2025) + href: https://web.archive.org/web/20250304230024/https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 + - title: Utah DWS Unemployment Insurance Benefit Schedule (current year — URL rolls over annually) href: https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml index c1d7155625b..5af6f368499 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml @@ -8,5 +8,7 @@ metadata: period: year label: Utah UI minimum quarters with wages reference: + - title: Utah Code § 35A-4-403(1)(f) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html - title: Utah Admin Code R994-401-202 href: https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml index 428cf7fd5f7..7155bcc9386 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml @@ -17,7 +17,7 @@ # https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-301 # # --------------------------------------------------------------------------- -# THRESHOLD BOUNDARIES — minimum base-period wages ($5,300 in 2025) +# THRESHOLD BOUNDARIES — minimum base-period wages ($5,300 in 2024-2025; $5,500 in 2026) # --------------------------------------------------------------------------- - name: Case 1, base wages one dollar below $5,300 floor fails minimum test. @@ -677,3 +677,111 @@ # ut_ui has defined_for = StateCode.UT -> zero for non-UT households, # regardless of all monetary and benefit inputs. ut_ui: 0 + +# --------------------------------------------------------------------------- +# THRESHOLD BOUNDARIES — cross-year regression tests +# (2024 floor: $5,300; 2026 floor: $5,500) +# --------------------------------------------------------------------------- + +- name: Case 28, 2024 base wages one dollar below $5,300 floor fail minimum test. + period: 2024 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_299 + ut_ui_high_quarter_wages: 3_200 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,299 < $5,300 (2024 minimum) -> fails. + ut_ui_monetarily_eligible: false + +- name: Case 29, 2024 base wages exactly at $5,300 floor pass the minimum test. + period: 2024 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_300 + ut_ui_high_quarter_wages: 3_200 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,300 >= $5,300 (2024 minimum). + # Test 2: 4 quarters >= 2. + # Test 3: $5,300 >= 1.5*$3,200 = $4,800. + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true + +- name: Case 30, 2026 base wages one dollar below $5,500 floor fail minimum test. + period: 2026 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_499 + ut_ui_high_quarter_wages: 3_200 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,499 < $5,500 (2026 minimum) -> fails. + ut_ui_monetarily_eligible: false + +- name: Case 31, 2026 base wages exactly at $5,500 floor pass the minimum test. + period: 2026 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_500 + ut_ui_high_quarter_wages: 3_200 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,500 >= $5,500 (2026 minimum). + # Test 2: 4 quarters >= 2. + # Test 3: $5,500 >= 1.5*$3,200 = $4,800. + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true + +- name: Case 32, 2026 base wages at $5,300 fail (regression — 2025 floor would pass). + period: 2026 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_300 + ut_ui_high_quarter_wages: 3_200 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,300 < $5,300 (2026 minimum is $5,500) -> fails. + # Regression guard: a collapse of the parameter into a single value + # across years would let this case pass under the 2024/2025 floor. + ut_ui_monetarily_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml index 1b31816b6af..56118a04c4a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml @@ -3,8 +3,8 @@ # - 30% earnings disregard: first 0.30 * WBA of weekly earnings is disregarded # (Utah Code § 35A-4-401(3)(a); Utah Admin Code R994-401-301). # - Excess earnings (above 0.30 * WBA) reduce WBA dollar-for-dollar. -# - Earnings >= WBA disqualify the week (Claimant Guide p. 11). -# - Weekly hours >= 40 disqualify the week (Claimant Guide p. 11; § 35A-4-207). +# - Earnings >= WBA disqualify the week (Claimant Guide p. 11; PDF file p. 13). +# - Weekly hours >= 40 disqualify the week (Claimant Guide p. 11; PDF file p. 13; § 35A-4-207). # Result is floored to a whole dollar per § 35A-4-401(3)(b). # # All cases below use WBA = $395 (HQ = $10,400, base = $25,000, 4 quarters). diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py index 00d577d2347..6ae932a4d41 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py @@ -11,5 +11,5 @@ class ut_ui_weekly_hours_worked(Variable): reference = "https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=13" # Hours worked during a claim week. A claimant who works at least the # full-time hours threshold (40 hours) in a week is not eligible for - # benefits that week per Utah DWS Claimant Guide page 11 and the - # "total unemployment" definition in Utah Code § 35A-4-207. + # benefits that week per Utah DWS Claimant Guide page 11 (PDF file p. 13) + # and the "total unemployment" definition in Utah Code § 35A-4-207. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py index 43bad21663c..593ea34d818 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py +++ b/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py @@ -27,8 +27,9 @@ def formula(person, period, parameters): raw_payable = max_(np.floor(weekly_benefit_amount - excess_earnings), 0) # § 35A-4-401(3)(a): earnings at or above the WBA disqualify the - # week. Claimant Guide page 11 / § 35A-4-207: working at least the - # full-time hours threshold (40 hours) in a week also disqualifies. + # week. Claimant Guide page 11 (PDF file p. 13) / § 35A-4-207: + # working at least the full-time hours threshold (40 hours) in a + # week also disqualifies. disqualified = (gross_weekly_earnings >= weekly_benefit_amount) | ( weekly_hours_worked >= p.benefit.partial.hours_threshold ) From b94967f8941c2d6800c4d290db33be2d668d95ab Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 13 May 2026 14:44:57 -0400 Subject: [PATCH 5/6] Review-fix round 3: correct 2024 min_base_period_wages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Derived from 2024 max WBA ($712) per UC § 35A-4-201(16) + § 35A-4-401(2)(b)(ii): both values depend on the same insured average fiscal year wage. Working backward, 8% × annual_IAFY ≈ $4,772, rounded up to next $100 = $4,800. - Update 2024-01-01 entry from $5,300 to $4,800 - Adjust edge case boundaries (Cases 28-29) to test new $4,800 floor --- .../eligibility/min_base_period_wages.yaml | 9 ++++-- .../ut_ui_edge_cases.yaml | 28 ++++++++++--------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml index dba0c7b2361..2d64e2aefc1 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml +++ b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml @@ -2,10 +2,13 @@ description: Utah limits monetary eligibility to claimants with total base-perio # The floor is recomputed annually per Utah Code § 35A-4-201(16): # 8% of the insured average fiscal-year wage for the preceding fiscal year, -# rounded up to the next higher multiple of $100. The 2024 entry mirrors the -# adjacent 2025 value because DWS no longer publishes the 2024 schedule PDF. +# rounded up to the next higher multiple of $100. The 2024 value is derived +# from the 2024 max WBA ($712) per UC § 35A-4-201(16) (8% of insured average +# fiscal year wage, rounded up to next $100) and § 35A-4-401(2)(b)(ii). DWS +# no longer publishes the 2024 schedule PDF, but the value is recoverable +# from the 2024 max WBA already encoded in `wba/max_amount.yaml`. values: - 2024-01-01: 5_300 + 2024-01-01: 4_800 2025-01-01: 5_300 2026-01-01: 5_500 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml index 7155bcc9386..4276e8a64d5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml @@ -17,7 +17,8 @@ # https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-301 # # --------------------------------------------------------------------------- -# THRESHOLD BOUNDARIES — minimum base-period wages ($5,300 in 2024-2025; $5,500 in 2026) +# THRESHOLD BOUNDARIES — minimum base-period wages +# ($4,800 in 2024; $5,300 in 2025; $5,500 in 2026) # --------------------------------------------------------------------------- - name: Case 1, base wages one dollar below $5,300 floor fails minimum test. @@ -680,17 +681,17 @@ # --------------------------------------------------------------------------- # THRESHOLD BOUNDARIES — cross-year regression tests -# (2024 floor: $5,300; 2026 floor: $5,500) +# (2024 floor: $4,800; 2026 floor: $5,500) # --------------------------------------------------------------------------- -- name: Case 28, 2024 base wages one dollar below $5,300 floor fail minimum test. +- name: Case 28, 2024 base wages one dollar below $4,800 floor fail minimum test. period: 2024 input: people: person1: age: 35 - ut_ui_base_period_wages: 5_299 - ut_ui_high_quarter_wages: 3_200 + ut_ui_base_period_wages: 4_799 + ut_ui_high_quarter_wages: 3_000 ut_ui_quarters_with_wages: 4 households: household: @@ -699,17 +700,18 @@ output: people: person1: - # Test 1: $5,299 < $5,300 (2024 minimum) -> fails. + # Test 1: $4,799 < $4,800 (2024 minimum) -> fails. + # (Tests 2 and 3 would pass: 4 quarters >= 2; 4,799 >= 1.5*3,000=4,500.) ut_ui_monetarily_eligible: false -- name: Case 29, 2024 base wages exactly at $5,300 floor pass the minimum test. +- name: Case 29, 2024 base wages exactly at $4,800 floor pass the minimum test. period: 2024 input: people: person1: age: 35 - ut_ui_base_period_wages: 5_300 - ut_ui_high_quarter_wages: 3_200 + ut_ui_base_period_wages: 4_800 + ut_ui_high_quarter_wages: 3_000 ut_ui_quarters_with_wages: 4 households: household: @@ -718,9 +720,9 @@ output: people: person1: - # Test 1: $5,300 >= $5,300 (2024 minimum). + # Test 1: $4,800 >= $4,800 (2024 minimum). # Test 2: 4 quarters >= 2. - # Test 3: $5,300 >= 1.5*$3,200 = $4,800. + # Test 3: $4,800 >= 1.5*$3,000 = $4,500. # All tests pass -> monetarily eligible. ut_ui_monetarily_eligible: true @@ -781,7 +783,7 @@ output: people: person1: - # Test 1: $5,300 < $5,300 (2026 minimum is $5,500) -> fails. + # Test 1: $5,300 < $5,500 (2026 minimum) -> fails. # Regression guard: a collapse of the parameter into a single value - # across years would let this case pass under the 2024/2025 floor. + # across years would let this case pass under the 2025 floor. ut_ui_monetarily_eligible: false From 2ee684060a6c2ed9eb35707333c9b3cfaf1e01ad Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Tue, 4 Aug 2026 11:36:31 -0400 Subject: [PATCH 6/6] Address program review: 2024 values, dws rename, citations, tests - Correct 2024 max WBA $712 -> $746 and 2024 minimum base-period wages $4,800 -> $5,100 per the archived January 2024 DWS Benefit Schedule; recompute the four dependent 2024 test cases - Rename agency path dwf -> dws (Department of Workforce Services); pre-existing dwf/fep left for separate cleanup - Fix R994-401-202 -> R994-401-201 pin-cites; make the Claimant Guide the value-bearing citation for the 2-quarter rule and 40-hour threshold; add per-year archive.org references for schedule values - Document unmodeled provisions (waiting week, 20-week alternative sunset, child-support and voluntary tax withholding) and zero-default microsim-inert inputs - Add boundary and defensive tests: WBA floor cases, partial earnings at WBA-1, MBA equality, negative wages, just-above-floor eligibility Co-Authored-By: Claude Fable 5 --- .../benefit/wba/max_amount.yaml | 16 -- .../benefit/duration/max_weeks.yaml | 0 .../benefit/duration/min_weeks.yaml | 0 .../benefit/duration/multiplier.yaml | 0 .../partial/earnings_disregard_rate.yaml | 0 .../benefit/partial/hours_threshold.yaml | 4 +- .../benefit/wba/divisor.yaml | 0 .../benefit/wba/max_amount.yaml | 21 +++ .../benefit/wba/subtraction.yaml | 0 .../base_period_to_high_quarter_ratio.yaml | 8 +- .../eligibility/min_base_period_wages.yaml | 12 +- .../eligibility/min_quarters_with_wages.yaml | 8 +- .../unemployment_insurance/index.yaml | 0 policyengine_us/programs.yaml | 2 +- .../ut_ui_weekly_benefit_amount.yaml | 92 ---------- .../unemployment_insurance/integration.yaml | 55 +++++- .../ut_ui_duration_weeks.yaml | 0 .../ut_ui_edge_cases.yaml | 59 +++--- .../ut_ui_maximum_benefit_amount.yaml | 0 .../ut_ui_monetarily_eligible.yaml | 72 +++++++- .../ut_ui_weekly_benefit_amount.yaml | 168 ++++++++++++++++++ .../ut_ui_weekly_payable_amount.yaml | 28 +++ .../unemployment_insurance/ut_ui.py | 8 + .../ut_ui_base_period_wages.py | 2 + .../ut_ui_duration_weeks.py | 2 +- .../ut_ui_gross_weekly_earnings.py | 2 + .../ut_ui_high_quarter_wages.py | 2 + .../ut_ui_maximum_benefit_amount.py | 0 .../ut_ui_monetarily_eligible.py | 10 +- .../ut_ui_quarters_with_wages.py | 6 +- .../ut_ui_weekly_benefit_amount.py | 2 +- .../ut_ui_weekly_hours_worked.py | 2 + .../ut_ui_weekly_payable_amount.py | 2 +- .../ut_ui_weeks_unemployed.py | 2 + 34 files changed, 415 insertions(+), 170 deletions(-) delete mode 100644 policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/max_amount.yaml rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/benefit/duration/max_weeks.yaml (100%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/benefit/duration/min_weeks.yaml (100%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/benefit/duration/multiplier.yaml (100%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml (100%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/benefit/partial/hours_threshold.yaml (100%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/benefit/wba/divisor.yaml (100%) create mode 100644 policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/wba/max_amount.yaml rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/benefit/wba/subtraction.yaml (100%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml (60%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/eligibility/min_base_period_wages.yaml (68%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/eligibility/min_quarters_with_wages.yaml (68%) rename policyengine_us/parameters/gov/states/ut/{dwf => dws}/unemployment_insurance/index.yaml (100%) delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml rename policyengine_us/tests/policy/baseline/gov/states/ut/{dwf => dws}/unemployment_insurance/integration.yaml (78%) rename policyengine_us/tests/policy/baseline/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_duration_weeks.yaml (100%) rename policyengine_us/tests/policy/baseline/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_edge_cases.yaml (93%) rename policyengine_us/tests/policy/baseline/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml (100%) rename policyengine_us/tests/policy/baseline/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_monetarily_eligible.yaml (52%) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml rename policyengine_us/tests/policy/baseline/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_weekly_payable_amount.yaml (80%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui.py (70%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_base_period_wages.py (83%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_duration_weeks.py (95%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_gross_weekly_earnings.py (83%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_high_quarter_wages.py (78%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_maximum_benefit_amount.py (100%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_monetarily_eligible.py (74%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_quarters_with_wages.py (65%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_weekly_benefit_amount.py (94%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_weekly_hours_worked.py (81%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_weekly_payable_amount.py (96%) rename policyengine_us/variables/gov/states/ut/{dwf => dws}/unemployment_insurance/ut_ui_weeks_unemployed.py (78%) diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/max_amount.yaml deleted file mode 100644 index 520397469b9..00000000000 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/max_amount.yaml +++ /dev/null @@ -1,16 +0,0 @@ -description: Utah limits the weekly benefit amount to this amount under the Unemployment Insurance program. - -values: - 2024-01-01: 712 - 2025-01-01: 777 - 2026-01-01: 806 - -metadata: - unit: currency-USD - period: week - label: Utah UI maximum weekly benefit amount - reference: - - title: Utah Code § 35A-4-401(2)(b)(ii) - href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html - - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0126) - href: https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/max_weeks.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/duration/max_weeks.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/max_weeks.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/duration/max_weeks.yaml diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/min_weeks.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/duration/min_weeks.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/min_weeks.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/duration/min_weeks.yaml diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/multiplier.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/duration/multiplier.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/duration/multiplier.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/duration/multiplier.yaml diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/partial/earnings_disregard_rate.yaml diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/partial/hours_threshold.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/partial/hours_threshold.yaml index bf2ecec68c8..7aa482738f8 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/partial/hours_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/partial/hours_threshold.yaml @@ -8,7 +8,7 @@ metadata: period: week label: Utah UI weekly hours threshold reference: - - title: Utah Code § 35A-4-207 - href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S207.html - title: Utah DWS Claimant Guide (Jan 2025) href: https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=13 + - title: Utah Code § 35A-4-207 + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S207.html diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/divisor.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/wba/divisor.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/divisor.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/wba/divisor.yaml diff --git a/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/wba/max_amount.yaml new file mode 100644 index 00000000000..4cc9f1c38df --- /dev/null +++ b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/wba/max_amount.yaml @@ -0,0 +1,21 @@ +description: Utah limits the weekly benefit amount to this amount under the Unemployment Insurance program. + +# Jan-1 steps track the DWS calendar-year benefit schedule effective dates. +values: + 2024-01-01: 746 + 2025-01-01: 777 + 2026-01-01: 806 + +metadata: + unit: currency-USD + period: week + label: Utah UI maximum weekly benefit amount + reference: + - title: Utah Code § 35A-4-401(2)(b)(ii) + href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html + - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0126, archived 2024) + href: https://web.archive.org/web/20240613222926/https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 + - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0125, archived 2025) + href: https://web.archive.org/web/20250304230024/https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 + - title: Utah DWS Unemployment Insurance Benefit Schedule (current year — URL rolls over annually) + href: https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/subtraction.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/wba/subtraction.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/benefit/wba/subtraction.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/benefit/wba/subtraction.yaml diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml similarity index 60% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml index 2d140d16fd5..c9646fd8832 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml +++ b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/base_period_to_high_quarter_ratio.yaml @@ -1,5 +1,9 @@ description: Utah uses this multiple of high-quarter wages as the minimum total base-period wages under the Unemployment Insurance program. +# § 35A-4-403(1)(f)(ii) provides an alternative to this 1.5x ratio test — +# wages in insured work for at least 20 weeks in the base period. That +# alternative sunset on or before Jan 1, 2011, so only the ratio test is +# modeled. values: 2024-01-01: 1.5 @@ -10,5 +14,5 @@ metadata: reference: - title: Utah Code § 35A-4-403(1)(f)(i) href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html - - title: Utah Admin Code R994-401-202 - href: https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202 + - title: Utah Admin Code R994-401-201 + href: https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-201 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/min_base_period_wages.yaml similarity index 68% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/min_base_period_wages.yaml index 2d64e2aefc1..0a6625edc0d 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_base_period_wages.yaml +++ b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/min_base_period_wages.yaml @@ -2,13 +2,11 @@ description: Utah limits monetary eligibility to claimants with total base-perio # The floor is recomputed annually per Utah Code § 35A-4-201(16): # 8% of the insured average fiscal-year wage for the preceding fiscal year, -# rounded up to the next higher multiple of $100. The 2024 value is derived -# from the 2024 max WBA ($712) per UC § 35A-4-201(16) (8% of insured average -# fiscal year wage, rounded up to next $100) and § 35A-4-401(2)(b)(ii). DWS -# no longer publishes the 2024 schedule PDF, but the value is recoverable -# from the 2024 max WBA already encoded in `wba/max_amount.yaml`. +# rounded up to the next higher multiple of $100. Each Jan-1 step tracks the +# DWS calendar-year benefit schedule effective date. The 2024 schedule PDF is +# published and states $5,100 directly (archived below). values: - 2024-01-01: 4_800 + 2024-01-01: 5_100 2025-01-01: 5_300 2026-01-01: 5_500 @@ -19,6 +17,8 @@ metadata: reference: - title: Utah Code § 35A-4-201(16) href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html + - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0126, archived 2024) + href: https://web.archive.org/web/20240613222926/https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 - title: Utah DWS Unemployment Insurance Benefit Schedule (Form 04-13-0125, archived 2025) href: https://web.archive.org/web/20250304230024/https://jobs.utah.gov/ui/UIShared/PDFs/BenefitCalculation.pdf#page=1 - title: Utah DWS Unemployment Insurance Benefit Schedule (current year — URL rolls over annually) diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/min_quarters_with_wages.yaml similarity index 68% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/min_quarters_with_wages.yaml index 5af6f368499..43f7e80e170 100644 --- a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/eligibility/min_quarters_with_wages.yaml +++ b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/eligibility/min_quarters_with_wages.yaml @@ -4,11 +4,13 @@ values: 2024-01-01: 2 metadata: - unit: int + unit: /1 period: year label: Utah UI minimum quarters with wages reference: + - title: Utah DWS Claimant Guide (Jan 2025) + href: https://jobs.utah.gov/ui/jobseeker/claimantguide.pdf#page=6 - title: Utah Code § 35A-4-403(1)(f) href: https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html - - title: Utah Admin Code R994-401-202 - href: https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202 + - title: Utah Admin Code R994-401-201 + href: https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-201 diff --git a/policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/index.yaml b/policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/index.yaml similarity index 100% rename from policyengine_us/parameters/gov/states/ut/dwf/unemployment_insurance/index.yaml rename to policyengine_us/parameters/gov/states/ut/dws/unemployment_insurance/index.yaml diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 5225fe29b7d..732ca10219f 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1353,7 +1353,7 @@ programs: coverage: UT verified_years: "2024-2026" variable: ut_ui - parameter_prefix: gov.states.ut.dwf.unemployment_insurance + parameter_prefix: gov.states.ut.dws.unemployment_insurance - id: tx_fpp_benefit name: Texas FPP diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml deleted file mode 100644 index 2890890b9b7..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# Tests for Utah UI weekly benefit amount. -# Formula: WBA = floor(high_quarter_wages / 26) - $5 (§ 35A-4-401(2)(a)(ii)). -# Then capped at the annual max WBA (§ 35A-4-401(2)(b)(ii)): -# 2024: $712; 2025: $777; 2026: $806. -# WBA = 0 when claimant is not monetarily eligible. - -- name: Case 1, standard WBA from $10,000 high quarter. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ut_ui_base_period_wages: 25_000 - ut_ui_high_quarter_wages: 10_000 - ut_ui_quarters_with_wages: 4 - households: - household: - members: [person1] - state_code: UT - output: - people: - person1: - # Monetarily eligible: $25,000 >= $5,300 and >= 1.5 * $10,000 = $15,000. - # WBA = floor($10,000 / 26) - $5 = $384 - $5 = $379. - # $379 below 2025 cap of $777, so no cap applies. - ut_ui_weekly_benefit_amount: 379 - -- name: Case 2, WBA capped at 2024 max of $712. - period: 2024 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ut_ui_base_period_wages: 50_000 - ut_ui_high_quarter_wages: 20_000 - ut_ui_quarters_with_wages: 4 - households: - household: - members: [person1] - state_code: UT - output: - people: - person1: - # Monetarily eligible: $50,000 >= 1.5 * $20,000 = $30,000. - # Raw WBA = floor($20,000 / 26) - $5 = $769 - $5 = $764. - # 2024 cap = $712, so WBA = $712. - ut_ui_weekly_benefit_amount: 712 - -- name: Case 3, WBA capped at 2026 max of $806. - period: 2026 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ut_ui_base_period_wages: 80_000 - ut_ui_high_quarter_wages: 25_000 - ut_ui_quarters_with_wages: 4 - households: - household: - members: [person1] - state_code: UT - output: - people: - person1: - # Monetarily eligible: $80,000 >= 1.5 * $25,000 = $37,500. - # Raw WBA = floor($25,000 / 26) - $5 = $961 - $5 = $956. - # 2026 cap = $806, so WBA = $806. - ut_ui_weekly_benefit_amount: 806 - -- name: Case 4, monetarily ineligible yields zero WBA. - period: 2025 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 35 - ut_ui_base_period_wages: 5_000 - ut_ui_high_quarter_wages: 2_000 - ut_ui_quarters_with_wages: 4 - households: - household: - members: [person1] - state_code: UT - output: - people: - person1: - # $5,000 < $5,300 minimum -> not monetarily eligible. - # WBA = 0 regardless of high-quarter calculation. - ut_ui_weekly_benefit_amount: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/integration.yaml similarity index 78% rename from policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml rename to policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/integration.yaml index 7dfa986448c..36f811ebc1c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/integration.yaml @@ -58,17 +58,17 @@ # Monetarily eligible: $80,000 >= 1.5 * $25,000 = $37,500. ut_ui_monetarily_eligible: true # Raw WBA = floor($25,000 / 26) - $5 = $961 - $5 = $956. - # 2024 cap = $712, so WBA = $712. - ut_ui_weekly_benefit_amount: 712 - # Raw duration = floor(floor(0.27 * $80,000) / $712) - # = floor($21,600 / $712) = floor(30.34) = 30, clamp 26. + # 2024 cap = $746, so WBA = $746. + ut_ui_weekly_benefit_amount: 746 + # Raw duration = floor(floor(0.27 * $80,000) / $746) + # = floor($21,600 / $746) = floor(28.95) = 28, clamp 26. ut_ui_duration_weeks: 26 - # MBA = $712 * 26 = $18,512. - ut_ui_maximum_benefit_amount: 18_512 + # MBA = $746 * 26 = $19,396. + ut_ui_maximum_benefit_amount: 19_396 # Weekly payable = WBA when no earnings/hours. - ut_ui_weekly_payable_amount: 712 - # Annual = $712 * 26 = $18,512; MBA cap = $18,512. - ut_ui: 18_512 + ut_ui_weekly_payable_amount: 746 + # Annual = $746 * 26 = $19,396; MBA cap = $19,396. + ut_ui: 19_396 - name: Case 3, full-year unemployment hits 2026 max WBA cap. period: 2026 @@ -229,3 +229,40 @@ # ut_ui has defined_for = StateCode.UT -> zero for non-UT households, # regardless of monetary inputs. ut_ui: 0 + +# --------------------------------------------------------------------------- +# S9(d) WEEKS UNEMPLOYED EXACTLY EQUAL TO DURATION — the min_(WBA * weeks, MBA) +# cap binds at equality (annual == MBA). Also the 10-week duration floor +# (S9(a)) is effectively unreachable: the raw duration only drops toward 10 as +# base wages approach the 1.5x monetary boundary, which is already exercised by +# integration Case 4 without a separately contrived input, so no extra case is +# added for it here. +- name: Case 8, weeks unemployed exactly equal to duration weeks hit MBA cap. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_weeks_unemployed: 17 + ut_ui_gross_weekly_earnings: 0 + ut_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $25,000 >= 1.5 * $10,400 = $15,600. + # WBA = $395; duration = 17; MBA = $395 * 17 = $6,715. + ut_ui_weekly_benefit_amount: 395 + ut_ui_duration_weeks: 17 + ut_ui_maximum_benefit_amount: 6_715 + ut_ui_weekly_payable_amount: 395 + # weeks_unemployed (17) == duration (17): annual = $395 * 17 = $6,715. + # min($6,715, MBA $6,715) = $6,715 -> cap binds exactly at equality. + ut_ui: 6_715 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_duration_weeks.yaml similarity index 100% rename from policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.yaml rename to policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_duration_weeks.yaml diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_edge_cases.yaml similarity index 93% rename from policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml rename to policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_edge_cases.yaml index 4276e8a64d5..6105d612951 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_edge_cases.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_edge_cases.yaml @@ -11,14 +11,14 @@ # https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html # - Utah Code § 35A-4-403(1)(f)(i) (1.5x ratio test) # https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html -# - Utah Admin Code R994-401-202 (quarters test) -# https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202 +# - Utah Admin Code R994-401-201 (quarters test) +# https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-201 # - Utah Admin Code R994-401-301 (partial benefit) # https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-301 # # --------------------------------------------------------------------------- # THRESHOLD BOUNDARIES — minimum base-period wages -# ($4,800 in 2024; $5,300 in 2025; $5,500 in 2026) +# ($5,100 in 2024; $5,300 in 2025; $5,500 in 2026) # --------------------------------------------------------------------------- - name: Case 1, base wages one dollar below $5,300 floor fails minimum test. @@ -204,7 +204,7 @@ people: person1: age: 35 - ut_ui_base_period_wages: 5_500 + ut_ui_base_period_wages: 300 ut_ui_high_quarter_wages: 100 ut_ui_quarters_with_wages: 4 households: @@ -214,11 +214,13 @@ output: people: person1: - # Monetarily eligible: $5,500 >= $5,300 min; 4 quarters >= 2; - # $5,500 >= 1.5*$100 = $150. - ut_ui_monetarily_eligible: true + # Consistent inputs: HQ is the highest single quarter, so total + # base-period wages ($300) cannot exceed 4 x HQ. Such a claimant is + # far below the $5,300 minimum and thus not monetarily eligible. + ut_ui_monetarily_eligible: false # Raw WBA = floor(100/26) - 5 = 3 - 5 = -2 -> max_(.,0) = 0. - # Tests negative-protection: WBA must never be negative. + # Tests negative-protection: WBA must never be negative (and the + # monetary-ineligibility gate independently forces WBA to 0). ut_ui_weekly_benefit_amount: 0 - name: Case 10, high quarter at exact lower boundary of 2024 WBA cap. @@ -229,7 +231,7 @@ person1: age: 35 ut_ui_base_period_wages: 50_000 - ut_ui_high_quarter_wages: 18_642 + ut_ui_high_quarter_wages: 19_526 ut_ui_quarters_with_wages: 4 households: household: @@ -238,12 +240,12 @@ output: people: person1: - # Monetarily eligible: $50,000 >= 1.5 * $18,642 = $27,963. - # Raw WBA = floor(18,642/26) - 5 = floor(717.0) - 5 = 717 - 5 = $712. - # 2024 cap = $712 -> WBA exactly hits the cap with no clipping. - ut_ui_weekly_benefit_amount: 712 + # Monetarily eligible: $50,000 >= 1.5 * $19,526 = $29,289. + # Raw WBA = floor(19,526/26) - 5 = floor(751.0) - 5 = 751 - 5 = $746. + # 2024 cap = $746 -> WBA exactly hits the cap with no clipping. + ut_ui_weekly_benefit_amount: 746 -- name: Case 11, high quarter just above 2024 cap threshold is capped to 712. +- name: Case 11, high quarter of $18,668 stays below the 2024 cap. period: 2024 absolute_error_margin: 0.01 input: @@ -261,8 +263,8 @@ people: person1: # Raw WBA = floor(18,668/26) - 5 = floor(718.0) - 5 = 718 - 5 = $713. - # 2024 cap = $712 -> capped down to $712. - ut_ui_weekly_benefit_amount: 712 + # 2024 cap = $746 -> $713 < cap, so no cap applies. + ut_ui_weekly_benefit_amount: 713 - name: Case 12, high quarter at exact lower boundary of 2025 WBA cap. period: 2025 @@ -319,7 +321,7 @@ people: person1: age: 35 - ut_ui_base_period_wages: 5_500 + ut_ui_base_period_wages: 300 ut_ui_high_quarter_wages: 100 ut_ui_quarters_with_wages: 4 households: @@ -329,8 +331,9 @@ output: people: person1: - # WBA = 0 (see Case 9). Duration formula short-circuits to 0 - # rather than dividing by zero or returning the 10-week floor. + # WBA = 0 (see Case 9; consistent HQ=$100/base=$300 combo). Duration + # formula short-circuits to 0 rather than dividing by zero or + # returning the 10-week floor. ut_ui_weekly_benefit_amount: 0 ut_ui_duration_weeks: 0 @@ -681,16 +684,16 @@ # --------------------------------------------------------------------------- # THRESHOLD BOUNDARIES — cross-year regression tests -# (2024 floor: $4,800; 2026 floor: $5,500) +# (2024 floor: $5,100; 2026 floor: $5,500) # --------------------------------------------------------------------------- -- name: Case 28, 2024 base wages one dollar below $4,800 floor fail minimum test. +- name: Case 28, 2024 base wages one dollar below $5,100 floor fail minimum test. period: 2024 input: people: person1: age: 35 - ut_ui_base_period_wages: 4_799 + ut_ui_base_period_wages: 5_099 ut_ui_high_quarter_wages: 3_000 ut_ui_quarters_with_wages: 4 households: @@ -700,17 +703,17 @@ output: people: person1: - # Test 1: $4,799 < $4,800 (2024 minimum) -> fails. - # (Tests 2 and 3 would pass: 4 quarters >= 2; 4,799 >= 1.5*3,000=4,500.) + # Test 1: $5,099 < $5,100 (2024 minimum) -> fails. + # (Tests 2 and 3 would pass: 4 quarters >= 2; 5,099 >= 1.5*3,000=4,500.) ut_ui_monetarily_eligible: false -- name: Case 29, 2024 base wages exactly at $4,800 floor pass the minimum test. +- name: Case 29, 2024 base wages exactly at $5,100 floor pass the minimum test. period: 2024 input: people: person1: age: 35 - ut_ui_base_period_wages: 4_800 + ut_ui_base_period_wages: 5_100 ut_ui_high_quarter_wages: 3_000 ut_ui_quarters_with_wages: 4 households: @@ -720,9 +723,9 @@ output: people: person1: - # Test 1: $4,800 >= $4,800 (2024 minimum). + # Test 1: $5,100 >= $5,100 (2024 minimum). # Test 2: 4 quarters >= 2. - # Test 3: $4,800 >= 1.5*$3,000 = $4,500. + # Test 3: $5,100 >= 1.5*$3,000 = $4,500. # All tests pass -> monetarily eligible. ut_ui_monetarily_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml similarity index 100% rename from policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml rename to policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_maximum_benefit_amount.yaml diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_monetarily_eligible.yaml similarity index 52% rename from policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml rename to policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_monetarily_eligible.yaml index f8c774c8d25..22678cc1da8 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_monetarily_eligible.yaml @@ -1,8 +1,8 @@ # Tests for Utah UI monetary eligibility. # A claimant is monetarily eligible only if ALL THREE base-period tests pass: -# 1. Total base-period wages >= the annual minimum ($5,300 in 2024-2025; -# $5,500 in 2026), per Utah Code § 35A-4-201(16). -# 2. Wages paid in at least 2 calendar quarters (Utah Admin Code R994-401-202). +# 1. Total base-period wages >= the annual minimum ($5,100 in 2024; +# $5,300 in 2025; $5,500 in 2026), per Utah Code § 35A-4-201(16). +# 2. Wages paid in at least 2 calendar quarters (Utah Admin Code R994-401-201). # 3. Total base-period wages >= 1.5 x high-quarter wages (§ 35A-4-403(1)(f)(i)). - name: Case 1, all three monetary tests pass. @@ -83,3 +83,69 @@ person1: # Test 3: $14,000 < 1.5 * $10,000 = $15,000 -> fails. ut_ui_monetarily_eligible: false + +# --------------------------------------------------------------------------- +# G5 DEFENSIVE — negative wages (data error) and just-above-floor boundaries. +- name: Case 5, negative base-period and high-quarter wages fail eligibility. + period: 2025 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: -10_000 + ut_ui_high_quarter_wages: -3_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: -$10,000 < $5,300 minimum -> fails. + # Negative wages can never satisfy monetary eligibility. + ut_ui_monetarily_eligible: false + +- name: Case 6, 2024 base wages one dollar above $5,100 floor pass eligibility. + period: 2024 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_101 + ut_ui_high_quarter_wages: 3_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,101 >= $5,100 (2024 minimum). + # Test 2: 4 quarters >= 2. + # Test 3: $5,101 >= 1.5 * $3,000 = $4,500. + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true + +- name: Case 7, 2026 base wages one dollar above $5,500 floor pass eligibility. + period: 2026 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_501 + ut_ui_high_quarter_wages: 3_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Test 1: $5,501 >= $5,500 (2026 minimum). + # Test 2: 4 quarters >= 2. + # Test 3: $5,501 >= 1.5 * $3,000 = $4,500. + # All tests pass -> monetarily eligible. + ut_ui_monetarily_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml new file mode 100644 index 00000000000..2296a787443 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_benefit_amount.yaml @@ -0,0 +1,168 @@ +# Tests for Utah UI weekly benefit amount. +# Formula: WBA = floor(high_quarter_wages / 26) - $5 (§ 35A-4-401(2)(a)(ii)). +# Then capped at the annual max WBA (§ 35A-4-401(2)(b)(ii)): +# 2024: $746; 2025: $777; 2026: $806. +# WBA = 0 when claimant is not monetarily eligible. + +- name: Case 1, standard WBA from $10,000 high quarter. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $25,000 >= $5,300 and >= 1.5 * $10,000 = $15,000. + # WBA = floor($10,000 / 26) - $5 = $384 - $5 = $379. + # $379 below 2025 cap of $777, so no cap applies. + ut_ui_weekly_benefit_amount: 379 + +- name: Case 2, WBA capped at 2024 max of $746. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 50_000 + ut_ui_high_quarter_wages: 20_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $50,000 >= 1.5 * $20,000 = $30,000. + # Raw WBA = floor($20,000 / 26) - $5 = $769 - $5 = $764. + # 2024 cap = $746, so WBA = $746. + ut_ui_weekly_benefit_amount: 746 + +- name: Case 3, WBA capped at 2026 max of $806. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 80_000 + ut_ui_high_quarter_wages: 25_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Monetarily eligible: $80,000 >= 1.5 * $25,000 = $37,500. + # Raw WBA = floor($25,000 / 26) - $5 = $961 - $5 = $956. + # 2026 cap = $806, so WBA = $806. + ut_ui_weekly_benefit_amount: 806 + +- name: Case 4, monetarily ineligible yields zero WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 5_000 + ut_ui_high_quarter_wages: 2_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # $5,000 < $5,300 minimum -> not monetarily eligible. + # WBA = 0 regardless of high-quarter calculation. + ut_ui_weekly_benefit_amount: 0 + +# --------------------------------------------------------------------------- +# S9(b) RAW WBA SUBTRACTION FLOOR — max_(floor(HQ/26) - 5, 0) zero-crossing. +# The raw amount turns positive between HQ $130 (floor 5 -> 5-5 = 0) and +# HQ $156 (floor 6 -> 6-5 = 1). Because HQ is the single highest quarter, +# base-period wages can never exceed 4 x HQ, so a claimant with HQ in this +# range ($<= $624 base) is always far below the $5,300 minimum and thus not +# monetarily eligible. Both boundary cases therefore output WBA = 0; the pair +# documents that the raw subtraction floor never emits a negative value. +- name: Case 5, raw WBA subtraction at exactly zero (HQ $130) yields zero WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 520 + ut_ui_high_quarter_wages: 130 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Raw WBA = floor(130/26) - 5 = 5 - 5 = 0 (crossing point). + # Not monetarily eligible ($520 < $5,300) -> WBA = 0. + ut_ui_monetarily_eligible: false + ut_ui_weekly_benefit_amount: 0 + +- name: Case 6, raw WBA subtraction just positive (HQ $156) still yields zero WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 624 + ut_ui_high_quarter_wages: 156 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Raw WBA = floor(156/26) - 5 = 6 - 5 = 1 (just above the crossing). + # Not monetarily eligible ($624 < $5,300) -> WBA still forced to 0. + ut_ui_monetarily_eligible: false + ut_ui_weekly_benefit_amount: 0 + +# --------------------------------------------------------------------------- +# G5 DEFENSIVE — negative high-quarter wages (data error) never inflate WBA. +- name: Case 7, negative high-quarter wages yield zero WBA (no negative benefit). + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: -5_000 + ut_ui_high_quarter_wages: -2_000 + ut_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # Negative base wages fail the $5,300 minimum -> not eligible. + # Raw WBA = floor(-2000/26) - 5 = -78 - 5 = -83 -> max_(.,0) = 0. + ut_ui_monetarily_eligible: false + ut_ui_weekly_benefit_amount: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_payable_amount.yaml similarity index 80% rename from policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml rename to policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_payable_amount.yaml index 56118a04c4a..09beadaab6b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_payable_amount.yaml @@ -128,3 +128,31 @@ # Earnings $0 < WBA, BUT hours 40 >= 40-hour threshold -> disqualified. ut_ui_weekly_benefit_amount: 395 ut_ui_weekly_payable_amount: 0 + +# --------------------------------------------------------------------------- +# S9(c) EARNINGS ONE DOLLAR BELOW WBA — still payable (disqualification is at +# earnings >= WBA, so WBA-1 does not disqualify). +- name: Case 6, earnings one dollar below WBA remain payable. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ut_ui_base_period_wages: 25_000 + ut_ui_high_quarter_wages: 10_400 + ut_ui_quarters_with_wages: 4 + ut_ui_gross_weekly_earnings: 394 + ut_ui_weekly_hours_worked: 20 + households: + household: + members: [person1] + state_code: UT + output: + people: + person1: + # WBA = $395. Earnings $394 < WBA $395 -> not disqualified. + # Disregard = $118.50; excess = $394 - $118.50 = $275.50. + # Payable = floor(max(0, $395 - $275.50)) = floor($119.50) = $119. + ut_ui_weekly_benefit_amount: 395 + ut_ui_weekly_payable_amount: 119 diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui.py similarity index 70% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui.py index a2442042b31..a7d982f223b 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui.py @@ -19,6 +19,14 @@ class ut_ui(Variable): # § 35A-4-401(2)(c)(i)-(iii); Utah Admin Code R994-401-203). Modeling # requires base-period-employer attribution that is not available in # the underlying microdata. + # - Waiting week: the first otherwise-eligible week is unpaid (Claimant + # Guide p.16). Not modeled — the annual formula does not track the + # week-by-week claim sequence. + # - Deductions from the benefit payment that do not change entitlement: + # child-support withholding of up to 50% of the WBA, and voluntary + # federal (10%) and Utah state (5%) income-tax withholding (Claimant + # Guide p.19). Not modeled — these are payment-side withholdings, not + # reductions in the benefit amount. def formula(person, period, parameters): weekly_payable_amount = person("ut_ui_weekly_payable_amount", period) diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_base_period_wages.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_base_period_wages.py similarity index 83% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_base_period_wages.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_base_period_wages.py index c3d46b3ca87..c74a2844cba 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_base_period_wages.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_base_period_wages.py @@ -16,3 +16,5 @@ class ut_ui_base_period_wages(Variable): # quarters) when the standard base period fails monetary eligibility. # Caller should supply the more favorable of standard or alternate base # period wages. + # Defaults to 0, so in microsimulation (where this input is not populated) + # claimants are treated as having no base-period wages and are ineligible. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_duration_weeks.py similarity index 95% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_duration_weeks.py index ff317de6e1b..e7973b08e1d 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_duration_weeks.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_duration_weeks.py @@ -10,7 +10,7 @@ class ut_ui_duration_weeks(Variable): reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html" def formula(person, period, parameters): - p = parameters(period).gov.states.ut.dwf.unemployment_insurance + p = parameters(period).gov.states.ut.dws.unemployment_insurance base_period_wages = person("ut_ui_base_period_wages", period) weekly_benefit_amount = person("ut_ui_weekly_benefit_amount", period) diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_gross_weekly_earnings.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_gross_weekly_earnings.py similarity index 83% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_gross_weekly_earnings.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_gross_weekly_earnings.py index 35707de9fa7..d11ae999cc0 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_gross_weekly_earnings.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_gross_weekly_earnings.py @@ -15,3 +15,5 @@ class ut_ui_gross_weekly_earnings(Variable): # payments are excluded from "wages" for this calculation, so the caller # is responsible for providing only countable earnings here (excluding # public assistance benefits). + # Defaults to 0, so in microsimulation (where this input is not populated) + # claimants are treated as having no earnings while claiming. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_high_quarter_wages.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_high_quarter_wages.py similarity index 78% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_high_quarter_wages.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_high_quarter_wages.py index a7795a12a14..fe666cb9d0c 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_high_quarter_wages.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_high_quarter_wages.py @@ -12,3 +12,5 @@ class ut_ui_high_quarter_wages(Variable): # Wages paid during the calendar quarter of the base period in which the # claimant's wages were highest, used to compute the weekly benefit amount # under Utah Code § 35A-4-401(2)(a)(ii). + # Defaults to 0, so in microsimulation (where this input is not populated) + # claimants are treated as having no high-quarter wages. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_maximum_benefit_amount.py similarity index 100% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_maximum_benefit_amount.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_maximum_benefit_amount.py diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_monetarily_eligible.py similarity index 74% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_monetarily_eligible.py index 348f85967ef..c421f96ae06 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_monetarily_eligible.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_monetarily_eligible.py @@ -9,18 +9,22 @@ class ut_ui_monetarily_eligible(Variable): reference = ( "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S201.html", "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S403.html", - "https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202", + "https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-201", ) + # Not modeled: § 35A-4-403(1)(f)(ii) provides an alternative to the 1.5x + # high-quarter-wage ratio test — wages in insured work for at least 20 + # weeks in the base period. That alternative sunset on or before Jan 1, + # 2011, so only the § 35A-4-403(1)(f)(i) ratio test is modeled here. def formula(person, period, parameters): - p = parameters(period).gov.states.ut.dwf.unemployment_insurance + p = parameters(period).gov.states.ut.dws.unemployment_insurance base_period_wages = person("ut_ui_base_period_wages", period) high_quarter_wages = person("ut_ui_high_quarter_wages", period) quarters_with_wages = person("ut_ui_quarters_with_wages", period) # § 35A-4-201(16): minimum total base-period wages. meets_minimum_wages = base_period_wages >= p.eligibility.min_base_period_wages - # R994-401-202: wages in at least two base-period quarters. + # R994-401-201: wages in at least two base-period quarters. meets_quarters_test = ( quarters_with_wages >= p.eligibility.min_quarters_with_wages ) diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_quarters_with_wages.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_quarters_with_wages.py similarity index 65% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_quarters_with_wages.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_quarters_with_wages.py index 8060d2f008a..a5b77a59323 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_quarters_with_wages.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_quarters_with_wages.py @@ -8,8 +8,10 @@ class ut_ui_quarters_with_wages(Variable): definition_period = YEAR default_value = 0 reference = ( - "https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-202" + "https://www.law.cornell.edu/regulations/utah/Utah-Admin-Code-R994-401-201" ) # Number of base-period calendar quarters (0-4) in which the claimant - # earned wages. Utah Admin Code R994-401-202 requires wages in at least + # earned wages. Utah Admin Code R994-401-201 requires wages in at least # two base-period quarters. + # Defaults to 0, so in microsimulation (where this input is not populated) + # claimants are treated as having wages in no base-period quarters. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_benefit_amount.py similarity index 94% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_benefit_amount.py index f3c27c7e30e..2ce4867cb78 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_benefit_amount.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_benefit_amount.py @@ -10,7 +10,7 @@ class ut_ui_weekly_benefit_amount(Variable): reference = "https://le.utah.gov/xcode/Title35A/Chapter4/35A-4-S401.html" def formula(person, period, parameters): - p = parameters(period).gov.states.ut.dwf.unemployment_insurance + p = parameters(period).gov.states.ut.dws.unemployment_insurance high_quarter_wages = person("ut_ui_high_quarter_wages", period) monetarily_eligible = person("ut_ui_monetarily_eligible", period) diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_hours_worked.py similarity index 81% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_hours_worked.py index 6ae932a4d41..57498b5803a 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_hours_worked.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_hours_worked.py @@ -13,3 +13,5 @@ class ut_ui_weekly_hours_worked(Variable): # full-time hours threshold (40 hours) in a week is not eligible for # benefits that week per Utah DWS Claimant Guide page 11 (PDF file p. 13) # and the "total unemployment" definition in Utah Code § 35A-4-207. + # Defaults to 0, so in microsimulation (where this input is not populated) + # claimants are treated as working no hours while claiming. diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_payable_amount.py similarity index 96% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_payable_amount.py index 593ea34d818..fe15a936b61 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weekly_payable_amount.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weekly_payable_amount.py @@ -13,7 +13,7 @@ class ut_ui_weekly_payable_amount(Variable): ) def formula(person, period, parameters): - p = parameters(period).gov.states.ut.dwf.unemployment_insurance + p = parameters(period).gov.states.ut.dws.unemployment_insurance weekly_benefit_amount = person("ut_ui_weekly_benefit_amount", period) gross_weekly_earnings = person("ut_ui_gross_weekly_earnings", period) weekly_hours_worked = person("ut_ui_weekly_hours_worked", period) diff --git a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weeks_unemployed.py b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weeks_unemployed.py similarity index 78% rename from policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weeks_unemployed.py rename to policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weeks_unemployed.py index eb463115674..b14a5af5b9c 100644 --- a/policyengine_us/variables/gov/states/ut/dwf/unemployment_insurance/ut_ui_weeks_unemployed.py +++ b/policyengine_us/variables/gov/states/ut/dws/unemployment_insurance/ut_ui_weeks_unemployed.py @@ -13,3 +13,5 @@ class ut_ui_weeks_unemployed(Variable): # collect) Utah Unemployment Insurance benefits. Used to convert the # weekly payable amount into an annual benefit, capped by the maximum # benefit amount per Utah Code § 35A-4-401(4)(a). + # Defaults to 0, so in microsimulation (where this input is not populated) + # claimants are treated as unemployed for no weeks, yielding a $0 benefit.