From fe7c62ebb179b7a296fcd2bb0d467b49e6a694de Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:26:58 -0400 Subject: [PATCH 1/4] Initial commit for NY Unemployment Insurance implementation Starting implementation of New York State Unemployment Insurance. Documentation and parallel development will follow. From d3ed032c0288ec52980cecdfaffce315acf8b277 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 23 Apr 2026 14:21:01 -0400 Subject: [PATCH 2/4] Implement New York Unemployment Insurance (ny_ui) (ref #8143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds NY UI benefit with formula-based WBR, 3-tier partial benefit with hours-based tiers, 3 monetary eligibility tests, and max WBR change effective 2025-10-13 ($504 → $869). Co-Authored-By: Claude Sonnet 4.6 --- .../ny-unemployment-insurance.added.md | 1 + .../benefit/low_divisor.yaml | 14 + .../benefit/low_hq_threshold.yaml | 14 + .../benefit/max_amount.yaml | 17 + .../benefit/max_weeks.yaml | 12 + .../benefit/min_amount.yaml | 15 + .../benefit/partial_benefit_credit_min.yaml | 12 + .../benefit/partial_benefit_credit_rate.yaml | 12 + .../benefit/standard_divisor.yaml | 14 + .../benefit/two_quarter_hq_threshold.yaml | 14 + .../eligibility/base_wages_multiplier.yaml | 14 + .../capped_other_quarters_rate.yaml | 14 + .../eligibility/high_quarter_cap.yaml | 14 + .../eligibility/high_quarter_minimum.yaml | 15 + .../eligibility/quarters_required.yaml | 14 + .../ny/dol/unemployment_insurance/index.yaml | 4 + .../partial/hours_tiers.yaml | 38 ++ .../unemployment_insurance/integration.yaml | 215 +++++++ .../ny/dol/unemployment_insurance/ny_ui.yaml | 129 ++++ .../ny_ui_hours_tier_rate.yaml | 188 ++++++ .../ny_ui_monetarily_eligible.yaml | 224 +++++++ .../ny_ui_partial_benefit_credit.yaml | 135 ++++ .../ny_ui_weekly_benefit_rate.yaml | 235 +++++++ .../ny_ui_weekly_payable.yaml | 133 ++++ .../ny/dol/unemployment_insurance/ny_ui.py | 23 + .../ny_ui_base_period_wages.py | 11 + .../ny_ui_gross_weekly_earnings.py | 11 + .../ny_ui_high_quarter_wages.py | 11 + .../ny_ui_hours_tier_rate.py | 14 + .../ny_ui_monetarily_eligible.py | 34 + .../ny_ui_partial_benefit_credit.py | 20 + .../ny_ui_quarters_with_wages.py | 10 + .../ny_ui_raw_weekly_benefit_rate.py | 52 ++ .../ny_ui_second_high_quarter_wages.py | 11 + .../ny_ui_weekly_benefit_rate.py | 15 + .../ny_ui_weekly_hours_worked.py | 11 + .../ny_ui_weekly_payable.py | 41 ++ .../ny_ui_weeks_unemployed.py | 11 + sources/ny-ui-impl-spec.md | 430 +++++++++++++ sources/ny-ui-requirements-checklist.md | 53 ++ sources/ny-ui-research-summary.md | 21 + sources/ny-ui-scope-summary.md | 96 +++ sources/working_references.md | 604 ++++++++++++++++++ 43 files changed, 2976 insertions(+) create mode 100644 changelog.d/ny-unemployment-insurance.added.md create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_divisor.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_hq_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_amount.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_weeks.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/min_amount.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/partial_benefit_credit_min.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/partial_benefit_credit_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/standard_divisor.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/two_quarter_hq_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/base_wages_multiplier.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/capped_other_quarters_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_cap.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_minimum.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/quarters_required.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/index.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/partial/hours_tiers.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/integration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_hours_tier_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_monetarily_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_payable.yaml create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_base_period_wages.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_gross_weekly_earnings.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_high_quarter_wages.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_hours_tier_rate.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_monetarily_eligible.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_quarters_with_wages.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_raw_weekly_benefit_rate.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_second_high_quarter_wages.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_hours_worked.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_payable.py create mode 100644 policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weeks_unemployed.py create mode 100644 sources/ny-ui-impl-spec.md create mode 100644 sources/ny-ui-requirements-checklist.md create mode 100644 sources/ny-ui-research-summary.md create mode 100644 sources/ny-ui-scope-summary.md create mode 100644 sources/working_references.md diff --git a/changelog.d/ny-unemployment-insurance.added.md b/changelog.d/ny-unemployment-insurance.added.md new file mode 100644 index 00000000000..42dadc839d6 --- /dev/null +++ b/changelog.d/ny-unemployment-insurance.added.md @@ -0,0 +1 @@ +Add New York Unemployment Insurance benefit (ny_ui). diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_divisor.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_divisor.yaml new file mode 100644 index 00000000000..a8de50c40cb --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_divisor.yaml @@ -0,0 +1,14 @@ +description: New York divides high quarter wages by this amount to compute the weekly benefit rate when high quarter wages are at or below the low threshold under the Unemployment Insurance program. + +values: + 2020-01-01: 25 + +metadata: + unit: /1 + period: year + label: New York UI low weekly benefit divisor + reference: + - title: NY Labor Law § 590(5) — Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_hq_threshold.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_hq_threshold.yaml new file mode 100644 index 00000000000..4155179c6b3 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_hq_threshold.yaml @@ -0,0 +1,14 @@ +description: New York applies the low weekly benefit divisor when high quarter wages are at or below this amount under the Unemployment Insurance program. + +values: + 2020-01-01: 3_575 + +metadata: + unit: currency-USD + period: year + label: New York UI low high quarter threshold + reference: + - title: NY Labor Law § 590(5) — Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_amount.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_amount.yaml new file mode 100644 index 00000000000..da3b153339e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_amount.yaml @@ -0,0 +1,17 @@ +description: New York sets this maximum weekly benefit rate under the Unemployment Insurance program. + +values: + 2020-01-01: 504 + 2025-10-13: 869 + +metadata: + unit: currency-USD + period: week + label: New York UI maximum weekly benefit rate + reference: + - title: NY Labor Law § 590 — Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 + - title: Governor Hochul and Labor Leaders Announce Maximum Weekly Benefit Increase for Unemployed Workers + href: https://www.governor.ny.gov/news/governor-hochul-and-labor-leaders-announce-maximum-weekly-benefit-increase-unemployed-workers + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_weeks.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_weeks.yaml new file mode 100644 index 00000000000..5efd785ff77 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_weeks.yaml @@ -0,0 +1,12 @@ +description: New York limits the duration of benefits to this many weeks within a benefit year under the Unemployment Insurance program. + +values: + 2020-01-01: 26 + +metadata: + unit: week + period: year + label: New York UI maximum benefit weeks + reference: + - title: NY Labor Law § 590 — Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/min_amount.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/min_amount.yaml new file mode 100644 index 00000000000..db999eb1de5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/min_amount.yaml @@ -0,0 +1,15 @@ +description: New York sets this minimum weekly benefit rate under the Unemployment Insurance program. + +values: + 2020-01-01: 104 + 2026-01-01: 140 + +metadata: + unit: currency-USD + period: week + label: New York UI minimum weekly benefit rate + reference: + - title: NY Labor Law § 590 — Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/partial_benefit_credit_min.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/partial_benefit_credit_min.yaml new file mode 100644 index 00000000000..1d29259e133 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/partial_benefit_credit_min.yaml @@ -0,0 +1,12 @@ +description: New York sets a floor on the partial benefit credit at this amount under the Unemployment Insurance program. + +values: + 2020-01-01: 100 + +metadata: + unit: currency-USD + period: week + label: New York UI partial benefit credit minimum + reference: + - title: NY Labor Law § 525 — Partial benefit credit + href: https://www.nysenate.gov/legislation/laws/LAB/525 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/partial_benefit_credit_rate.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/partial_benefit_credit_rate.yaml new file mode 100644 index 00000000000..c3e484fc9b7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/partial_benefit_credit_rate.yaml @@ -0,0 +1,12 @@ +description: New York sets the partial benefit credit at this share of the weekly benefit rate under the Unemployment Insurance program. + +values: + 2020-01-01: 0.5 + +metadata: + unit: /1 + period: year + label: New York UI partial benefit credit rate + reference: + - title: NY Labor Law § 525 — Partial benefit credit + href: https://www.nysenate.gov/legislation/laws/LAB/525 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/standard_divisor.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/standard_divisor.yaml new file mode 100644 index 00000000000..363b40c834f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/standard_divisor.yaml @@ -0,0 +1,14 @@ +description: New York divides high quarter wages by this amount to compute the weekly benefit rate when high quarter wages exceed the low threshold under the Unemployment Insurance program. + +values: + 2020-01-01: 26 + +metadata: + unit: /1 + period: year + label: New York UI standard weekly benefit divisor + reference: + - title: NY Labor Law § 590(5) — Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/two_quarter_hq_threshold.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/two_quarter_hq_threshold.yaml new file mode 100644 index 00000000000..2271a10e352 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/two_quarter_hq_threshold.yaml @@ -0,0 +1,14 @@ +description: New York applies the averaged two-highest-quarter weekly benefit formula when high quarter wages exceed this amount in a two or three quarter claim under the Unemployment Insurance program. + +values: + 2020-01-01: 4_000 + +metadata: + unit: currency-USD + period: year + label: New York UI two or three quarter high quarter threshold + reference: + - title: NY Labor Law § 590(5) — Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/base_wages_multiplier.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/base_wages_multiplier.yaml new file mode 100644 index 00000000000..641f96027d9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/base_wages_multiplier.yaml @@ -0,0 +1,14 @@ +description: New York requires total base period wages to be at least this multiple of high quarter wages under the Unemployment Insurance program. + +values: + 2020-01-01: 1.5 + +metadata: + unit: /1 + period: year + label: New York UI base wages multiplier + reference: + - title: NY Labor Law § 527 — Valid original claim + href: https://www.nysenate.gov/legislation/laws/LAB/527 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/capped_other_quarters_rate.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/capped_other_quarters_rate.yaml new file mode 100644 index 00000000000..1740f7a5575 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/capped_other_quarters_rate.yaml @@ -0,0 +1,14 @@ +description: New York requires other base period quarters to provide at least this share of the high quarter cap when high quarter wages reach the cap under the Unemployment Insurance program. + +values: + 2020-01-01: 0.5 + +metadata: + unit: /1 + period: year + label: New York UI capped other quarters wages share + reference: + - title: NY Labor Law § 527 — Valid original claim + href: https://www.nysenate.gov/legislation/laws/LAB/527 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_cap.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_cap.yaml new file mode 100644 index 00000000000..f68945b5617 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_cap.yaml @@ -0,0 +1,14 @@ +description: New York applies the capped wages test when high quarter wages reach this amount under the Unemployment Insurance program. + +values: + 2026-01-01: 19_118 + +metadata: + unit: currency-USD + period: year + label: New York UI high quarter cap + reference: + - title: NY Labor Law § 527 — Valid original claim + href: https://www.nysenate.gov/legislation/laws/LAB/527 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_minimum.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_minimum.yaml new file mode 100644 index 00000000000..6892ce16780 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_minimum.yaml @@ -0,0 +1,15 @@ +description: New York requires this minimum amount of wages paid in the high quarter of the base period under the Unemployment Insurance program. + +values: + 2025-01-01: 3_400 + 2026-01-05: 3_500 + +metadata: + unit: currency-USD + period: year + label: New York UI high quarter minimum wages + reference: + - title: NY Labor Law § 527 — Valid original claim + href: https://www.nysenate.gov/legislation/laws/LAB/527 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/quarters_required.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/quarters_required.yaml new file mode 100644 index 00000000000..69fa068dfc4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/quarters_required.yaml @@ -0,0 +1,14 @@ +description: New York requires wages to have been paid in at least this many calendar quarters of the base period under the Unemployment Insurance program. + +values: + 2020-01-01: 2 + +metadata: + unit: int + period: year + label: New York UI quarters required + reference: + - title: NY Labor Law § 527 — Valid original claim + href: https://www.nysenate.gov/legislation/laws/LAB/527 + - title: NYSDOL P832 (Feb 2026), page 1 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/index.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/index.yaml new file mode 100644 index 00000000000..cb39cde8a79 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/index.yaml @@ -0,0 +1,4 @@ +metadata: + propagate_metadata_to_children: true + economy: false + household: true diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/partial/hours_tiers.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/partial/hours_tiers.yaml new file mode 100644 index 00000000000..a32dc710115 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/partial/hours_tiers.yaml @@ -0,0 +1,38 @@ +description: New York pays this share of the weekly benefit rate based on hours worked in a week under the Unemployment Insurance program. + +brackets: + - threshold: + 2021-08-16: 0 + amount: + 2021-08-16: 1.0 + - threshold: + 2021-08-16: 11 + amount: + 2021-08-16: 0.75 + - threshold: + 2021-08-16: 17 + amount: + 2021-08-16: 0.5 + - threshold: + 2021-08-16: 22 + amount: + 2021-08-16: 0.25 + - threshold: + 2021-08-16: 31 + amount: + 2021-08-16: 0 + +metadata: + type: single_amount + threshold_unit: hour + amount_unit: /1 + threshold_period: week + period: week + label: New York UI partial benefit hours tier rates + reference: + - title: NY Labor Law § 523 — Total unemployment + href: https://www.nysenate.gov/legislation/laws/LAB/523 + - title: NY Labor Law § 522 — Total and partial unemployment + href: https://www.nysenate.gov/legislation/laws/LAB/522 + - title: NYSDOL P803 (Oct 2025), Partial Unemployment FAQs + href: https://dol.ny.gov/system/files/documents/2025/10/p803-partial-ui-faqs-10-3-25.pdf diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/integration.yaml new file mode 100644 index 00000000000..7bc8c1a37af --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/integration.yaml @@ -0,0 +1,215 @@ +# Integration tests for New York Unemployment Insurance (NY UI). +# End-to-end scenarios checking ny_ui together with intermediate variables. +# References: NY Lab. Law §§ 522, 525, 527, 590; NYSDOL P803 (Oct 2025), +# P832 (Feb 2026). + +- name: Case 1, standard full unemployment with 4-quarter wage history. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ny_ui_high_quarter_wages: 8_000 + ny_ui_base_period_wages: 28_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 26 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Monetarily eligible (§ 527): + # HQ $8,000 >= $3,400 (2025 minimum). + # 4 quarters >= 2 required. + # Base $28,000 >= 1.5 * $8,000 = $12,000. + ny_ui_monetarily_eligible: true + # WBR (§ 590): 4 quarters, HQ > $3,575 -> floor($8,000 / 26) = $307. + # $104 <= $307 <= $504 (2025 range) -> WBR = $307. + ny_ui_weekly_benefit_rate: 307 + # Weekly payable: 0 hours, 0 earnings -> full WBR. + ny_ui_weekly_payable: 307 + # Annual benefit: $307 * 26 weeks = $7,982; MBA = $307 * 26 = $7,982. + ny_ui: 7_982 + +- name: Case 2, P832 worked example - 2-quarter claimant in 2026. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 4_500 + ny_ui_second_high_quarter_wages: 4_288 + ny_ui_base_period_wages: 8_788 + ny_ui_quarters_with_wages: 2 + ny_ui_weeks_unemployed: 10 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Monetarily eligible: HQ $4,500 >= $3,500 (2026); 2 quarters; + # Base $8,788 >= 1.5 * $4,500 = $6,750. + ny_ui_monetarily_eligible: true + # WBR (2/3-quarter tier 1, HQ > $4,000): + # avg = ($4,500 + $4,288) / 2 = $4,394; floor($4,394 / 26) = $169. + # $140 <= $169 <= $869 -> WBR = $169. + ny_ui_weekly_benefit_rate: 169 + ny_ui_weekly_payable: 169 + # Annual benefit: $169 * 10 weeks = $1,690; MBA = $169 * 26 = $4,394. + ny_ui: 1_690 + +- name: Case 3, partial employment in 11-16 hour tier. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 35_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 4 + ny_ui_weekly_hours_worked: 13 + ny_ui_gross_weekly_earnings: 200 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Monetarily eligible: HQ $10,000; 4 qtrs; $35,000 >= 1.5 * $10,000. + ny_ui_monetarily_eligible: true + # WBR: floor($10,000 / 26) = $384. + ny_ui_weekly_benefit_rate: 384 + # PBC: max(0.5 * $384, $100) = $192. + ny_ui_partial_benefit_credit: 192 + # Hours tier: 13 hours -> 11-16 tier -> 0.75 rate. + ny_ui_hours_tier_rate: 0.75 + # Earnings $200 < $576 ($384 + $192) -> partial payment eligible. + # Partial amount = 0.75 * $384 = $288. + ny_ui_weekly_payable: 288 + # Annual benefit: $288 * 4 weeks = $1,152. + ny_ui: 1_152 + +- name: Case 4, earnings exceed max WBR - disqualified for the week. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 35_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 4 + ny_ui_weekly_hours_worked: 5 + ny_ui_gross_weekly_earnings: 600 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Monetarily eligible. + ny_ui_monetarily_eligible: true + # WBR: $384; 2025 max WBR = $504. + ny_ui_weekly_benefit_rate: 384 + # Earnings $600 > $504 (2025 max WBR) -> earnings-cap disqualified. + ny_ui_weekly_payable: 0 + # Annual benefit: $0. + ny_ui: 0 + +- name: Case 5, monetarily ineligible - high quarter wages too low. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ny_ui_high_quarter_wages: 2_000 + ny_ui_base_period_wages: 8_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 10 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $2,000 < $3,400 (2025 minimum) -> monetarily ineligible. + ny_ui_monetarily_eligible: false + ny_ui_weekly_payable: 0 + # Annual benefit: $0. + ny_ui: 0 + +- name: Case 6, high earner in 2026 capped at new $869 maximum. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + ny_ui_high_quarter_wages: 50_000 + ny_ui_base_period_wages: 150_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 26 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Monetarily eligible (capped case): HQ $50,000 >= $19,118 cap. + # Other 3 quarters = $150,000 - $50,000 = $100,000 >= $9,559. + ny_ui_monetarily_eligible: true + # WBR: floor($50,000 / 26) = $1,923; capped at $869 (2026 max). + ny_ui_weekly_benefit_rate: 869 + ny_ui_weekly_payable: 869 + # Annual benefit: $869 * 26 weeks = $22,594; MBA = $869 * 26 = $22,594. + ny_ui: 22_594 + +- name: Case 7, maximum benefit amount cap at WBR times 26 weeks. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + ny_ui_high_quarter_wages: 13_000 + ny_ui_base_period_wages: 52_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 26 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Monetarily eligible: HQ $13,000; 4 qtrs; $52,000 >= 1.5 * $13,000. + ny_ui_monetarily_eligible: true + # WBR: floor($13,000 / 26) = $500; within 2025 range ($104-$504). + ny_ui_weekly_benefit_rate: 500 + ny_ui_weekly_payable: 500 + # Annual benefit: $500 * 26 = $13,000; MBA = $500 * 26 = $13,000. + ny_ui: 13_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui.yaml new file mode 100644 index 00000000000..25ce7c39e24 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui.yaml @@ -0,0 +1,129 @@ +# Tests for New York UI annual benefit (§ 590). +# ny_ui = min(weekly_payable * weeks_unemployed, weekly_benefit_rate * 26). +# Reference: NY Lab. Law § 590. + +- name: Case 1, boundary - 26 weeks unemployed yields full MBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 30_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 26 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # WBR = floor($10,000 / 26) = $384. + # Weekly payable = $384 (no hours, no earnings). + # Annual = $384 * 26 = $9,984; MBA = $384 * 26 = $9,984. + ny_ui_weekly_benefit_rate: 384 + ny_ui: 9_984 + +- name: Case 2, boundary - 0 weeks unemployed yields zero annual benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 30_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 0 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Annual = $384 * 0 = $0; MBA cap does not bind. + ny_ui_weekly_benefit_rate: 384 + ny_ui: 0 + +- name: Case 3, boundary - 27 weeks capped at MBA (26 * WBR). + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 30_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 27 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # WBR = $384. + # Annual uncapped = $384 * 27 = $10,368. + # MBA = $384 * 26 = $9,984; min($10,368, $9,984) = $9,984. + ny_ui_weekly_benefit_rate: 384 + ny_ui: 9_984 + +- name: Case 4, max WBR boundary - HQ $20,000 in 2025 capped at $504. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ny_ui_high_quarter_wages: 20_000 + ny_ui_base_period_wages: 60_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 26 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # floor($20,000 / 26) = $769; capped at 2025 max $504. + ny_ui_weekly_benefit_rate: 504 + # Annual = $504 * 26 = $13,104; MBA = $504 * 26 = $13,104. + ny_ui: 13_104 + +- name: Case 5, max WBR boundary - HQ $20,000 in 2026 capped at $869. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ny_ui_high_quarter_wages: 20_000 + ny_ui_base_period_wages: 60_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weeks_unemployed: 26 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # floor($20,000 / 26) = $769; within 2026 range ($140-$869) -> $769. + ny_ui_weekly_benefit_rate: 769 + # Annual = $769 * 26 = $19,994; MBA = $769 * 26 = $19,994. + ny_ui: 19_994 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_hours_tier_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_hours_tier_rate.yaml new file mode 100644 index 00000000000..6cce1f271e4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_hours_tier_rate.yaml @@ -0,0 +1,188 @@ +# Tests for New York UI partial benefit hours tier rate (effective 2021-08-16). +# Hours-based reduction bracket: +# 0-10 hours -> 100% (rate 1.00) +# 11-16 hours -> 75% (rate 0.75) +# 17-21 hours -> 50% (rate 0.50) +# 22-30 hours -> 25% (rate 0.25) +# 31+ hours -> 0% (rate 0.00) +# Reference: NY Lab. Law § 522; NYSDOL P803 (Oct 2025). + +- name: Case 1, 5 hours worked - tier 1 (0-10), full weekly benefit. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 5 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 5 hours falls in the 0-10 tier -> 100% of WBR. + ny_ui_hours_tier_rate: 1.0 + +- name: Case 2, 13 hours worked - tier 2 (11-16), 75 percent of WBR. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 13 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 13 hours falls in the 11-16 tier -> 75% of WBR. + ny_ui_hours_tier_rate: 0.75 + +- name: Case 3, 19 hours worked - tier 3 (17-21), 50 percent of WBR. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 19 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 19 hours falls in the 17-21 tier -> 50% of WBR. + ny_ui_hours_tier_rate: 0.5 + +- name: Case 4, 25 hours worked - tier 4 (22-30), 25 percent of WBR. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 25 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 25 hours falls in the 22-30 tier -> 25% of WBR. + ny_ui_hours_tier_rate: 0.25 + +- name: Case 5, 35 hours worked - tier 5 (31+), no weekly benefit. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 35 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 35 hours falls in the 31+ tier -> 0% of WBR. + ny_ui_hours_tier_rate: 0.0 + +- name: Case 6, boundary - 10 hours is the top of tier 1, full rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 10 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 10 hours is below the tier-2 threshold of 11 -> full rate 1.0. + ny_ui_hours_tier_rate: 1.0 + +- name: Case 7, boundary - 11 hours is the bottom of tier 2, 75 percent rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 11 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 11 hours meets tier-2 threshold -> 0.75 rate. + ny_ui_hours_tier_rate: 0.75 + +- name: Case 8, boundary - 30 hours is the top of tier 4, 25 percent rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 30 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 30 hours is below the tier-5 threshold of 31 -> 0.25 rate. + ny_ui_hours_tier_rate: 0.25 + +- name: Case 9, boundary - 31 hours is the bottom of tier 5, no rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 31 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 31 hours meets tier-5 threshold -> 0.0 rate. + ny_ui_hours_tier_rate: 0.0 + +- name: Case 10, boundary - zero hours worked, full rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + ny_ui_weekly_hours_worked: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 0 hours falls in tier 1 (0-10) -> full rate 1.0. + ny_ui_hours_tier_rate: 1.0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_monetarily_eligible.yaml new file mode 100644 index 00000000000..7af2a7a6ec8 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_monetarily_eligible.yaml @@ -0,0 +1,224 @@ +# Tests for New York UI monetary eligibility (§ 527). +# A claimant is monetarily eligible only if ALL THREE base-period tests pass: +# 1. High-quarter wages >= statutory minimum ($3,400 in 2025; $3,500 from 2026-01-05). +# 2. Wages paid in at least 2 calendar quarters of the base period. +# 3. Total base-period wages >= 1.5 x high-quarter wages (standard case) +# OR other 3 quarters >= $9,559 when HQ >= $19,118 (capped case). +# Reference: NY Lab. Law § 527; NYSDOL P832 (Feb 2026). + +- name: Case 1, fully eligible - all three tests pass. + period: 2025 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 5_000 + ny_ui_base_period_wages: 10_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $5,000 >= $3,400 (2025 minimum). + # 4 quarters >= 2 required. + # Base $10,000 >= 1.5 * $5,000 = $7,500 -> standard test passes. + ny_ui_monetarily_eligible: true + +- name: Case 2, high quarter too low - fails high-quarter minimum test. + period: 2025 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_000 + ny_ui_base_period_wages: 10_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $3,000 < $3,400 (2025 minimum) -> fails test 1. + ny_ui_monetarily_eligible: false + +- name: Case 3, too few quarters - fails 2-quarter test. + period: 2025 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 5_000 + ny_ui_base_period_wages: 10_000 + ny_ui_quarters_with_wages: 1 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Only 1 quarter with wages < 2 required -> fails test 2. + ny_ui_monetarily_eligible: false + +- name: Case 4, fails 1.5x total-wages test. + period: 2025 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 5_000 + ny_ui_base_period_wages: 6_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Base $6,000 < 1.5 * $5,000 = $7,500 -> fails test 3. + ny_ui_monetarily_eligible: false + +- name: Case 5, boundary - HQ one dollar below 2025 minimum fails test 1. + period: 2025 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_399 + ny_ui_base_period_wages: 15_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $3,399 < $3,400 (2025 minimum) -> fails test 1. + ny_ui_monetarily_eligible: false + +- name: Case 6, boundary - HQ exactly at 2025 minimum passes test 1. + period: 2025 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_400 + ny_ui_base_period_wages: 15_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $3,400 >= $3,400 (2025 minimum) -> test 1 passes (uses >=). + # Base $15,000 >= 1.5 * $3,400 = $5,100 -> test 3 passes. + ny_ui_monetarily_eligible: true + +- name: Case 7, boundary - HQ exactly at 2026 minimum passes test 1. + period: 2026 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_500 + ny_ui_base_period_wages: 15_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $3,500 >= $3,500 (2026 minimum) -> test 1 passes. + # Base $15,000 >= 1.5 * $3,500 = $5,250 -> test 3 passes. + ny_ui_monetarily_eligible: true + +- name: Case 8, boundary - base wages one dollar below 1.5x HQ fails test 3. + period: 2025 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 6_000 + ny_ui_base_period_wages: 8_999 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Base $8,999 < 1.5 * $6,000 = $9,000 -> fails test 3 (uses >=). + ny_ui_monetarily_eligible: false + +- name: Case 9, boundary - base wages exactly at 1.5x HQ passes test 3. + period: 2025 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 6_000 + ny_ui_base_period_wages: 9_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Base $9,000 >= 1.5 * $6,000 = $9,000 -> test 3 passes (uses >=). + ny_ui_monetarily_eligible: true + +- name: Case 10, capped-case boundary - other 3 quarters one dollar below half of cap. + period: 2026 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 19_118 + # Other 3 quarters total = $28,676 - $19,118 = $9,558. + ny_ui_base_period_wages: 28_676 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $19,118 >= cap $19,118 -> capped test applies. + # Other 3 qtrs = $9,558 < 0.5 * $19,118 = $9,559 -> fails capped test. + ny_ui_monetarily_eligible: false + +- name: Case 11, capped-case boundary - other 3 quarters exactly at half of cap. + period: 2026 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 19_118 + # Other 3 quarters total = $28,677 - $19,118 = $9,559. + ny_ui_base_period_wages: 28_677 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $19,118 >= cap $19,118 -> capped test applies. + # Other 3 qtrs = $9,559 >= 0.5 * $19,118 = $9,559 -> passes capped test. + ny_ui_monetarily_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.yaml new file mode 100644 index 00000000000..b545f135600 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.yaml @@ -0,0 +1,135 @@ +# Tests for New York UI partial benefit credit (§ 525). +# Formula: PBC = ceil(max(0.50 * WBR, $100)). +# Reference: NY Lab. Law § 525. + +- name: Case 1, WBR $300 - 50 percent of WBR exceeds the $100 floor. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # WBR derived from HQ: floor($7,800 / 26) = $300. + ny_ui_high_quarter_wages: 7_800 + ny_ui_base_period_wages: 23_400 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + ny_ui_weekly_benefit_rate: 300 + # 0.5 * $300 = $150; max($150, $100) = $150. + ny_ui_partial_benefit_credit: 150 + +- name: Case 2, WBR $180 - 50 percent of WBR is below the $100 floor, floor applies. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # WBR derived from HQ: floor($4,680 / 26) = $180. + ny_ui_high_quarter_wages: 4_680 + ny_ui_base_period_wages: 14_040 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + ny_ui_weekly_benefit_rate: 180 + # 0.5 * $180 = $90; max($90, $100) = $100. + ny_ui_partial_benefit_credit: 100 + +- name: Case 3, WBR $504 (pre-Oct-2025 cap) - 50 percent of WBR is $252. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + # WBR capped at $504 (2025 maximum) regardless of HQ above $13,104. + ny_ui_high_quarter_wages: 50_000 + ny_ui_base_period_wages: 150_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + ny_ui_weekly_benefit_rate: 504 + # 0.5 * $504 = $252; max($252, $100) = $252. + ny_ui_partial_benefit_credit: 252 + +- name: Case 4, boundary - WBR $200 yields PBC exactly at floor. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # WBR from HQ $5,200: floor($5,200 / 26) = $200. + ny_ui_high_quarter_wages: 5_200 + ny_ui_base_period_wages: 15_600 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + ny_ui_weekly_benefit_rate: 200 + # 0.5 * $200 = $100; max($100, $100) = $100 (floor equals rate-based). + ny_ui_partial_benefit_credit: 100 + +- name: Case 5, boundary - low WBR $140 triggers $100 floor. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # WBR from HQ $3,600: floor($3,600 / 26) = $138 -> lifted to $140 min. + ny_ui_high_quarter_wages: 3_600 + ny_ui_base_period_wages: 12_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + ny_ui_weekly_benefit_rate: 140 + # 0.5 * $140 = $70; max($70, $100) = $100 (floor applies). + ny_ui_partial_benefit_credit: 100 + +- name: Case 6, odd WBR $307 - ceil rounds 0.50 * WBR up to nearest dollar. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # WBR from HQ $7,982: floor($7,982 / 26) = $307. + ny_ui_high_quarter_wages: 7_982 + ny_ui_base_period_wages: 23_946 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + ny_ui_weekly_benefit_rate: 307 + # 0.5 * $307 = $153.50; ceil($153.50) = $154; max($154, $100) = $154. + ny_ui_partial_benefit_credit: 154 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.yaml new file mode 100644 index 00000000000..8b7743c8561 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.yaml @@ -0,0 +1,235 @@ +# Tests for New York UI weekly benefit rate (§ 590(5)). +# Standard 4-quarter formula: +# HQ > $3,575 -> WBR_raw = floor(HQ / 26) +# HQ <= $3,575 -> WBR_raw = floor(HQ / 25) +# 2-or-3-quarter formula: +# HQ > $4,000 -> WBR_raw = floor(avg of 2 highest quarters / 26) +# $3,576 <= HQ <= $4,000 -> WBR_raw = floor(HQ / 26) +# HQ <= $3,575 -> WBR_raw = floor(HQ / 25) +# Final WBR = min(max(WBR_raw, min_amount), max_amount). +# min_amount: $104 (2020-), $140 (2026-01-01). +# max_amount: $504 (2020-), $869 (2025-10-13). +# Reference: NY Lab. Law § 590(5); NYSDOL P832 (Feb 2026). + +- name: Case 1, P832 worked example - 2-quarter case with HQ > $4,000. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 4_500 + ny_ui_second_high_quarter_wages: 4_288 + ny_ui_base_period_wages: 8_788 + ny_ui_quarters_with_wages: 2 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 2 quarters, HQ $4,500 > $4,000 -> tier 1. + # avg = ($4,500 + $4,288) / 2 = $4,394. + # $4,394 / 26 = $169.00; floor = $169. + # $140 <= $169 <= $869 -> WBR = $169. + ny_ui_weekly_benefit_rate: 169 + +- name: Case 2, 4-quarter case with HQ above $3,575 uses divisor 26. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 28_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 4 quarters, HQ $10,000 > $3,575 -> divisor 26. + # $10,000 / 26 = $384.615; floor = $384. + # $104 <= $384 <= $504 -> WBR = $384. + ny_ui_weekly_benefit_rate: 384 + +- name: Case 3, 4-quarter case with HQ at or below $3,575 uses divisor 25; floor lifted by 2026 minimum. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_000 + ny_ui_base_period_wages: 9_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 4 quarters, HQ $3,000 <= $3,575 -> divisor 25. + # $3,000 / 25 = $120; floor = $120. + # $120 < $140 (2026 minimum) -> WBR lifted to $140. + ny_ui_weekly_benefit_rate: 140 + +- name: Case 4, 4-quarter case with HQ at or below $3,575 in 2025 uses pre-2026 minimum. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_000 + ny_ui_base_period_wages: 9_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 4 quarters, HQ $3,000 <= $3,575 -> divisor 25. + # $3,000 / 25 = $120; floor = $120. + # $120 >= $104 (2025 minimum) -> WBR = $120. + ny_ui_weekly_benefit_rate: 120 + +- name: Case 5, high earner capped at pre-Oct-2025 maximum of $504. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ny_ui_high_quarter_wages: 50_000 + ny_ui_base_period_wages: 150_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 4 quarters, HQ $50,000 > $3,575 -> divisor 26. + # $50,000 / 26 = $1,923.08; floor = $1,923. + # $1,923 capped at $504 (2025 maximum) -> WBR = $504. + ny_ui_weekly_benefit_rate: 504 + +- name: Case 6, high earner in 2026 capped at new maximum of $869. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ny_ui_high_quarter_wages: 50_000 + ny_ui_base_period_wages: 150_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 4 quarters, HQ $50,000 > $3,575 -> divisor 26. + # $50,000 / 26 = $1,923.08; floor = $1,923. + # $1,923 capped at $869 (effective 2025-10-13) -> WBR = $869. + ny_ui_weekly_benefit_rate: 869 + +- name: Case 7, boundary - HQ exactly at low threshold uses low divisor 25. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_575 + ny_ui_base_period_wages: 15_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $3,575 > $3,575 is FALSE -> divisor 25. + # floor($3,575 / 25) = $143. + # $104 <= $143 <= $504 -> WBR = $143. + ny_ui_weekly_benefit_rate: 143 + +- name: Case 8, boundary - HQ one dollar above low threshold switches to standard divisor 26. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_576 + ny_ui_base_period_wages: 15_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $3,576 > $3,575 TRUE -> standard divisor 26. + # floor($3,576 / 26) = 137. + # $104 <= $137 <= $504 -> WBR = $137. + ny_ui_weekly_benefit_rate: 137 + +- name: Case 9, boundary - HQ one dollar above low threshold in 2026, lifted by new minimum. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 3_576 + ny_ui_base_period_wages: 15_000 + ny_ui_quarters_with_wages: 4 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $3,576 > $3,575 -> standard divisor 26. + # floor($3,576 / 26) = 137. + # $137 < $140 (2026 minimum) -> lifted to $140. + ny_ui_weekly_benefit_rate: 140 + +- name: Case 10, 2/3-quarter tier 2 boundary - HQ exactly at tier-2 upper threshold uses divisor 26. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 4_000 + ny_ui_second_high_quarter_wages: 3_000 + ny_ui_base_period_wages: 7_000 + ny_ui_quarters_with_wages: 2 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 2 quarters; HQ $4,000 > $4,000 is FALSE, $4,000 > $3,575 TRUE -> tier 2. + # floor($4,000 / 26) = $153. + # $104 <= $153 <= $504 -> WBR = $153. + ny_ui_weekly_benefit_rate: 153 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_payable.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_payable.yaml new file mode 100644 index 00000000000..a6a8298630a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_payable.yaml @@ -0,0 +1,133 @@ +# Tests for New York UI weekly payable amount. +# Combines weekly benefit rate with: +# - Earnings cap: gross earnings > max WBR -> $0 for the week (P803). +# - Hours-tier reduction: fraction of WBR based on weekly hours worked. +# - Partial employment test: gross earnings < WBR + PBC to be "unemployed". +# References: NY Lab. Law § 522, § 525, § 590; NYSDOL P803. + +- name: Case 1, fully unemployed and monetarily eligible - full WBR paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 28_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # Monetarily eligible (HQ >= $3,400; 4 qtrs; $28,000 >= 1.5 * $10,000). + ny_ui_monetarily_eligible: true + # WBR = floor($10,000 / 26) = $384. + ny_ui_weekly_benefit_rate: 384 + # 0 hours, 0 earnings -> full WBR payable. + ny_ui_weekly_payable: 384 + +- name: Case 2, partial employment in 11-16 hour tier - 75 percent of WBR paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 28_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weekly_hours_worked: 13 + ny_ui_gross_weekly_earnings: 200 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # WBR = $384; PBC = max(0.5 * $384, $100) = $192. + # Earnings $200 <= max WBR ($504) -> not earnings-cap disqualified. + # Earnings $200 < $384 + $192 = $576 -> partial payment eligible. + # 13 hours -> tier 2, 75% of WBR. + # Partial amount = 0.75 * $384 = $288. + ny_ui_weekly_benefit_rate: 384 + ny_ui_partial_benefit_credit: 192 + ny_ui_weekly_payable: 288 + +- name: Case 3, earnings exceed max WBR - no benefit for the week. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 28_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weekly_hours_worked: 5 + ny_ui_gross_weekly_earnings: 870 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # 2026 max WBR = $869. + # Earnings $870 > $869 -> earnings-cap disqualified -> $0. + ny_ui_weekly_payable: 0 + +- name: Case 4, partial earnings above WBR + PBC - not partially employed, no benefit. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 10_000 + ny_ui_base_period_wages: 28_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weekly_hours_worked: 5 + ny_ui_gross_weekly_earnings: 600 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # WBR = $384; PBC = $192; threshold = $576. + # 2026 max WBR = $869; earnings $600 <= $869 so not cap-disqualified. + # Earnings $600 >= $576 -> not partially employed per § 522. + # Claimant does not qualify for any weekly payment. + ny_ui_weekly_benefit_rate: 384 + ny_ui_partial_benefit_credit: 192 + ny_ui_weekly_payable: 0 + +- name: Case 5, monetarily ineligible - no weekly payment regardless of hours. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + ny_ui_high_quarter_wages: 1_000 + ny_ui_base_period_wages: 3_000 + ny_ui_quarters_with_wages: 4 + ny_ui_weekly_hours_worked: 0 + ny_ui_gross_weekly_earnings: 0 + households: + household: + members: [person1] + state_code: NY + output: + people: + person1: + # HQ $1,000 < $3,400 (2025 minimum) -> monetarily ineligible. + ny_ui_monetarily_eligible: false + ny_ui_weekly_payable: 0 diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui.py new file mode 100644 index 00000000000..2508dc23070 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ny_ui(Variable): + value_type = float + entity = Person + label = "New York Unemployment Insurance" + unit = USD + definition_period = YEAR + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" + defined_for = StateCode.NY + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.dol.unemployment_insurance.benefit + weekly_benefit_rate = person("ny_ui_weekly_benefit_rate", period) + weekly_payable = person("ny_ui_weekly_payable", period) + weeks_unemployed = person("ny_ui_weeks_unemployed", period) + + # Maximum benefit amount caps total benefits at the weekly rate times + # the maximum benefit weeks within the benefit year (§ 590). + maximum_benefit_amount = weekly_benefit_rate * p.max_weeks + annual_benefit = weekly_payable * weeks_unemployed + return min_(annual_benefit, maximum_benefit_amount) diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_base_period_wages.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_base_period_wages.py new file mode 100644 index 00000000000..de5fd73d2ce --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_base_period_wages.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ny_ui_base_period_wages(Variable): + value_type = float + entity = Person + label = "NY UI base period wages" + unit = USD + definition_period = YEAR + default_value = 0 + reference = "https://www.nysenate.gov/legislation/laws/LAB/527" diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_gross_weekly_earnings.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_gross_weekly_earnings.py new file mode 100644 index 00000000000..58c4187f05e --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_gross_weekly_earnings.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ny_ui_gross_weekly_earnings(Variable): + value_type = float + entity = Person + label = "NY UI gross weekly earnings" + unit = USD + definition_period = YEAR + default_value = 0 + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_high_quarter_wages.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_high_quarter_wages.py new file mode 100644 index 00000000000..01d90521f56 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_high_quarter_wages.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ny_ui_high_quarter_wages(Variable): + value_type = float + entity = Person + label = "NY UI high quarter wages" + unit = USD + definition_period = YEAR + default_value = 0 + reference = "https://www.nysenate.gov/legislation/laws/LAB/527" diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_hours_tier_rate.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_hours_tier_rate.py new file mode 100644 index 00000000000..88480f44c34 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_hours_tier_rate.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class ny_ui_hours_tier_rate(Variable): + value_type = float + entity = Person + label = "NY UI hours tier rate" + definition_period = YEAR + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.dol.unemployment_insurance + weekly_hours_worked = person("ny_ui_weekly_hours_worked", period) + return p.partial.hours_tiers.calc(weekly_hours_worked) diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_monetarily_eligible.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_monetarily_eligible.py new file mode 100644 index 00000000000..407f222fb96 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_monetarily_eligible.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class ny_ui_monetarily_eligible(Variable): + value_type = bool + entity = Person + label = "Monetarily eligible for New York Unemployment Insurance" + definition_period = YEAR + reference = "https://www.nysenate.gov/legislation/laws/LAB/527" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.dol.unemployment_insurance + high_quarter_wages = person("ny_ui_high_quarter_wages", period) + base_period_wages = person("ny_ui_base_period_wages", period) + quarters_with_wages = person("ny_ui_quarters_with_wages", period) + + meets_high_quarter_minimum = ( + high_quarter_wages >= p.eligibility.high_quarter_minimum + ) + meets_quarters_test = quarters_with_wages >= p.eligibility.quarters_required + meets_standard_wages_test = ( + base_period_wages + >= p.eligibility.base_wages_multiplier * high_quarter_wages + ) + other_quarters_wages = base_period_wages - high_quarter_wages + meets_capped_wages_test = other_quarters_wages >= ( + p.eligibility.capped_other_quarters_rate * p.eligibility.high_quarter_cap + ) + meets_wages_test = where( + high_quarter_wages >= p.eligibility.high_quarter_cap, + meets_capped_wages_test, + meets_standard_wages_test, + ) + return meets_high_quarter_minimum & meets_quarters_test & meets_wages_test diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.py new file mode 100644 index 00000000000..57538c79e7d --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class ny_ui_partial_benefit_credit(Variable): + value_type = float + entity = Person + label = "NY UI partial benefit credit" + unit = USD + definition_period = YEAR + reference = "https://www.nysenate.gov/legislation/laws/LAB/525" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.dol.unemployment_insurance.benefit + weekly_benefit_rate = person("ny_ui_weekly_benefit_rate", period) + return np.ceil( + max_( + p.partial_benefit_credit_rate * weekly_benefit_rate, + p.partial_benefit_credit_min, + ) + ) diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_quarters_with_wages.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_quarters_with_wages.py new file mode 100644 index 00000000000..50bf2fae249 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_quarters_with_wages.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class ny_ui_quarters_with_wages(Variable): + value_type = int + entity = Person + label = "NY UI quarters with wages" + definition_period = YEAR + default_value = 0 + reference = "https://www.nysenate.gov/legislation/laws/LAB/527" diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_raw_weekly_benefit_rate.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_raw_weekly_benefit_rate.py new file mode 100644 index 00000000000..74d47f92686 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_raw_weekly_benefit_rate.py @@ -0,0 +1,52 @@ +from policyengine_us.model_api import * + + +class ny_ui_raw_weekly_benefit_rate(Variable): + value_type = float + entity = Person + label = "NY UI raw weekly benefit rate" + unit = USD + definition_period = YEAR + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.dol.unemployment_insurance.benefit + high_quarter_wages = person("ny_ui_high_quarter_wages", period) + second_high_quarter_wages = person("ny_ui_second_high_quarter_wages", period) + quarters_with_wages = person("ny_ui_quarters_with_wages", period) + + four_quarter_case = quarters_with_wages >= 4 + + # Four-quarter formula: high quarter wages divided by the standard + # divisor (or the low divisor when wages are at or below the low + # threshold). + divisor_four_quarter = where( + high_quarter_wages > p.low_hq_threshold, + p.standard_divisor, + p.low_divisor, + ) + raw_four_quarter = np.floor(high_quarter_wages / divisor_four_quarter) + + # Two- or three-quarter formula has three tiers: + # Tier 1: high quarter wages above two-quarter threshold ($4,000) → + # average of two highest quarters divided by standard divisor. + # Tier 2: high quarter wages above low threshold ($3,575) but at or + # below two-quarter threshold → high quarter wages / standard + # divisor. + # Tier 3: high quarter wages at or below low threshold → high + # quarter wages / low divisor. + average_two_quarters = (high_quarter_wages + second_high_quarter_wages) / 2 + raw_two_three_tier_1 = np.floor(average_two_quarters / p.standard_divisor) + raw_two_three_tier_2 = np.floor(high_quarter_wages / p.standard_divisor) + raw_two_three_tier_3 = np.floor(high_quarter_wages / p.low_divisor) + + raw_two_three_quarter = select( + [ + high_quarter_wages > p.two_quarter_hq_threshold, + high_quarter_wages > p.low_hq_threshold, + ], + [raw_two_three_tier_1, raw_two_three_tier_2], + default=raw_two_three_tier_3, + ) + + return where(four_quarter_case, raw_four_quarter, raw_two_three_quarter) diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_second_high_quarter_wages.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_second_high_quarter_wages.py new file mode 100644 index 00000000000..9fe338c99df --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_second_high_quarter_wages.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ny_ui_second_high_quarter_wages(Variable): + value_type = float + entity = Person + label = "NY UI second high quarter wages" + unit = USD + definition_period = YEAR + default_value = 0 + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.py new file mode 100644 index 00000000000..169f9f34032 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class ny_ui_weekly_benefit_rate(Variable): + value_type = float + entity = Person + label = "NY UI weekly benefit rate" + unit = USD + definition_period = YEAR + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.dol.unemployment_insurance.benefit + raw_weekly_benefit_rate = person("ny_ui_raw_weekly_benefit_rate", period) + return min_(max_(raw_weekly_benefit_rate, p.min_amount), p.max_amount) diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_hours_worked.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_hours_worked.py new file mode 100644 index 00000000000..18741429f13 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_hours_worked.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ny_ui_weekly_hours_worked(Variable): + value_type = float + entity = Person + label = "NY UI weekly hours worked" + unit = "hour" + definition_period = YEAR + default_value = 0 + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_payable.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_payable.py new file mode 100644 index 00000000000..afbd02f748a --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_payable.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * + + +class ny_ui_weekly_payable(Variable): + value_type = float + entity = Person + label = "NY UI weekly payable amount" + unit = USD + definition_period = YEAR + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.dol.unemployment_insurance.benefit + weekly_benefit_rate = person("ny_ui_weekly_benefit_rate", period) + partial_benefit_credit = person("ny_ui_partial_benefit_credit", period) + gross_weekly_earnings = person("ny_ui_gross_weekly_earnings", period) + weekly_hours_worked = person("ny_ui_weekly_hours_worked", period) + hours_tier_rate = person("ny_ui_hours_tier_rate", period) + monetarily_eligible = person("ny_ui_monetarily_eligible", period) + + earnings_cap_disqualified = gross_weekly_earnings > p.max_amount + partially_employed = (weekly_hours_worked > 0) & ~earnings_cap_disqualified + partial_payment_eligible = gross_weekly_earnings < ( + weekly_benefit_rate + partial_benefit_credit + ) + partial_amount = hours_tier_rate * weekly_benefit_rate + + amount = select( + [ + earnings_cap_disqualified, + partially_employed & partial_payment_eligible, + partially_employed & ~partial_payment_eligible, + ], + [ + 0, + partial_amount, + 0, + ], + default=weekly_benefit_rate, + ) + return amount * monetarily_eligible diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weeks_unemployed.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weeks_unemployed.py new file mode 100644 index 00000000000..9f56eaef320 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_weeks_unemployed.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ny_ui_weeks_unemployed(Variable): + value_type = int + entity = Person + label = "NY UI weeks unemployed" + unit = "week" + definition_period = YEAR + default_value = 0 + reference = "https://www.nysenate.gov/legislation/laws/LAB/590" diff --git a/sources/ny-ui-impl-spec.md b/sources/ny-ui-impl-spec.md new file mode 100644 index 00000000000..84c1fae29ae --- /dev/null +++ b/sources/ny-ui-impl-spec.md @@ -0,0 +1,430 @@ +# NY UI Implementation Specification + +**Program**: New York State Unemployment Insurance (UI) +**Administering Agency**: New York State Department of Labor (NYSDOL) +**Statutory Authority**: NY Labor Law Article 18, §§ 500–603 +**Variable Prefix**: `ny_ui` +**Spec Date**: 2026-04-23 +**Status**: Pre-implementation spec — no code exists yet + +--- + +## Discovered Reference Implementations + +| Implementation | Branch / Location | Key Files | +|---|---|---| +| PA UC (Pennsylvania Unemployment Compensation) | `.claude/worktrees/pa-unemployment-insurance` | `pa/dli/unemployment_compensation/` — 20 variables | +| WA PFML (Washington Paid Family and Medical Leave) | Current branch `issue-8136-wa-pfml` | `wa/pfml/` (empty on current branch; prior commits) | +| Federal `unemployment_compensation` stub | `policyengine_us/variables/gov/states/unemployment_compensation.py` | Input stub, no formula | + +**Primary reference**: PA UC (`pa-unemployment-insurance` worktree) — closest structural analog with high-quarter wages test, credit-weeks test, partial benefit credit, WBR floor/cap, and weeks-unemployed input pattern. + +--- + +## Source Citations + +All requirements below are cross-referenced against these primary sources: + +| ID | Source | URL | +|---|---|---| +| S1 | NY Lab. Law § 590 — Rights to benefits | https://www.nysenate.gov/legislation/laws/LAB/590 | +| S2 | NY Lab. Law § 527 — Valid original claim | https://www.nysenate.gov/legislation/laws/LAB/527 | +| S3 | NY Lab. Law § 525 — Partial benefit credit | https://www.nysenate.gov/legislation/laws/LAB/525 | +| S4 | NY Lab. Law § 522 — Total and partial unemployment | https://www.nysenate.gov/legislation/laws/LAB/522 | +| S5 | NY Lab. Law § 524 — Base period | https://www.nysenate.gov/legislation/laws/LAB/524 | +| S6 | P832 (NYSDOL, Feb 2026) — How Your Weekly UI Benefit Payment Is Calculated | User-supplied PDF: p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf | +| S7 | P803 (NYSDOL, Oct 2025) — Partial Unemployment FAQs | User-supplied PDF: p803-partial-ui-faqs-10-3-25.pdf | +| S8 | Governor Hochul announcement — Max benefit increase to $869 | https://www.governor.ny.gov/news/governor-hochul-and-labor-leaders-announce-maximum-weekly-benefit-increase-unemployed-workers | + +--- + +## Citation Discrepancies Found + +Two values differ between the earlier working notes and the authoritative P832 (Feb 2026) document: + +1. **High-quarter cap for 1.5x test**: Working notes cited $11,088 (possibly a 2024 figure). P832 Feb 2026 states $19,118 as the cap above which the 1.5x rule is replaced by a flat $9,559 requirement in other quarters. Use P832 value. + +2. **Minimum WBR**: Working notes cited $104. P832 Feb 2026 states $140 as the minimum as of January 2026 (and likely $143 for 4-quarter cases based on formulaic structure; P832 says $143 specifically for the >$3,575 / 4-quarter case). Use $140 as the general statutory floor, noting $143 appears in P832 as a practical floor for the 4-quarter formula. + +3. **Partial benefit earnings cap**: P803 (Oct 2025) cites $869 as the gross earnings cap — consistent with the new max WBR effective 2025-10-13. Earlier working notes also cite $869, which is correct. + +4. **2-or-3-quarter formula**: P832 (Feb 2026) adds a third tier not present in working notes: + - HQ > $4,000: avg of 2 highest / 26 (min $143) + - $3,576–$4,000: HQ / 26 (min $143) + - ≤ $3,575: HQ / 25 + The working_references.md simplified this to "avg of 2 highest / 26" for all 2/3-quarter cases. The P832 version is authoritative. + +--- + +## Existing Variables to Reuse + +| Variable | File | Notes | +|---|---|---| +| `employment_income` | `policyengine_us/variables/input/employment_income.py` | Annual wages — approximation basis for quarterly estimates | +| `employment_income_last_year` | `policyengine_us/variables/household/income/person/employment_income_last_year.py` | Prior-year wages for base-period approximation | +| `weekly_hours_worked` | `policyengine_us/variables/household/income/person/weekly_hours_worked.py` | Average weekly hours — for partial benefit tier lookup | +| `hours_worked_last_week` | `policyengine_us/variables/household/income/person/hours_worked_last_week.py` | Point-in-time hours — alternative to weekly_hours_worked | +| `unemployment_compensation` | `policyengine_us/variables/gov/states/unemployment_compensation.py` | Federal stub — ny_ui should feed into this | +| `self_employment_income` | `policyengine_us/variables/input/self_employment_income.py` | Needed to exclude from gross-earnings cap check | + +**PA UC variables as structural patterns** (not reused directly — NY-specific equivalents needed): + +| PA UC Variable | NY UI Equivalent | Notes | +|---|---|---| +| `pa_uc_highest_quarter_wages` | `ny_ui_high_quarter_wages` | Input variable, no formula | +| `pa_uc_base_year_wages` | `ny_ui_base_period_wages` | Sum of all 4 quarters | +| `pa_uc_weekly_benefit_rate` | `ny_ui_weekly_benefit_rate` | Formula differs significantly | +| `pa_uc_partial_benefit_credit` | `ny_ui_partial_benefit_credit` | Formula differs (50% vs 30%) | +| `pa_uc_gross_weekly_earnings` | `ny_ui_gross_weekly_earnings` | Input variable, no formula | +| `pa_uc_weeks_unemployed` | `ny_ui_weeks_unemployed` | Input variable, no formula | +| `pa_uc_monetarily_eligible` | `ny_ui_monetarily_eligible` | Logic differs | +| `pa_uc` | `ny_ui` | Top-level benefit variable | + +--- + +## Requirements + +### Base Period + +**REQ-001** [INCOME] Define standard base period as first 4 of last 5 completed calendar quarters before the quarter in which the claim is filed. +- Source: S5 (§ 524), S6 (P832 "Understanding your base period") + +**REQ-002** [INCOME] Define alternate base period as last 4 completed calendar quarters before the quarter of filing. +- Source: S5 (§ 524), S6 (P832 "Two types of base periods") +- Note: Claimant may elect alternate if standard period fails the monetary tests. PolicyEngine simplification: treat as an input flag or use whichever yields higher benefit (approximation acceptable). + +**REQ-003** [INCOME] Quarter in which the claim is filed does not count as part of either base period; wages earned in that quarter are excluded. +- Source: S5 (§ 524), S6 (P832 "For all base periods, the quarter in which you file…") +- Implementation note: In a YEAR-period model this is approximated. Implementer should document the limitation. + +### Quarterly Wage Inputs + +**REQ-004** [INCOME] Accept per-quarter wage inputs for the 4 base-period quarters. +- Suggested variables: `ny_ui_q1_wages`, `ny_ui_q2_wages`, `ny_ui_q3_wages`, `ny_ui_q4_wages` (all `float`, entity=`Person`, period=`YEAR`, unit=`USD`) +- Alternative: `ny_ui_high_quarter_wages` as a single input (direct HQ wages, no formula), plus `ny_ui_base_period_wages` (sum). This is the PA UC approach and is adequate if implementer accepts the limitation that per-quarter breakdown is user-supplied. +- Source: S2 (§ 527), S5 (§ 524) + +**REQ-005** [INCOME] Derive `ny_ui_high_quarter_wages` as the maximum of the 4 quarterly inputs. +- Formula: `max(q1, q2, q3, q4)` — or accepted as a direct input following the PA UC pattern. +- Source: S2 (§ 527), S6 (P832 "high quarter wages") + +**REQ-006** [INCOME] Count the number of quarters with non-zero wages (`ny_ui_quarters_with_wages`). +- Formula: `sum([q > 0 for q in [q1, q2, q3, q4]])` +- Required for the 2/3-quarter WBR formula (REQ-014, REQ-015) and the 2-quarter eligibility test (REQ-009). +- Source: S2 (§ 527), S6 (P832) + +### Monetary Eligibility — § 527 + +**REQ-007** [ELIGIBILITY] High-quarter minimum: claimant must have earned at least the indexed minimum in the highest quarter of the base period. +- Parameter: `gov.states.ny.dol.unemployment_insurance.eligibility.high_quarter_minimum` +- Values by date: + - 2025-01-01: $3,400 + - 2026-01-05: $3,500 +- Source: S2 (§ 527), S6 (P832 "For claims filed in 2026, you must have been paid at least $3,500") + +**REQ-008** [ELIGIBILITY] High-quarter minimum threshold is indexed; implementer should use a date-keyed parameter to support future annual increases. +- Source: S2 (§ 527) + +**REQ-009** [ELIGIBILITY] Work-in-2-quarters test: claimant must have been paid wages in at least 2 calendar quarters of the base period. +- Formula: `ny_ui_quarters_with_wages >= 2` +- Source: S2 (§ 527), S6 (P832 "You must have worked and been paid wages in jobs covered by UI in at least two calendar quarters") + +**REQ-010** [ELIGIBILITY] 1.5x total-wages test (standard case): total base-period wages must be ≥ 1.5 × high-quarter wages, when high-quarter wages < the cap. +- Parameter: `gov.states.ny.dol.unemployment_insurance.eligibility.total_wages_multiplier` = 1.5 +- Condition: applies when `ny_ui_high_quarter_wages < high_quarter_cap` +- Source: S2 (§ 527), S6 (P832 "The total wages paid to you must be at least 1.5 times the amount paid to you in your high quarter") + +**REQ-011** [ELIGIBILITY] 1.5x total-wages test (capped case): when high-quarter wages ≥ cap, other-three-quarters wages must be ≥ cap/2. +- P832 (Feb 2026) cap: $19,118; required in other 3 quarters: $9,559 +- Parameter: `gov.states.ny.dol.unemployment_insurance.eligibility.high_quarter_cap` = 19,118 (2026 value) +- Note: Working references.md cited $11,088 / $5,544 — these appear to be 2024/2025 values. P832 Feb 2026 is authoritative for 2026: $19,118 / $9,559. +- Formula: `total_base_wages >= high_quarter_wages + (high_quarter_cap / 2)` when `ny_ui_high_quarter_wages >= high_quarter_cap` +- Source: S2 (§ 527), S6 (P832 "Exception: If your high quarter wages were $19,118 or more, you must have been paid a combined total of at least $9,559 in the other three quarters") + +**REQ-012** [ELIGIBILITY] `ny_ui_monetarily_eligible` = all three tests pass: REQ-007 (high quarter minimum), REQ-009 (2+ quarters), and REQ-010/REQ-011 (1.5x test). +- Suggested variable: `ny_ui_monetarily_eligible` (bool, Person, YEAR) +- Source: S2 (§ 527) + +### Weekly Benefit Rate — § 590(5) + +**REQ-013** [BENEFIT] Standard formula (all 4 quarters): if high-quarter wages > $3,575 → WBR_raw = HQ / 26; if ≤ $3,575 → WBR_raw = HQ / 25. +- Parameter: `gov.states.ny.dol.unemployment_insurance.benefit.divisor_threshold` = 3,575 +- Parameter: `gov.states.ny.dol.unemployment_insurance.benefit.divisor_high` = 26 +- Parameter: `gov.states.ny.dol.unemployment_insurance.benefit.divisor_low` = 25 +- Applies when: `ny_ui_quarters_with_wages == 4` +- Source: S1 (§ 590(5)), S6 (P832 "If you were paid wages in all four quarters of your base period…") + +**REQ-014** [BENEFIT] 2/3-quarter formula tier 1: if 2 or 3 quarters with wages AND high-quarter wages > $4,000 → WBR_raw = average of two highest quarters / 26. +- P832 worked example: HQ=$4,500, 2nd=$4,288 → avg=$4,394 → WBR=$169 +- Applies when: `ny_ui_quarters_with_wages in [2, 3]` AND `ny_ui_high_quarter_wages > 4_000` +- Source: S1 (§ 590(5)), S6 (P832 "More than $4,000: Your benefit amount is the average wages of your two highest quarter wages, divided by 26") + +**REQ-015** [BENEFIT] 2/3-quarter formula tier 2: if 2 or 3 quarters with wages AND $3,576 ≤ HQ ≤ $4,000 → WBR_raw = HQ / 26. +- Applies when: `ny_ui_quarters_with_wages in [2, 3]` AND `3576 <= ny_ui_high_quarter_wages <= 4_000` +- Source: S6 (P832 "$3,576 to $4,000: Your benefit amount is your high quarter wages divided by 26") + +**REQ-016** [BENEFIT] 2/3-quarter formula tier 3: if 2 or 3 quarters with wages AND HQ ≤ $3,575 → WBR_raw = HQ / 25. +- Applies when: `ny_ui_quarters_with_wages in [2, 3]` AND `ny_ui_high_quarter_wages <= 3_575` +- Source: S6 (P832 "$3,575 or less: Your benefit amount is your high quarter wages divided by 25") + +**REQ-017** [BENEFIT] WBR is rounded DOWN to the nearest whole dollar (floor, not round). +- Formula: `WBR_floored = floor(WBR_raw)` +- Source: S1 (§ 590(5): "if not a multiple of one dollar, shall be lowered to the next multiple of one dollar") + +**REQ-018** [BENEFIT] Minimum weekly benefit rate (statutory floor). +- Parameter: `gov.states.ny.dol.unemployment_insurance.benefit.min_amount` +- Values by date: + - 2020-01-01: 104 (historical) + - 2026-01-01: 140 (P832 Feb 2026: "The minimum benefit rate is $140 as of January 2026") +- Note: P832 also mentions $143 as a practical floor for the 4-quarter/HQ>$3,575 case (since $3,576/26 ≈ $137.54 floored to $137 < $143). The $140 statutory minimum supersedes this. Encode $140 as min; the $143 figure in P832 likely refers to a formula minimum for that tier specifically, or reflects a slightly different threshold. Use $140 per explicit statement. +- Source: S1 (§ 590), S6 (P832 "minimum benefit rate is $140 as of January 2026") + +**REQ-019** [BENEFIT] Maximum weekly benefit rate. +- Parameter: `gov.states.ny.dol.unemployment_insurance.benefit.max_amount` +- Values by date: + - 2020-01-01: 504 (frozen through 2025-10-12 due to UI Trust Fund loan) + - 2025-10-13: 869 (FY26 enacted budget; effective first Monday of October 2025) +- Source: S1 (§ 590), S6 (P832 "Effective the first Monday of October 2025 the maximum benefit rate increased to $869"), S8 + +**REQ-020** [BENEFIT] Maximum WBR indexed annually at 50% of NY State Average Weekly Wage (SAWW) from 2025-10-13 onward. +- Implementation note: Future annual updates require a date-keyed parameter update each year. The SAWW-indexing mechanism itself does not need to be automated in code — a manually-updated parameter per year is correct and consistent with PE patterns. +- Source: S1 (§ 590) + +**REQ-021** [BENEFIT] Final WBR = min(max(WBR_floored, min_amount), max_amount). +- Suggested variable: `ny_ui_weekly_benefit_rate` +- Source: S1 (§ 590(5)) + +### Partial Benefit Credit — § 525 + +**REQ-022** [PARTIAL] Partial benefit credit = ceil(max(0.50 × WBR, $100)). +- Parameter: `gov.states.ny.dol.unemployment_insurance.partial_benefit_credit.rate` = 0.50 +- Parameter: `gov.states.ny.dol.unemployment_insurance.partial_benefit_credit.floor` = 100 +- Rounding: round UP (ceiling) to next whole dollar. +- Suggested variable: `ny_ui_partial_benefit_credit` +- Note: NY's PBC formula (50% / $100) differs from PA UC (30% / $6). Do not copy PA formula. +- Source: S3 (§ 525), working_references.md section 6 + +**REQ-023** [PARTIAL] A claimant is "partially employed" for a week if: gross weekly compensation < WBR + partial_benefit_credit. (Used to determine eligibility for any partial payment that week.) +- Source: S4 (§ 522), S3 (§ 525) + +### Partial Benefit — Hours-Based Tiers (effective 2021-08-16) + +**REQ-024** [PARTIAL] Weekly benefit payment fraction is determined by total weekly hours worked according to a 5-tier bracket (effective 2021-08-16): +- 0–10 hours: 100% of WBR +- 11–16 hours: 75% of WBR +- 17–21 hours: 50% of WBR +- 22–30 hours: 25% of WBR +- 31+ hours: 0% of WBR +- Parameter path: `gov.states.ny.dol.unemployment_insurance.partial.hours_tiers` +- Suggested implementation: bracket parameter keyed on hours thresholds with fraction amounts. +- Source: S7 (P803 hours table), NY Lab. Art. 18 amendment eff. 2021-08-16 + +**REQ-025** [PARTIAL] When totaling weekly hours, a maximum of 10 hours per calendar day is counted (prevents a single 12-hour day from counting as 12 hours). +- Source: S7 (P803: "When totaling hours for the week, claimants should use a maximum of 10 hours per calendar day") +- Implementation note: At YEAR periodicity this rule cannot be enforced per-day; document the limitation. The input `ny_ui_weekly_hours_worked` should be understood as already capped accordingly if provided correctly. + +**REQ-026** [PARTIAL] Gross earnings cap: if weekly gross earnings (excluding self-employment earnings) exceed the current maximum WBR, no benefit is payable for that week. +- Suggested variable: `ny_ui_gross_weekly_earnings` (input, float, Person, YEAR, unit=USD) — covers non-self-employment earnings only. +- Condition: if `ny_ui_gross_weekly_earnings > max_amount`, weekly payment = 0. +- Source: S7 (P803: "Any claimant who earns more than $869 in weekly gross pay excluding earnings from self-employment will not be eligible") + +**REQ-027** [PARTIAL] Self-employment earnings are excluded from the gross-earnings cap check (REQ-026), but self-employment hours still count toward the hours-tier calculation. +- Source: S7 (P803), working_references.md section 8 + +### Duration — § 590 + +**REQ-028** [DURATION] Maximum benefit duration: 26 weeks within a 52-week benefit year. +- Parameter: `gov.states.ny.dol.unemployment_insurance.duration.max_weeks` = 26 +- Source: S1 (§ 590) + +**REQ-029** [DURATION] Maximum benefit amount (MBA) = WBR × 26 weeks. +- Suggested variable: `ny_ui_maximum_benefit_amount` +- Source: S1 (§ 590) + +**REQ-030** [DURATION] Weeks-unemployed input: number of weeks in the benefit year the claimant certifies as unemployed (0–26). +- Suggested variable: `ny_ui_weeks_unemployed` (int, Person, YEAR, unit="week") +- Following PA UC pattern: `pa_uc_weeks_unemployed` +- Source: S1 (§ 590) + +### Top-Level Benefit Variable + +**REQ-031** [BENEFIT] Annual NY UI benefit = sum of weekly payments across `ny_ui_weeks_unemployed` weeks, capped at MBA. +- For full-unemployment weeks: annual benefit ≈ WBR × min(weeks_unemployed, 26) +- For partial-unemployment: annual benefit ≈ (fraction × WBR) × min(weeks_unemployed, 26) +- Suggested variable: `ny_ui` (float, Person, YEAR, unit=USD) +- `defined_for = "ny_ui_monetarily_eligible"` +- Must eventually feed into `unemployment_compensation` (federal stub variable) — check whether `unemployment_compensation` uses `adds` or requires override. +- Source: S1 (§ 590) + +### Non-Monetary Eligibility [NOT-MODELED] + +**REQ-032** [NOT-MODELED] Claimant must be totally or partially unemployed (§ 522). +- Not modeled in PolicyEngine individual calculations. +- Source: S4 (§ 522), S1 (§ 591) + +**REQ-033** [NOT-MODELED] Claimant must be capable of work, ready and willing to work, and actively seeking work (§ 591). +- Source: S1 (§ 591) + +**REQ-034** [NOT-MODELED] Disqualifications — voluntary quit without good cause, discharge for misconduct, refusal of suitable work (§ 593). +- Source: NY Lab. § 593 + +**REQ-035** [NOT-MODELED] Dismissal pay exclusion: weeks where dismissal pay > (WBR + PBC) are ineligible (§ 591(6)). +- Source: NY Lab. § 591(6) + +**REQ-036** [NOT-MODELED] Pension offset: WBR reduced if receiving a pension from a base-period employer (§ 600). +- Source: NY Lab. § 600 + +### Out-of-Scope Programs [NOT-MODELED] + +**REQ-037** [NOT-MODELED] Shared Work / Short-Time Compensation (STC) — § 599: employer-sponsored partial-hours alternative. +**REQ-038** [NOT-MODELED] Self-Employment Assistance Program (SEAP) — § 591-a. +**REQ-039** [NOT-MODELED] Extended Benefits (EB): federal/state program triggered by elevated unemployment rate; adds up to 13 weeks. +**REQ-040** [NOT-MODELED] Alternate base period automatic election (§ 527): claimant may request recalculation using alternate base period. PolicyEngine should offer this as an optional flag input. + +### Dependent Allowance + +**REQ-041** [EXEMPTION] NY does NOT provide a dependent allowance under regular UI (§ 590). No dependent-allowance variable is needed. +- Source: S1 (§ 590) — confirmed no subdivision for dependent allowance; confirmed distinct from PA, NJ, MA, CT which do have dependent allowances. +- Note: Some secondary sources erroneously suggest $25/dependent; this is incorrect. + +--- + +## Suggested Variable Structure + +``` +policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ + ny_ui.py REQ-031 — annual benefit, defined_for eligible + ny_ui_monetarily_eligible.py REQ-012 — AND of 3 sub-tests + ny_ui_high_quarter_wages.py REQ-005 — input or derived from 4 quarterly inputs + ny_ui_base_period_wages.py REQ-004 — sum of 4 quarterly wages + ny_ui_quarters_with_wages.py REQ-006 — count of non-zero quarters + ny_ui_second_high_quarter_wages.py REQ-014 — second-highest quarterly wages (for 2/3-quarter formula) + ny_ui_meets_high_quarter_test.py REQ-007 — HQ >= minimum + ny_ui_meets_quarters_test.py REQ-009 — >= 2 quarters with wages + ny_ui_meets_total_wages_test.py REQ-010/011 — 1.5x or capped test + ny_ui_weekly_benefit_rate.py REQ-013–021 — WBR with divisor, min, max + ny_ui_partial_benefit_credit.py REQ-022 — ceil(max(0.5*WBR, 100)) + ny_ui_weekly_benefit_fraction.py REQ-024 — fraction from hours-tier bracket + ny_ui_weekly_payable.py REQ-026,027 — WBR * fraction, with earnings cap + ny_ui_maximum_benefit_amount.py REQ-029 — WBR * 26 + ny_ui_weeks_unemployed.py REQ-030 — input, int, 0-26 + ny_ui_gross_weekly_earnings.py REQ-026 — input, non-self-employment earnings +``` + +Optional (for full quarterly wage decomposition): +``` + ny_ui_q1_wages.py ny_ui_q2_wages.py ny_ui_q3_wages.py ny_ui_q4_wages.py +``` + +Simpler approach (following PA UC pattern): accept `ny_ui_high_quarter_wages` and `ny_ui_base_period_wages` as direct inputs; add `ny_ui_second_high_quarter_wages` for the 2/3-quarter formula; add `ny_ui_quarters_with_wages` as input. + +--- + +## Suggested Parameter Structure + +``` +policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/ + index.yaml metadata: economy: false; household: true + benefit/ + max_amount.yaml 504 → 869 (2025-10-13) + min_amount.yaml 104 (hist.) → 140 (2026-01-01) + divisor_threshold.yaml 3575 + divisor_high.yaml 26 + divisor_low.yaml 25 + two_quarter_threshold_high.yaml 4000 (for 2/3-quarter tier 1 vs 2) + two_quarter_threshold_low.yaml 3575 (same as divisor_threshold; reuse or unify) + eligibility/ + high_quarter_minimum.yaml 3400 (2025) → 3500 (2026-01-05) + high_quarter_cap.yaml 19118 (2026; was ~11088 in earlier years) + total_wages_multiplier.yaml 1.5 + min_quarters.yaml 2 + duration/ + max_weeks.yaml 26 + partial_benefit_credit/ + rate.yaml 0.50 + floor.yaml 100 + partial/ + hours_tiers.yaml bracket: 0→1.0, 11→0.75, 17→0.50, 22→0.25, 31→0.0 +``` + +--- + +## Key Decision Points for Implementer + +### Decision 1: Quarterly wage inputs vs. annual approximation + +PolicyEngine's standard inputs are annual. Options: + +**Option A** (Recommended — follows PA UC): Accept `ny_ui_high_quarter_wages` and `ny_ui_base_period_wages` as direct user inputs (no formula). The user or microdata layer supplies quarterly estimates. This is what PA UC does for `pa_uc_highest_quarter_wages` — it is a plain `Variable` with no `formula`. + +**Option B** (Full quarterly decomposition): Create 4 quarterly input variables and derive HQ from max. More correct but adds 4 new inputs with no automatic formula. + +**Option C** (Annual approximation): Derive HQ ≈ max(employment_income / 4, 0). This is a rough approximation and should be noted as a limitation. Acceptable for microsimulation; less accurate for individual use. + +Recommendation: Implement Option A for launch. Document Option B as future enhancement. + +### Decision 2: 2/3-quarter formula requires second-highest quarter wages + +The 2/3-quarter formula (REQ-014) needs the second-highest quarterly wage. If using Option A/B, add `ny_ui_second_high_quarter_wages` as a direct input. If using Option C (annual approx), this cannot be derived and the 2/3-quarter case defaults to the standard HQ/26 or HQ/25 formula. + +### Decision 3: Partial benefit hours tiers (REQ-024–027) require weekly hours worked + +`weekly_hours_worked` exists already as an annual average variable (default 40). For partial benefit calculation, the intent is hours worked in a given certification week, not annual average. Options: + +- Use `hours_worked_last_week` (already exists as YEAR-period input) as the input for partial benefit calculation. Accept that users input a representative week's hours. +- Accept a new `ny_ui_weekly_hours_worked` input specific to UI certification. + +Recommendation: Use `hours_worked_last_week` or create `ny_ui_weekly_hours_worked` mirroring the PA UC `pa_uc_gross_weekly_earnings` pattern (state-namespaced input). + +### Decision 4: Max WBR date boundary — 2025-10-13 + +Standard PE parameter date keys are `YYYY-MM-DD`. The October 13, 2025 effective date is a Sunday (first Monday = October 13 in some years — confirm: 2025-10-13 is a Monday). Use `2025-10-13` as the date key in `max_amount.yaml`. + +### Decision 5: `high_quarter_cap` value — $11,088 or $19,118 + +The working_references.md cited $11,088 (from an earlier year's § 527 reading). P832 (Feb 2026) states $19,118. This strongly suggests the cap is indexed. Use $19,118 for 2026. Prior years' values ($11,088 likely for 2025 or earlier) should be encoded with their effective dates if backfilling. + +--- + +## Worked Example Verification (from P832) + +Claimant earns $4,500 in Q1 and $4,288 in Q3 (only 2 quarters with wages). + +1. Quarters with wages: 2 → triggers 2/3-quarter formula +2. High quarter: $4,500 > $4,000 → REQ-014 applies: avg of 2 highest / 26 +3. Average = ($4,500 + $4,288) / 2 = $4,394 +4. WBR_raw = $4,394 / 26 = $169.0 +5. WBR_floored = $169 +6. Apply min ($140) / max ($869): $169 is within range → WBR = $169/week +7. Expected result: $169 ✓ (matches P832 example) + +Monetary eligibility check: +- High quarter $4,500 ≥ $3,500 minimum ✓ +- 2 quarters with wages ≥ 2 ✓ +- Total wages = $4,500 + $4,288 = $8,788; 1.5 × $4,500 = $6,750; $8,788 ≥ $6,750 ✓ (high quarter < $19,118 cap so standard 1.5x applies) +- Result: monetarily eligible ✓ + +--- + +## Tests to Write + +The following YAML test cases should be created at `policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/`: + +1. `ny_ui_weekly_benefit_rate.yaml` — 4-quarter case HQ>$3,575 (HQ/26), 4-quarter case HQ≤$3,575 (HQ/25), 2-quarter case HQ>$4,000 (avg/26), 2-quarter case $3,576–$4,000 (HQ/26), min floor ($140), max cap ($504 pre-Oct-2025, $869 post) +2. `ny_ui_monetarily_eligible.yaml` — pass all 3 tests, fail each individually, cap test edge +3. `ny_ui_partial_benefit_credit.yaml` — PBC = max(0.5*WBR, 100) with ceiling +4. `ny_ui_weekly_payable.yaml` — earnings cap disqualification, hours tier reductions +5. `ny_ui.yaml` — full benefit with weeks_unemployed × WBR, cap at MBA + +P832 worked example should be a required test case for `ny_ui_weekly_benefit_rate`. + +--- + +## Reference Implementation Paths + +- PA UC variables: `/Users/daphnehansell/Documents/GitHub/policyengine-us/.claude/worktrees/pa-unemployment-insurance/policyengine_us/variables/gov/states/pa/dli/unemployment_compensation/` +- PA UC parameters: `/Users/daphnehansell/Documents/GitHub/policyengine-us/.claude/worktrees/pa-unemployment-insurance/policyengine_us/parameters/gov/states/pa/dli/unemployment_compensation/` +- Existing NY variables: `/Users/daphnehansell/Documents/GitHub/policyengine-us/policyengine_us/variables/gov/states/ny/` +- Federal unemployment stub: `/Users/daphnehansell/Documents/GitHub/policyengine-us/policyengine_us/variables/gov/states/unemployment_compensation.py` +- Weekly hours input: `/Users/daphnehansell/Documents/GitHub/policyengine-us/policyengine_us/variables/household/income/person/weekly_hours_worked.py` +- Hours worked last week input: `/Users/daphnehansell/Documents/GitHub/policyengine-us/policyengine_us/variables/household/income/person/hours_worked_last_week.py` diff --git a/sources/ny-ui-requirements-checklist.md b/sources/ny-ui-requirements-checklist.md new file mode 100644 index 00000000000..80b612c6f9a --- /dev/null +++ b/sources/ny-ui-requirements-checklist.md @@ -0,0 +1,53 @@ +# NY UI Requirements Checklist + +**Total requirements: 41** (28 simulatable + 13 not-modeled/out-of-scope) + +| REQ | Tag | Description | Status | +|---|---|---|---| +| REQ-001 | INCOME | Standard base period = first 4 of last 5 completed calendar quarters | To do | +| REQ-002 | INCOME | Alternate base period = last 4 completed calendar quarters | To do | +| REQ-003 | INCOME | Quarter of filing excluded from base period | To do (approximation) | +| REQ-004 | INCOME | Per-quarter wage inputs for 4 base-period quarters | To do | +| REQ-005 | INCOME | Derive ny_ui_high_quarter_wages = max of 4 quarters | To do | +| REQ-006 | INCOME | Count quarters with non-zero wages | To do | +| REQ-007 | ELIGIBILITY | High-quarter minimum: $3,400 (2025), $3,500 (2026-01-05) | To do | +| REQ-008 | ELIGIBILITY | High-quarter minimum is indexed — use date-keyed parameter | To do | +| REQ-009 | ELIGIBILITY | Work-in-2-quarters test: wages in ≥ 2 quarters | To do | +| REQ-010 | ELIGIBILITY | 1.5x total-wages test (when HQ < cap) | To do | +| REQ-011 | ELIGIBILITY | 1.5x test capped case: when HQ ≥ $19,118, other 3 qtrs ≥ $9,559 | To do | +| REQ-012 | ELIGIBILITY | ny_ui_monetarily_eligible = all 3 tests pass | To do | +| REQ-013 | BENEFIT | Standard WBR: HQ/26 if HQ>$3,575; HQ/25 if HQ≤$3,575 (4-quarter case) | To do | +| REQ-014 | BENEFIT | 2/3-quarter WBR tier 1: HQ>$4,000 → avg of 2 highest qtrs / 26 | To do | +| REQ-015 | BENEFIT | 2/3-quarter WBR tier 2: $3,576–$4,000 → HQ / 26 | To do | +| REQ-016 | BENEFIT | 2/3-quarter WBR tier 3: HQ≤$3,575 → HQ / 25 | To do | +| REQ-017 | BENEFIT | WBR rounded down (floor) to nearest whole dollar | To do | +| REQ-018 | BENEFIT | Minimum WBR: $140 as of 2026-01-01 (was $104 historically) | To do | +| REQ-019 | BENEFIT | Maximum WBR: $504 through 2025-10-12; $869 from 2025-10-13 | To do | +| REQ-020 | BENEFIT | Max WBR indexed at 50% SAWW annually from 2025-10-13 (parameter update) | To do | +| REQ-021 | BENEFIT | Final WBR = min(max(floor(raw), min), max) | To do | +| REQ-022 | PARTIAL | Partial benefit credit = ceil(max(0.50 × WBR, $100)) | To do | +| REQ-023 | PARTIAL | Partial employment test: gross weekly compensation < WBR + PBC | To do | +| REQ-024 | PARTIAL | Hours-based tiers: 0-10h→100%, 11-16h→75%, 17-21h→50%, 22-30h→25%, 31+h→0% | To do | +| REQ-025 | PARTIAL | Hours cap: max 10 hours per calendar day when totaling weekly hours | To do (doc. limitation) | +| REQ-026 | PARTIAL | Gross earnings cap: if earnings > max WBR → no benefit (excl. self-employment) | To do | +| REQ-027 | PARTIAL | Self-employment earnings excluded from gross-earnings cap (hours still count) | To do | +| REQ-028 | DURATION | Maximum duration: 26 weeks within 52-week benefit year | To do | +| REQ-029 | DURATION | Maximum benefit amount = WBR × 26 | To do | +| REQ-030 | DURATION | ny_ui_weeks_unemployed input (0–26) | To do | +| REQ-031 | BENEFIT | ny_ui annual benefit = sum of weekly payables, capped at MBA | To do | +| REQ-032 | NOT-MODELED | Total/partial unemployment status (§ 522) | Not modeled | +| REQ-033 | NOT-MODELED | Able, available, actively seeking work (§ 591) | Not modeled | +| REQ-034 | NOT-MODELED | Disqualifications — voluntary quit, misconduct, refusal (§ 593) | Not modeled | +| REQ-035 | NOT-MODELED | Dismissal pay exclusion (§ 591(6)) | Not modeled | +| REQ-036 | NOT-MODELED | Pension offset — § 600 | Not modeled | +| REQ-037 | NOT-MODELED | Shared Work / STC (§ 599) | Not modeled | +| REQ-038 | NOT-MODELED | Self-Employment Assistance Program / SEAP (§ 591-a) | Not modeled | +| REQ-039 | NOT-MODELED | Extended Benefits (EB) — federal/state trigger program | Not modeled | +| REQ-040 | NOT-MODELED | Alternate base period automatic election / recalculation (§ 527) | Not modeled (input flag) | +| REQ-041 | EXEMPTION | No dependent allowance in NY UI (confirmed § 590) | Confirmed — no code needed | + +--- + +**Simulatable requirements**: REQ-001 through REQ-031 (31 items) +**Not-modeled / out-of-scope**: REQ-032 through REQ-040 (9 items) +**Exemption confirmed / no code**: REQ-041 (1 item) diff --git a/sources/ny-ui-research-summary.md b/sources/ny-ui-research-summary.md new file mode 100644 index 00000000000..fa8939d1c2d --- /dev/null +++ b/sources/ny-ui-research-summary.md @@ -0,0 +1,21 @@ +# NY UI Research Summary + +- Official program name: New York Unemployment Insurance (NY UI), NYSDOL, NY Labor Law Article 18. +- Key sources: + - NY Lab. Law s 590 (benefit formula): https://www.nysenate.gov/legislation/laws/LAB/590 + - NY Lab. Law s 527 (earnings tests): https://www.nysenate.gov/legislation/laws/LAB/527 + - NY Lab. Law s 525 (partial benefit credit): https://www.nysenate.gov/legislation/laws/LAB/525 + - NYSDOL MBR page: https://dol.ny.gov/mbr + - NYSDOL Partial UI: https://dol.ny.gov/unemployment/partial-unemployment-eligibility + - Governor announcement (max 504 to 869, eff. 2025-10-13): https://www.governor.ny.gov/news/governor-hochul-and-labor-leaders-announce-maximum-weekly-benefit-increase-unemployed-workers +- Eligibility tests: 3 monetary (high-quarter min 3400/3500; 2+ quarters with wages; 1.5x total-to-high ratio with 11088 cap) plus non-monetary (able/available/actively seeking; not disqualified). +- Deductions/exemptions: Self-employment earnings excluded from gross-earnings cap; dismissal pay offsets; partial benefit credit = max(50% of WBR, 100). No dependent allowance. +- Benefit calc type: Formula - high-quarter wages / 26 (or /25 if high quarter <= 3575); avg of two highest quarters /26 if 2-3 quarters; floor to whole dollar; min 104, max 504 pre-2025-10-13 and 869 on/after. +- Complexity: MEDIUM-HIGH - requires base-period quarterly wages (not standard PolicyEngine input), two divisors, hours-based partial tiers (5-tier bracket), 2025-10-13 max jump. +- Failed fetches (curl/Bash and WebFetch denied in this session): + - P832 benefit calc PDF: https://dol.ny.gov/system/files/documents/2025/01/how-your-weekly-unemployment-insurance-benefit-payment-is-calculated-p832.pdf + - P803 partial UI FAQs PDF: https://dol.ny.gov/system/files/documents/2025/10/p803-partial-ui-faqs-10-3-25.pdf + - IA 318.2 employer guide PDF: https://forms.labor.ny.gov/UI/IA318.2.pdf + - Section 900 adjudication manual PDF: https://dol.ny.gov/system/files/documents/2025/10/section-900.pdf + - FindLaw s 590 (403): https://codes.findlaw.com/ny/labor-law/lab-sect-590/ + - public.law s 590 (denied): https://newyork.public.law/laws/n.y._labor_law_section_590 diff --git a/sources/ny-ui-scope-summary.md b/sources/ny-ui-scope-summary.md new file mode 100644 index 00000000000..94a901459e3 --- /dev/null +++ b/sources/ny-ui-scope-summary.md @@ -0,0 +1,96 @@ +# NY UI Scope Summary + +| Field | Value | +|---|---| +| Program name | New York State Unemployment Insurance (UI) | +| State agency | NYSDOL — Unemployment Insurance Division | +| Variable prefix | `ny_ui` | +| Total requirements | 41 | +| Simulatable requirements | 31 | +| Not-modeled requirements | 9 | +| Complexity | MEDIUM-HIGH | +| Primary reference impl | PA UC (`pa-unemployment-insurance` worktree) | + +--- + +## Reference Implementation Paths + +| Item | Path | +|---|---| +| PA UC variables | `.claude/worktrees/pa-unemployment-insurance/policyengine_us/variables/gov/states/pa/dli/unemployment_compensation/` | +| PA UC parameters | `.claude/worktrees/pa-unemployment-insurance/policyengine_us/parameters/gov/states/pa/dli/unemployment_compensation/` | +| Existing NY variables | `policyengine_us/variables/gov/states/ny/` | +| Federal UC stub | `policyengine_us/variables/gov/states/unemployment_compensation.py` | +| Weekly hours input | `policyengine_us/variables/household/income/person/weekly_hours_worked.py` | + +--- + +## Key Decision Points + +### 1. Quarterly wage inputs + +**Problem**: PolicyEngine models annual household income; NY UI eligibility and WBR calculations require wages broken down by base-period calendar quarter. + +**Options**: + +| Option | Approach | Tradeoff | +|---|---|---| +| A (Recommended) | Accept `ny_ui_high_quarter_wages`, `ny_ui_base_period_wages`, `ny_ui_second_high_quarter_wages`, `ny_ui_quarters_with_wages` as direct user inputs (no formula). Follows PA UC pattern. | Correct for calculator use; requires user to supply quarterly breakdown. Microsimulation will need to approximate. | +| B | Create 4 quarterly wage inputs (`ny_ui_q1_wages` etc.) and derive HQ, base total, and quarter count. | More granular; still requires manual user input or approximation from microdata. | +| C | Derive HQ ≈ `employment_income / 4`. | Crude approximation; adequate for rough microsimulation policy impact but not for individual accuracy. | + +**Recommendation**: Option A for initial implementation. Document Option B as future enhancement. Add a note in variable `documentation` that quarterly wage inputs should be provided by the user or approximated by the microdata layer. + +### 2. Partial benefit hours tiers — weekly hours worked input + +**Problem**: The 5-tier hours bracket (REQ-024) requires the total hours worked in a specific UI certification week, not an annual average. + +**Options**: + +| Option | Approach | +|---|---| +| Use `hours_worked_last_week` | Existing YEAR-period input representing the most recent week's hours. Semantically close to certification-week hours. | +| Create `ny_ui_weekly_hours_worked` | New state-namespaced input mirroring `pa_uc_gross_weekly_earnings` pattern — cleaner for NY-specific semantics. | +| Use `weekly_hours_worked` | Existing YEAR-period average hours variable (default 40). Inappropriate for UI partial — this is a labor supply variable, not a partial-unemployment input. | + +**Recommendation**: Create `ny_ui_weekly_hours_worked` (float, Person, YEAR, unit="hour") as a state-namespaced input. This follows the same pattern as `pa_uc_gross_weekly_earnings` (state-specific input variable with no formula). Note in documentation that this should represent hours worked in the UI certification week. + +### 3. Maximum WBR date change — 2025-10-13 + +**Problem**: The max WBR changed on October 13, 2025 ($504 → $869), which is a non-January date key. PolicyEngine supports any `YYYY-MM-DD` key. + +**Solution**: Use `2025-10-13` as the date key in `benefit/max_amount.yaml`. This is straightforward. Note that `2025-10-13` is a Monday; P832 confirms "effective the first Monday of October 2025." + +**Partial earnings cap alignment**: The $869 gross-earnings cap in the partial benefit rule (P803) ties directly to the max WBR. The parameter `benefit/max_amount` can serve double duty — both as the WBR cap and as the partial-earnings disqualification threshold. This avoids duplicating the value. + +### 4. High-quarter cap indexing ($11,088 vs $19,118) + +**Problem**: The cap used in the 1.5x eligibility test appears to change over time. Working notes cited $11,088 (likely a prior-year figure); P832 (Feb 2026) states $19,118. + +**Solution**: Use date-keyed parameter `eligibility/high_quarter_cap.yaml` with at minimum: +- `2026-01-01: 19118` (P832 Feb 2026 value) +- Earlier values should be researched and backfilled when extending coverage years. + +**Important**: The $11,088 figure in earlier working notes and the original REQ text should be treated as a stale reference. $19,118 / $9,559 are the 2026 values per the authoritative P832 document. + +### 5. Minimum WBR — $104 vs $140 + +**Problem**: Working notes cited $104 as the statutory minimum; P832 (Feb 2026) states $140 as of January 2026 (and mentions $143 as a practical floor for the 4-quarter/HQ>$3,575 case). + +**Solution**: Use date-keyed parameter `benefit/min_amount.yaml`: +- `2020-01-01: 104` (historical, for coverage year backfill) +- `2026-01-01: 140` (P832 Feb 2026) + +The $143 figure mentioned in P832 for the HQ>$3,575/4-quarter case likely refers to the formula minimum (i.e., the smallest WBR that would result from HQ=$3,576 using divisor 26: floor(3576/26) = 137, which is below $143; this suggests a higher statutory floor may apply in that case). Encode $140 as the general minimum and flag this ambiguity for legal review. + +--- + +## Complexity Factors + +1. **Three-tier WBR formula**: 4-quarter case vs. 2/3-quarter case (with its own 3-tier sub-formula). More complex than most state UI implementations. +2. **Two-pronged eligibility test**: Standard 1.5x rule and capped alternative; both require total base wages vs. HQ comparisons. +3. **Hours-based partial benefit**: Requires a weekly hours input that has no natural analog in PolicyEngine's annual-income model. +4. **Mid-year parameter change**: $504 → $869 max effective 2025-10-13 requires non-January date key. +5. **No rate table**: Unlike PA UC (which uses a statutory lookup table), NY UI uses formulas. The formula-based approach is cleaner in code but requires careful NumPy vectorization. +6. **Partial earnings cap = max WBR**: These two parameters are identical in value, allowing parameter reuse — but the relationship must be documented clearly. +7. **No dependent allowance**: Simpler than PA UC; no dependent-related variables needed. diff --git a/sources/working_references.md b/sources/working_references.md new file mode 100644 index 00000000000..65b119302ea --- /dev/null +++ b/sources/working_references.md @@ -0,0 +1,604 @@ +# Collected Documentation + +## New York State Unemployment Insurance (NY UI) — Implementation + +**Collected**: 2026-04-23 +**Implementation Task**: Encode New York Unemployment Insurance weekly benefit calculation, eligibility, and partial benefit rules. + +--- + +## Official Program Name + +- **Federal Program**: State Unemployment Insurance (Title III Social Security Act / FUTA 26 USC Chapter 23) +- **State's Official Name**: Unemployment Insurance (UI) +- **Administering Agency**: New York State Department of Labor (NYSDOL), Unemployment Insurance Division +- **Statutory Authority**: NY Labor Law Article 18 — Unemployment Insurance Law (sections 500-603) +- **Source**: NY Labor Law § 500 et seq. + +**Variable Prefix**: `ny_ui` + +--- + +## Key Statutory Structure (NY Labor Law Article 18) + +Article 18 is divided into Titles: +- **Title 2** — Definitions (§§ 510-530): Partial benefit credit, total/partial unemployment, employment, remuneration, etc. +- **Title 3** — Contributions by Employers (§§ 550-584) +- **Title 7** — Benefits and Claims (§§ 590-603): + - § 590 — Rights to benefits (the main benefit-amount statute) + - § 591 — Eligibility for benefits + - § 591-a — Self-Employment Assistance Program (SEAP) + - § 592 — Suspension of accumulation + - § 593 — Disqualifications (voluntary quit, misconduct, refusal of work) + - § 596 — Claim filing, registration, and reporting + - § 599 — Shared Work Program (STC) + +### Key Sections for Benefit Calculation +| Section | Topic | Authority | +|---|---|---| +| § 517 | Remuneration / Wages | Definitions | +| § 522 | Total and Partial Unemployment | Definitions | +| § 524 | Base Period | Definitions | +| § 525 | Partial Benefit Credit | Definitions | +| § 527 | Valid Original Claim (earnings tests) | Eligibility | +| § 590(5) | Weekly Benefit Amount formula | Benefit calc | +| § 591 | Able/Available/Actively Seeking | Eligibility | + +--- + +## Source Information + +### Primary Legal Authority (Statutes) + +| Section | Title | URL | +|---|---|---| +| NY Lab. § 590 | Rights to benefits | https://www.nysenate.gov/legislation/laws/LAB/590 | +| NY Lab. § 591 | Eligibility for benefits | https://www.nysenate.gov/legislation/laws/LAB/591 | +| NY Lab. § 527 | Valid original claim | https://www.nysenate.gov/legislation/laws/LAB/527 | +| NY Lab. § 525 | Partial benefit credit | https://www.nysenate.gov/legislation/laws/LAB/525 | +| NY Lab. § 522 | Total and partial unemployment | https://www.nysenate.gov/legislation/laws/LAB/522 | +| NY Lab. Article 18 | Unemployment Insurance Law (full) | https://www.nysenate.gov/legislation/laws/LAB/A18 | +| Justia Article 18 | 2025 codified version | https://law.justia.com/codes/new-york/lab/article-18/ | +| FindLaw § 590 | NY Labor Law § 590 | https://codes.findlaw.com/ny/labor-law/lab-sect-590/ | +| FindLaw § 525 | NY Labor Law § 525 (Partial Benefit Credit) | https://codes.findlaw.com/ny/labor-law/lab-sect-525/ | + +### NYSDOL Operational Documents + +| Document | URL | Notes | +|---|---|---| +| How Your Weekly UI Benefit Payment is Calculated (P832, 2025 version) | https://dol.ny.gov/system/files/documents/2025/01/how-your-weekly-unemployment-insurance-benefit-payment-is-calculated-p832.pdf | PDF could not be downloaded (bash curl denied); contains worked examples of high-quarter calculation | +| Maximum Benefit Rate explainer | https://dol.ny.gov/mbr | Public-facing page for current MBR | +| How Much Will My Benefit Be? | https://dol.ny.gov/how-much-will-my-benefit-be | Benefit rate overview | +| Estimate Weekly UI Benefits (calculator) | https://ux.labor.ny.gov/benefit-rate-calculator/ | Official benefit-rate calculator | +| Partial Unemployment Benefit Calculator | https://ux.labor.ny.gov/partial-unemployment-ben-calc/ | Official partial benefit calculator | +| Partial Unemployment Eligibility | https://dol.ny.gov/unemployment/partial-unemployment-eligibility | Hours-based tier explainer | +| Workforce Forward: Partial Unemployment FAQs (P803, Oct 2025) | https://dol.ny.gov/system/files/documents/2025/10/p803-partial-ui-faqs-10-3-25.pdf | PDF; not downloaded — HTML version available at https://dol.ny.gov/workforce-forward-partial-unemployment-faqs-p803-english | +| UI Benefits: Employer's Guide (IA 318.2, Dec 2025) | https://forms.labor.ny.gov/UI/IA318.2.pdf | PDF; not downloaded — HTML version at https://dol.ny.gov/employers-guide-unemployment-insurance-benefits-ia3182 | +| Certify for Weekly UI Benefits | https://dol.ny.gov/unemployment/certify-weekly-unemployment-insurance-benefits | Work-day definition | +| Before You File a Claim FAQs | https://dol.ny.gov/you-file-claim-unemployment-faqs | Base-period/earnings-test explainer | +| Governor's Announcement on Max Benefit Increase to $869 | https://www.governor.ny.gov/news/governor-hochul-and-labor-leaders-announce-maximum-weekly-benefit-increase-unemployed-workers | Oct 13, 2025 effective date | + +--- + +## Effective Dates and Recent Changes + +- **2020-01-01 through 2025-10-12**: Maximum weekly benefit frozen at **$504** (UI Trust Fund federal loan deficit) +- **2025-10-13**: Maximum weekly benefit increased to **$869** (FY26 enacted budget, $7B repayment of federal UI Trust Fund loan) +- **Annually thereafter**: Max benefit indexed at **50% of the state average weekly wage (SAWW)** +- **2021-08-16**: Partial benefit calculation moved from days-based to **hours-based tiers** +- **High-quarter threshold** ($3,575) — used to determine 1/25 vs 1/26 divisor (indexed over time; historical value) + +--- + +## Key Rules and Thresholds + +### 1. Eligibility — § 527 Valid Original Claim (Monetary) + +To have a "valid original claim," a claimant must satisfy earnings tests during the base period: + +**Basic (Standard) Base Period**: First 4 of last 5 completed calendar quarters before claim effective date +**Alternate Base Period** (§ 527): Last 4 completed calendar quarters (used if basic period fails) + +**Monetary Earnings Tests** (all three must be met): +1. **High-quarter minimum**: Claimant must have at least a specified minimum in the highest-earning quarter + - 2025 claims: **$3,400** + - 2026 claims (effective Jan 5, 2026): **$3,500** +2. **Work in at least 2 quarters**: Must have remuneration paid in at least 2 calendar quarters of the base period +3. **1.5× ratio**: Total base period wages must be at least **1.5 × high-quarter wages** + - **Cap**: If high-quarter wages ≥ $11,088, the "1.5×" requirement is replaced with the requirement that the claimant be paid at least half of $11,088 = **$5,544** in the other three quarters (i.e., total ≥ $11,088 + $5,544 = $16,632) + +### 2. Non-Monetary Eligibility — § 591 + +Claimant must be: +- Totally unemployed OR partially unemployed (§ 522) +- Capable of work +- Ready, willing, and able to work +- Actively seeking work ("systematic and sustained efforts") +- Not subject to disqualifications in § 593 (voluntary quit w/o good cause, misconduct, refusal of suitable work) +- Participating in reemployment services if directed (profiled claimants) + +**Dismissal pay exclusion**: No benefits if weekly dismissal pay > (weekly benefit rate + partial benefit credit). + +### 3. Weekly Benefit Amount (WBA) — § 590(5) + +**Standard case (claimant has wages in all 4 base-period quarters)**: + +``` +If high_quarter_wages > $3,575: + WBA = high_quarter_wages / 26 +Else (high_quarter_wages <= $3,575): + WBA = high_quarter_wages / 25 +``` + +**2-or-3-quarter case**: If the claimant has wages in only 2 or 3 quarters (not all 4): +``` +WBA = (average of TWO highest quarters) / 26 +``` + +**Rounding**: WBA rounded DOWN to the next multiple of $1 (statute: "if not a multiple of one dollar, shall be lowered to the next multiple of one dollar"). + +**Minimum WBA**: **$104/week** (statutory floor) +**Maximum WBA**: +- **$504/week** (2020-01-01 through 2025-10-12) +- **$869/week** (effective 2025-10-13) +- Thereafter indexed annually at 50% of NY State Average Weekly Wage (SAWW) + +### 4. Duration of Benefits + +- **Maximum regular duration**: **26 weeks** within a 52-week benefit year +- Operationalized as **104 "effective days"** (26 weeks × 4 days/week, since NYSDOL uses days-of-unemployment accounting) +- **Maximum benefit amount (MBA)** payable = WBA × 26 weeks + +Benefit year = 52 weeks starting the Sunday of the week the claim is filed. + +### 5. Partial Unemployment — Hours-Based Tiers (effective Aug 16, 2021) + +Claimant with a week of part-time work receives a fraction of WBA based on total weekly hours: + +| Hours Worked in Week | "Days" Reported | Benefit Fraction | +|---|---|---| +| 0-10 | 0 | 100% of WBA | +| 11-16 | 1 | 75% of WBA | +| 17-21 | 2 | 50% of WBA | +| 22-30 | 3 | 25% of WBA | +| 31+ | 4 | 0% (no benefit) | + +**Hours cap per day**: When totaling hours, maximum 10 hours per calendar day is counted. + +**Gross earnings cap**: If weekly gross pay > current max WBA (excluding self-employment earnings), NO benefit is payable for that week regardless of hours. + +### 6. Partial Benefit Credit — § 525 + +Definition (used in "partial employment" test, not in the hours-based reduction above): + +``` +partial_benefit_credit = max(0.50 × WBA, $100) +``` + +- Rounded UP to next multiple of $1 +- A claimant is "partially employed" under § 522 if: + ``` + compensation < WBA + partial_benefit_credit + ``` + +**Note on relationship to hours-based reduction**: The § 525 partial benefit credit defines the *earnings threshold for partial-unemployment status*. The *reduction* of the weekly payment follows the hours-based tiers (above), with the gross-earnings cap at MBR acting as a backstop. + +### 7. Dependent Allowance + +**NY does NOT have a dependent/dependency allowance in statute (§ 590)** for regular UI. + +Some secondary sources (one claimyr.com forum article) mentioned "$25/dependent"; this appears to be either: +- Confusion with a different state's program (e.g., MA, NJ, CT, PA dependent allowances), or +- A misrepresentation. + +NY Labor Law § 590 does not provide a dependent allowance. **Confirmed via review of § 590 subdivisions** on NY Senate, Justia, and FindLaw. + +### 8. Self-Employment + +Self-employment earnings are **excluded** from the gross-earnings cap (> max WBA disqualifies). +Self-employment "days" still count as work days for hours-based reduction. +NY has a separate **Self-Employment Assistance Program (SEAP)** under § 591-a — not modeled here. + +--- + +## Calculation Formulas + +### Base Period (§ 524) + +``` +basic_base_period = first 4 of last 5 completed calendar quarters before claim effective date +alternate_base_period = last 4 completed calendar quarters +``` + +### Weekly Benefit Rate (§ 590(5)) + +``` +IF wages paid in all 4 quarters: + IF high_quarter_wages > 3575: + wbr_raw = high_quarter_wages / 26 + ELSE: + wbr_raw = high_quarter_wages / 25 +ELIF wages paid in exactly 2 or 3 quarters: + wbr_raw = (highest_quarter + second_highest_quarter) / 2 / 26 +ELSE: + wbr_raw = 0 (ineligible under § 527) + +wbr_floored = floor(wbr_raw) # "lowered to next multiple of $1" +weekly_benefit_rate = min(max(wbr_floored, min_benefit), max_benefit) +``` + +### Monetary Eligibility (§ 527) + +``` +eligible_monetarily = ( + (high_quarter_wages >= high_quarter_minimum) + AND (number_of_quarters_with_wages >= 2) + AND ( + IF high_quarter_wages < 11088: + total_base_wages >= 1.5 * high_quarter_wages + ELSE: + total_base_wages >= high_quarter_wages + (11088 / 2) + ) +) +``` + +### Partial Benefit Credit (§ 525) + +``` +partial_benefit_credit = ceil(max(0.50 * wbr, 100)) +``` + +### Weekly Payment with Part-Time Work (effective 2021-08-16) + +``` +IF weekly_gross_earnings (excl. self-employment) > max_benefit: + weekly_payment = 0 +ELIF total_hours_worked >= 31: + weekly_payment = 0 +ELIF total_hours_worked >= 22: + weekly_payment = 0.25 * wbr +ELIF total_hours_worked >= 17: + weekly_payment = 0.50 * wbr +ELIF total_hours_worked >= 11: + weekly_payment = 0.75 * wbr +ELSE: # 0-10 hours + weekly_payment = 1.00 * wbr +``` + +### Total Benefit (Benefit Year) + +``` +maximum_benefit_amount = weekly_benefit_rate * 26 +``` + +--- + +## Special Cases and Exceptions + +- **Shared Work / Short-Time Compensation (STC)** — § 599: Alternative partial-UI program for employers reducing hours instead of laying off. NOT modeled in initial implementation. +- **Self-Employment Assistance Program (SEAP)** — § 591-a: Not modeled. +- **Extended Benefits (EB)**: Federal/state program triggered by unemployment rate; adds up to 13 weeks. Not part of regular UI calculation. +- **Dismissal pay** — § 591(6): Weeks covered by dismissal pay exceeding (WBR + PBC) are ineligible. +- **Pension offset** — § 600: Reduces WBR if receiving a pension from a base-period employer. Not in scope for initial implementation. +- **Jury service** (§ 591(1)): Not a bar to benefits. +- **Alternate base period election** (§ 527): Claimant may elect if both periods qualify. + +--- + +## Implementation Approach (Simplified) + +Because PolicyEngine models annual household tax/benefit calculations rather than week-by-week UI claim processing, a practical implementation will: + +1. **Inputs**: A household-level or person-level indicator of unemployment (`ny_ui_eligible` boolean) and/or base-period quarterly earnings. +2. **Derive weekly benefit rate** from highest-quarter wages (or an existing federal `unemployment_compensation` proxy). +3. **Apply min/max bounds** and 1/25 vs 1/26 divisor. +4. **Optional**: Partial-benefit reduction based on current-year earnings / hours worked. +5. **Multiply by weeks of unemployment** (capped at 26) for an annual benefit. + +Alternatively, given complexity and the fact that actual UI receipts are typically imputed from CPS microdata in PolicyEngine-US, this program may be represented primarily by: +- A state-level **UI benefit calculator** (public-facing), and +- An imputed annual benefit via `unemployment_compensation` (already in model). + +--- + +## Parameters Required + +### Primary parameters (under `gov/states/ny/dol/unemployment_insurance/`) + +| Parameter | Type | Value | Unit | Source | +|---|---|---|---|---| +| `benefit/max/amount` | Values by date | 504 (2020-01-01), 869 (2025-10-13) | currency-USD | NY Lab § 590(5); Gov announcement 2025 | +| `benefit/min/amount` | Values by date | 104 (2020-01-01) | currency-USD | NY Lab § 590(5); NYSDOL P832 | +| `benefit/divisor_threshold` | Value | 3575 | currency-USD | NY Lab § 590(5) | +| `benefit/divisor_low` | Value | 25 | /1 | NY Lab § 590(5) | +| `benefit/divisor_high` | Value | 26 | /1 | NY Lab § 590(5) | +| `eligibility/high_quarter_minimum` | Values by date | 3400 (2025-01-01), 3500 (2026-01-05) | currency-USD | NY Lab § 527 (indexed) | +| `eligibility/high_quarter_cap` | Value | 11088 | currency-USD | NY Lab § 527 | +| `eligibility/total_wages_multiplier` | Value | 1.5 | /1 | NY Lab § 527 | +| `duration/max_weeks` | Value | 26 | week | NY Lab § 590 | +| `partial/hours_tiers/rate` | Bracket by hours | (see below) | /1 | NYSDOL partial UI (§ 590, amended 2021) | +| `partial/benefit_credit/rate` | Value | 0.50 | /1 | NY Lab § 525 | +| `partial/benefit_credit/floor` | Value | 100 | currency-USD | NY Lab § 525 | + +**Partial UI hours bracket (`partial/hours_tiers/rate.yaml`)**: +```yaml +brackets: + - threshold: { 2021-08-16: 0 } + amount: { 2021-08-16: 1.0 } # 0-10 hours: full WBR + - threshold: { 2021-08-16: 11 } + amount: { 2021-08-16: 0.75 } # 11-16: 75% + - threshold: { 2021-08-16: 17 } + amount: { 2021-08-16: 0.50 } # 17-21: 50% + - threshold: { 2021-08-16: 22 } + amount: { 2021-08-16: 0.25 } # 22-30: 25% + - threshold: { 2021-08-16: 31 } + amount: { 2021-08-16: 0.0 } # 31+: 0% +``` + +### Variables Required + +| Variable | Entity | Period | Purpose | +|---|---|---|---| +| `ny_ui` | Person | YEAR | Total annual NY UI benefit received | +| `ny_ui_weekly_benefit_rate` | Person | YEAR | Calculated WBR (capped/floored) | +| `ny_ui_monetarily_eligible` | Person | YEAR | Passes § 527 tests | +| `ny_ui_eligible` | Person | YEAR | Overall eligibility | +| `ny_ui_high_quarter_wages` | Person | YEAR | Highest base-period quarter | +| `ny_ui_base_period_wages` | Person | YEAR | Total base-period wages | +| `ny_ui_partial_benefit_rate` | Person | WEEK/MONTH | Fraction based on hours | (if modeled weekly) + +--- + +## References for Metadata + +```yaml +# Primary statute reference +reference: + - title: NY Lab. Law § 590(5) Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 + - title: NY Lab. Law § 527 Valid original claim + href: https://www.nysenate.gov/legislation/laws/LAB/527 + - title: NY Lab. Law § 525 Partial benefit credit + href: https://www.nysenate.gov/legislation/laws/LAB/525 + - title: NYSDOL Maximum Benefit Rate + href: https://dol.ny.gov/mbr + - title: NYSDOL Partial Unemployment Eligibility + href: https://dol.ny.gov/unemployment/partial-unemployment-eligibility +``` + +```python +# Python variable references +reference = ( + "https://www.nysenate.gov/legislation/laws/LAB/590", + "https://dol.ny.gov/how-much-will-my-benefit-be", +) +``` + +--- + +## PDFs for Future Reference + +The following PDFs could not be downloaded and extracted in this research session because the environment denied `curl` / `Bash` access. All are authoritative NYSDOL documents that should be consulted when implementing: + +1. **How Your Weekly UI Benefit Payment Is Calculated (P832, Jan 2025)** + - URL: https://dol.ny.gov/system/files/documents/2025/01/how-your-weekly-unemployment-insurance-benefit-payment-is-calculated-p832.pdf + - Reason: curl/Bash denied — unable to extract text + - Expected content: Worked examples of high-quarter calculation, 1/25 vs 1/26 divisor illustration, rounding rule, min/max application + +2. **Workforce Forward: Partial Unemployment FAQs (P803, Oct 2025)** + - URL: https://dol.ny.gov/system/files/documents/2025/10/p803-partial-ui-faqs-10-3-25.pdf + - Reason: curl/Bash denied — unable to extract text + - Expected content: Detailed Q&A on hours-based partial UI, work-day reporting, self-employment, max-earnings cap + - HTML alternative (partial content): https://dol.ny.gov/workforce-forward-partial-unemployment-faqs-p803-english + +3. **Unemployment Insurance Benefits: An Employer's Guide (IA 318.2, Dec 2025)** + - URL: https://forms.labor.ny.gov/UI/IA318.2.pdf (also at https://dol.ny.gov/system/files/documents/2025/10/ia318.2.pdf) + - Reason: curl/Bash denied + - Expected content: Employer-facing summary of benefit formula, eligibility tests, duration + - HTML alternative: https://dol.ny.gov/employers-guide-unemployment-insurance-benefits-ia3182 + +4. **Section 900 — Determination of Benefits (NYSDOL adjudication manual)** + - URL: https://dol.ny.gov/system/files/documents/2025/10/section-900.pdf + - Reason: curl/Bash denied + - Expected content: Detailed adjudication rules for benefit-rate determination, base period, § 527 tests + +5. **TC 408 Unemployment Insurance Reference Guide (Oct 2023)** + - URL: https://dol.ny.gov/system/files/documents/2023/11/tc408-002.pdf + - Reason: curl/Bash denied + - Expected content: Summary reference card with thresholds, divisors, and benefit calculations + +**Note**: `WebFetch` tool also returned 403 on `codes.findlaw.com` and NYSenate PDFs during this session. All primary statutory text was captured via WebSearch extracts quoting the sources directly. + +P803 and P832 have since been provided as user-supplied PDFs and are appended in full at the end of this document. + +--- + +## Complexity Assessment + +**Complexity: MEDIUM-HIGH** + +Reasons: +- Requires modeling base-period quarterly wage history, which is not a standard PolicyEngine input (typically only annual earnings are available). +- Two divisors (25 vs 26) with a high-quarter threshold. +- Minimum/maximum benefit floors with a recent large change (2025-10-13). +- Partial benefit calculation is hours-based (bracket parameter), not days-based. +- Monetary eligibility test has a piecewise 1.5× rule with a cap. +- Annual vs weekly periodicity mismatch will require simplification (e.g., using annual wages as a proxy for high-quarter wages). + +**Key simplifications likely needed for PolicyEngine**: +- Approximate high-quarter wages from annual wages (e.g., using W2 data or a seasonality assumption) +- Represent weeks of unemployment as an exogenous input (number of weeks) +- Partial benefit reduction may be optional/simplified to the earnings-based formula + +--- + +## P803: Partial UI FAQs (NYSDOL, Oct 2025) + +Source: User-provided PDF: p803-partial-ui-faqs-10-3-25.pdf + +UPDATED PARTIAL UNEMPLOYMENT FAQS +UPDATED: OCTOBER 2025 + +On January 18, 2021, Former Governor Andrew M. Cuomo announced that under his direction NYS DOL will implement a new rule that redefines how part-time work impacts unemployment benefits. This change makes New York's partial unemployment system fairer and more equitable for New Yorkers who have the opportunity to work part-time while collecting unemployment and pandemic benefits. + +Effective August 16, 2021, New York State has modified the rules for partial unemployment eligibility. This update will apply to the benefit week of Monday, August 16, 2021 to Sunday, August 22, 2021 and all benefit weeks going forward. When certifying for benefits, New Yorkers should refer the new guidelines for reporting part-time work, available below. + +**Q: What changes have been made to partial unemployment?** + +A: NYS DOL's new partial unemployment system uses an "hours-based" approach. Under the new rules, claimants can work up to 7 days per week without losing full unemployment benefits for that week if they work 30 hours or fewer and earn $869 or less in gross pay excluding earnings from self-employment. With this change, claimants' benefits will not be reduced for each day they engage in part-time work and will be reduced in increments based on total hours of work for the week. + +For comparison, NYS DOL's previous system for partial UI counted part-time work in full-day increments. Under this approach, a claimant who worked part-time would lose 25% of their weekly benefits for each day worked regardless of the number of hours worked on each of those days. For example, a claimant who earned just $45 during a three-hour shift would have lost a quarter of their weekly benefits. + +**Q: What has changed with my weekly certification?** + +A: This system update modifies how claimants calculate the number of days they report working each week. Claimants should refer to the chart below to determine how their weekly hours worked translates to the number of days to report. For example, if a claimant works 10 hours or fewer in a week, they should report they worked 0 days when certifying. A claimant who works 30 hours, would report 3 days worked. + +Another change is that claimants are only required to report up to 10 hours worked each day. + +| Hours Worked Per Week | Number of Days to Report | % Reduction in UI | +|---|---|---| +| 0 - 10 | 0 days | 0% | +| 11 - 16 | 1 day | 25% | +| 17 - 21 | 2 days | 50% | +| 22 - 30 | 3 days | 75% | +| 31+ | 4 days | 100% | + +When calculating your hours worked, round up to the nearest whole hour. + +**Q: What has not changed with my weekly certification?** + +A: Claimants are still required to certify their weekly claims for benefits online or through the automated phone system. When certifying, the system will still ask for the number of days worked. Claimants should refer to the chart above to determine how their weekly hours worked translated to the number of days to report. + +In addition, claimants will still be required to report the amount of money earned during the week for which they are claiming. Any claimant who earns more than $869 in weekly gross pay (excluding earnings from self-employment) will not be eligible for unemployment or pandemic benefits regardless of hours worked. + +**Q: How should I calculate my hours if I work more than 10 hours on one day?** + +A: When totaling hours for the week, claimants should use a maximum of 10 hours per calendar day. To determine how many days of work to report to UI, claimants should add together all hours worked for each calendar day (with a maximum of 10 hours for any day claimants worked more than 10 hours) and refer to the chart above. + +For example, a claimant who works a total of 11 hours in a week should report one day of employment, and a claimant who works a total of 17 hours in a week should report two days of employment if they worked more than one day. If the 17 hours of work occurred on one calendar day, then that claimant should report one day of employment because of the 10-hour maximum rule. + +Note: This formula does not change the $869 gross weekly payments rule — claimants must still report their total earnings for the week. Any claimant who earns more than $869 in weekly gross pay (the amount of money earned before taxes and deductions are taken out) excluding earnings from self-employment will not be eligible for unemployment or pandemic benefits regardless of hours worked. + +**Q: When does this change to partial unemployment go into effect?** + +A: Starting Sunday, January 24, 2021, New Yorkers will report using the new method for the benefit week of Monday, January 18, 2021 to Sunday, January 24, 2021 — and all benefit weeks forward. + +Note: Starting Sunday, August 22, 2021, New Yorkers will report using the updated hours matrix for the benefit week of Monday, August 16, 2021 to Sunday, August 22, 2021 — and all benefit weeks going forward. + +**Q: Is there still an earnings cut-off for partial unemployment benefits?** + +A: Yes, if a claimant earns more than $869 in weekly gross pay (the amount of money earned before taxes and deductions are taken out excluding earnings from self-employment), then they will not be eligible for unemployment or pandemic benefits for that week no matter how few hours they worked. + +**Q: Does this change also apply to weekly certifications for Pandemic Unemployment Assistance (PUA) benefits?** + +A: Yes. Claimants who are eligible for PUA benefits will report their days of work using the new calculation method. Unlike regular UI benefits (or extended benefits), PUA claimants must report earnings in self-employment over $869 as per Federal requirements. + +**Q: If I work four hours in a week over four days, should I still report that I worked 0 days?** + +A: Yes, under NYS DOL's new partial unemployment system, four hours of work in a week — regardless of the total days worked — is equivalent to less than one day worked for certification purposes, as long as the claimant does not earn more than $869 in gross pay (excluding earnings from self-employment) for those hours worked. + +**Q: How does this change impact my benefits if I am not working part-time?** + +A: NYS DOL's change in how partial unemployment benefits are calculated will not impact claimants who work 0 hours in a week. + +**Q: How will this change to partial unemployment impact the overall time that I can receive unemployment benefits?** + +A: NYS DOL's change in how partial unemployment benefits are calculated will not impact the number of weeks of unemployment available to New Yorkers. + +**Q: I'm on Shared Work. How does this change affect my benefits?** + +A: Partial unemployment benefits for claimants enrolled in the Shared Work program are calculated differently. Click here for additional information about certifying for Shared Work benefits. + +**Q: What should I do if I reported the wrong number of hours worked while certifying?** + +A: If a claimant mistakenly reports the number of days worked for weeks starting January 18, 2021 or later, instead of using the new formula, or if you use the outdated reporting guidelines for weeks starting August 16, 2021 or later, they should let NYS DOL know so we can ensure they are paid all the benefits they are entitled to. + +**Q: What should I do if I'm certifying for back payments for weeks that I was partially unemployed between January 18, 2021 and August 16, 2021?** + +To certify for part-time work between January 18, 2021 and August 16, 2021, you should refer to the previous partial employment guidelines below. + +- 0 – 4 hours of work (equivalent to 0 days worked): 100% of weekly benefit rate +- 5 – 10 hours of work (equivalent to 1 day worked): 75% of weekly benefit rate +- 11 – 20 hours of work (equivalent to 2 days worked): 50% of weekly benefit rate +- 21 – 30 hours of work (equivalent to 3 days worked): 25% of weekly benefit rate +- 31+ hours of work (equivalent to 4 days worked): 0% of weekly benefit rate + +P803 (10/25) + +The New York State Department of Labor is an Equal Opportunity Employer/Program. Auxiliary aides and services are available upon request and free of charge to individuals with disabilities TTY/TDD 711 or 1-800-662-1220 (English) / 1-877-662-4886. + +--- + +## P832: How Your Weekly UI Benefit Is Calculated (NYSDOL, Feb 2026) + +Source: User-provided PDF: p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf + +HOW YOUR WEEKLY UNEMPLOYMENT INSURANCE BENEFIT PAYMENT IS CALCULATED + +### Understanding your "base period" + +Your weekly benefit payment amount depends on how much you were paid during a "base period." A base period represents one year of your work and wages (four calendar quarters). Calendar quarters are the three-month blocks of time shown in the chart below. Wages earned in your base period are used to calculate your benefit. Your benefit rate is the amount of money you receive if you are eligible for a full week of Unemployment Insurance benefits. + +Two types of base periods are shown in the chart below. The Basic Base Period is the first four of the last five completed calendar quarters before the quarter in which you file for benefits. If you have enough wages in your Basic Base Period, we use it when we calculate your benefit payment. + +If you do not have enough wages in your Basic Base Period, we use your Alternate Base Period to calculate your benefit payment. The Alternate Base Period is the last four completed calendar quarters before the quarter in which you file for benefits. + +**IMPORTANT:** If you have enough wages in your Basic Base Period, we do not automatically check to see if your benefit rate would be higher if your Alternate Base Period is used instead. If you think your benefit payment would be higher using your Alternate Base Period, you can ask us to use your Alternate Base Period to calculate your benefit amount. However, if you choose to use the alternate quarter (5th quarter as shown in the chart below) wages for your current claim, you cannot use these wages again in the future. This may affect your ability to qualify for a future claim. For more information, see the section "Requesting a benefit rate recalculation based on Alternate Base Period" in the claimant handbook. Or, see the Frequently Asked Questions section on our website under, "What if I think my rate will be higher using the Alternate Base Period?" + +For all base periods, the quarter in which you file for benefits does not count as part of your base period. Wages earned during the quarter you filed will not be used to calculate your benefit rate. + +### How base periods work + +This is an example only. Your base period quarters may differ from those shown. + +| Quarter | Dates | Notes | +|---|---|---| +| 1st Quarter (Previous Year) | January 1 – March 31 | Part of Basic Base Period | +| 2nd Quarter (Previous Year) | April 1 – June 30 | Part of Basic Base Period | +| 3rd Quarter (Previous Year) | July 1 – September 30 | Part of Basic Base Period | +| 4th Quarter (Previous Year) | October 1 – December 31 | Part of Basic Base Period and Alternate Base Period | +| 5th Quarter (Current Year) | January 1 – March 31 | Part of Alternate Base Period only | +| Quarter you filed for benefits (Current Year) | April 1 – June 30 | Does not count as part of base period | + +Basic Base Period: Wages paid to you during the first four quarters above make up your Basic Base Period. + +Alternate Base Period: Wages paid to you during quarters 2–5 above make up your Alternate Base Period. + +### Earnings required to qualify for benefits + +To qualify for benefits, you must meet all three of the following earnings requirements during your base period (basic or alternate): + +- You must have worked and been paid wages in jobs covered by Unemployment Insurance in at least two calendar quarters +- For claims filed in 2026, you must have been paid at least $3,500 in one calendar quarter (this amount increased from $3,400 for claims filed in 2025) +- The total wages paid to you must be at least 1.5 times the amount paid to you in your high quarter. Your high quarter is the quarter of your base period in which you were paid the most money. Exception: If your high quarter wages were $19,118 or more, you must have been paid a combined total of at least $9,559 in the other three quarters of your base period. + +To be eligible for benefits, you must also have lost work through no fault of your own; be ready, willing, and able to work; and be actively looking for work. + +### How we calculate your weekly benefit rate + +If you were paid wages in all four quarters of your base period and your high quarter wages are: + +- **More than $3,575**: Your benefit amount is your high quarter wages divided by 26. If this calculation is less than $143, your benefit rate is $143. +- **$3,575 or less**: Your benefit amount is your high quarter wages divided by 25. + +If you were paid wages in only two or three quarters of your base period and your high quarter wages are: + +- **More than $4,000**: Your benefit amount is the average wages of your two highest quarter wages, divided by 26. If this calculation is less than $143, your benefit amount is $143. For example, your high quarter wages are $4,500 and your next highest quarter wages are $4,288, an average of $4,394 ($4,500 + $4,288 = $8,788; $8,788 ÷ 2 = $4,394). Your benefit amount is $169 ($4,394 ÷ 26 = $169). +- **$3,576 to $4,000**: Your benefit amount is your high quarter wages divided by 26. If this calculation results in less than $143, your benefit amount is $143. +- **$3,575 or less**: Your benefit amount is your high quarter wages divided by 25. + +There are maximum and minimum benefit rates. Effective the first Monday of October 2025 the maximum benefit rate increased to $869. The minimum benefit rate is $140 as of January 2026. + +For more information and more examples of the information contained in this fact sheet, please see the claimant handbook at dol.ny.gov/unemployment-insurance-claimant-handbook. + +### Estimate your weekly benefit rate + +You can estimate your weekly benefit rate by using the online calculator located at ux.labor.ny.gov/benefit-rate-calculator. + +NOTE: The calculator gives an estimate only. It does not guarantee that you will be eligible for benefits or a specific amount of benefits. You must file an Unemployment Insurance claim to find out if you are eligible and learn your actual benefit amount. + +P832 (2/26) + +The New York State Department of Labor is an Equal Opportunity Employer/Program. Auxiliary aides and services are available upon request and free of charge to individuals with disabilities TTY/TDD 711 or 1-800-662-1220 (English) / 1-877-662-4886. The Unemployment Insurance Program is funded by a federal grant of $172,710,563 which constitutes 100% of its budget. 0%, or $0 is funded by state or non-governmental sources. + +--- From 92814360143e8baf774c15294b637361ad4cc670 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:32:34 -0400 Subject: [PATCH 3/4] Fix critical issues from review: date, $143 floor, page refs, aggregation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - benefit/max_amount.yaml: 2025-10-13 → 2025-10-06 (first Monday Oct 2025) - ny_ui_raw_weekly_benefit_rate.py: add $143 formula floor for all 3 divisor-26 tiers per P832 p.2 - All 11 P832 parameter hrefs: #page=1 → #page=2 - partial/hours_tiers.yaml: add #page=1 to P803 href - unemployment_compensation.py: add ny_ui to adds list - programs.yaml: add ny_ui entry Co-Authored-By: Claude Sonnet 4.6 --- .../benefit/formula_min_amount.yaml | 14 +++++++++ .../benefit/low_divisor.yaml | 4 +-- .../benefit/low_hq_threshold.yaml | 4 +-- .../benefit/max_amount.yaml | 6 ++-- .../benefit/min_amount.yaml | 4 +-- .../benefit/standard_divisor.yaml | 4 +-- .../benefit/two_quarter_hq_threshold.yaml | 4 +-- .../eligibility/base_wages_multiplier.yaml | 4 +-- .../capped_other_quarters_rate.yaml | 4 +-- .../eligibility/high_quarter_cap.yaml | 4 +-- .../eligibility/high_quarter_minimum.yaml | 4 +-- .../eligibility/quarters_required.yaml | 4 +-- .../partial/hours_tiers.yaml | 2 +- policyengine_us/programs.yaml | 10 +++++++ .../ny_ui_partial_benefit_credit.yaml | 9 +++--- .../ny_ui_weekly_benefit_rate.yaml | 16 +++++----- .../ny_ui_raw_weekly_benefit_rate.py | 29 ++++++++++++++----- .../gov/states/unemployment_compensation.py | 1 + 18 files changed, 83 insertions(+), 44 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/formula_min_amount.yaml diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/formula_min_amount.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/formula_min_amount.yaml new file mode 100644 index 00000000000..7acc1651ecd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/formula_min_amount.yaml @@ -0,0 +1,14 @@ +description: New York sets this minimum weekly benefit rate for divisor-26 formula cases under the Unemployment Insurance program. + +values: + 2020-01-01: 143 + +metadata: + unit: currency-USD + period: week + label: New York UI formula minimum weekly benefit rate + reference: + - title: NY Labor Law § 590(5) — Rights to benefits + href: https://www.nysenate.gov/legislation/laws/LAB/590 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_divisor.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_divisor.yaml index a8de50c40cb..07b59f83f10 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_divisor.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_divisor.yaml @@ -10,5 +10,5 @@ metadata: reference: - title: NY Labor Law § 590(5) — Rights to benefits href: https://www.nysenate.gov/legislation/laws/LAB/590 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_hq_threshold.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_hq_threshold.yaml index 4155179c6b3..c359a311aad 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_hq_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/low_hq_threshold.yaml @@ -10,5 +10,5 @@ metadata: reference: - title: NY Labor Law § 590(5) — Rights to benefits href: https://www.nysenate.gov/legislation/laws/LAB/590 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_amount.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_amount.yaml index da3b153339e..1498c4c36da 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_amount.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/max_amount.yaml @@ -2,7 +2,7 @@ description: New York sets this maximum weekly benefit rate under the Unemployme values: 2020-01-01: 504 - 2025-10-13: 869 + 2025-10-06: 869 metadata: unit: currency-USD @@ -13,5 +13,5 @@ metadata: href: https://www.nysenate.gov/legislation/laws/LAB/590 - title: Governor Hochul and Labor Leaders Announce Maximum Weekly Benefit Increase for Unemployed Workers href: https://www.governor.ny.gov/news/governor-hochul-and-labor-leaders-announce-maximum-weekly-benefit-increase-unemployed-workers - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/min_amount.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/min_amount.yaml index db999eb1de5..5079f917b9a 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/min_amount.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/min_amount.yaml @@ -11,5 +11,5 @@ metadata: reference: - title: NY Labor Law § 590 — Rights to benefits href: https://www.nysenate.gov/legislation/laws/LAB/590 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/standard_divisor.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/standard_divisor.yaml index 363b40c834f..8871b40ce84 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/standard_divisor.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/standard_divisor.yaml @@ -10,5 +10,5 @@ metadata: reference: - title: NY Labor Law § 590(5) — Rights to benefits href: https://www.nysenate.gov/legislation/laws/LAB/590 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/two_quarter_hq_threshold.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/two_quarter_hq_threshold.yaml index 2271a10e352..2366a68fca3 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/two_quarter_hq_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/benefit/two_quarter_hq_threshold.yaml @@ -10,5 +10,5 @@ metadata: reference: - title: NY Labor Law § 590(5) — Rights to benefits href: https://www.nysenate.gov/legislation/laws/LAB/590 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/base_wages_multiplier.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/base_wages_multiplier.yaml index 641f96027d9..3180eb60c71 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/base_wages_multiplier.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/base_wages_multiplier.yaml @@ -10,5 +10,5 @@ metadata: reference: - title: NY Labor Law § 527 — Valid original claim href: https://www.nysenate.gov/legislation/laws/LAB/527 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/capped_other_quarters_rate.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/capped_other_quarters_rate.yaml index 1740f7a5575..c24839aa341 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/capped_other_quarters_rate.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/capped_other_quarters_rate.yaml @@ -10,5 +10,5 @@ metadata: reference: - title: NY Labor Law § 527 — Valid original claim href: https://www.nysenate.gov/legislation/laws/LAB/527 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_cap.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_cap.yaml index f68945b5617..23dad82674f 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_cap.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_cap.yaml @@ -10,5 +10,5 @@ metadata: reference: - title: NY Labor Law § 527 — Valid original claim href: https://www.nysenate.gov/legislation/laws/LAB/527 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_minimum.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_minimum.yaml index 6892ce16780..f92dc5db898 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_minimum.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/high_quarter_minimum.yaml @@ -11,5 +11,5 @@ metadata: reference: - title: NY Labor Law § 527 — Valid original claim href: https://www.nysenate.gov/legislation/laws/LAB/527 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/quarters_required.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/quarters_required.yaml index 69fa068dfc4..06191230e89 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/quarters_required.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/eligibility/quarters_required.yaml @@ -10,5 +10,5 @@ metadata: reference: - title: NY Labor Law § 527 — Valid original claim href: https://www.nysenate.gov/legislation/laws/LAB/527 - - title: NYSDOL P832 (Feb 2026), page 1 - href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=1 + - title: NYSDOL P832 (Feb 2026), page 2 + href: https://dol.ny.gov/system/files/documents/2026/02/p832-how-your-weekly-ui-benefits-are-calculated-2-26.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/partial/hours_tiers.yaml b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/partial/hours_tiers.yaml index a32dc710115..a008e52475e 100644 --- a/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/partial/hours_tiers.yaml +++ b/policyengine_us/parameters/gov/states/ny/dol/unemployment_insurance/partial/hours_tiers.yaml @@ -35,4 +35,4 @@ metadata: - title: NY Labor Law § 522 — Total and partial unemployment href: https://www.nysenate.gov/legislation/laws/LAB/522 - title: NYSDOL P803 (Oct 2025), Partial Unemployment FAQs - href: https://dol.ny.gov/system/files/documents/2025/10/p803-partial-ui-faqs-10-3-25.pdf + href: https://dol.ny.gov/system/files/documents/2025/10/p803-partial-ui-faqs-10-3-25.pdf#page=1 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 801129254f1..7e987215980 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1044,6 +1044,16 @@ programs: variable: ny_drive_clean_rebate parameter_prefix: gov.states.ny.nyserda.drive_clean + - id: ny_ui + name: NY UI + full_name: New York Unemployment Insurance + category: state_benefits + agency: NYSDOL + status: complete + coverage: "2020-2026" + variable: ny_ui + parameter_prefix: gov.states.ny.dol.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/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.yaml index b545f135600..03cd3438b48 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_partial_benefit_credit.yaml @@ -90,14 +90,15 @@ # 0.5 * $200 = $100; max($100, $100) = $100 (floor equals rate-based). ny_ui_partial_benefit_credit: 100 -- name: Case 5, boundary - low WBR $140 triggers $100 floor. +- name: Case 5, boundary - low WBR $143 triggers $100 floor. period: 2026 absolute_error_margin: 0.01 input: people: person1: age: 30 - # WBR from HQ $3,600: floor($3,600 / 26) = $138 -> lifted to $140 min. + # WBR from HQ $3,600: floor($3,600/26)=$138 < $143 formula floor + # -> raw lifted to $143; $143 > $140 min -> WBR = $143. ny_ui_high_quarter_wages: 3_600 ny_ui_base_period_wages: 12_000 ny_ui_quarters_with_wages: 4 @@ -108,8 +109,8 @@ output: people: person1: - ny_ui_weekly_benefit_rate: 140 - # 0.5 * $140 = $70; max($70, $100) = $100 (floor applies). + ny_ui_weekly_benefit_rate: 143 + # 0.5 * $143 = $71.50; ceil($71.50) = $72; max($72, $100) = $100. ny_ui_partial_benefit_credit: 100 - name: Case 6, odd WBR $307 - ceil rounds 0.50 * WBR up to nearest dollar. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.yaml index 8b7743c8561..011ca3054bf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/dol/unemployment_insurance/ny_ui_weekly_benefit_rate.yaml @@ -8,7 +8,7 @@ # HQ <= $3,575 -> WBR_raw = floor(HQ / 25) # Final WBR = min(max(WBR_raw, min_amount), max_amount). # min_amount: $104 (2020-), $140 (2026-01-01). -# max_amount: $504 (2020-), $869 (2025-10-13). +# max_amount: $504 (2020-), $869 (2025-10-06). # Reference: NY Lab. Law § 590(5); NYSDOL P832 (Feb 2026). - name: Case 1, P832 worked example - 2-quarter case with HQ > $4,000. @@ -142,7 +142,7 @@ person1: # 4 quarters, HQ $50,000 > $3,575 -> divisor 26. # $50,000 / 26 = $1,923.08; floor = $1,923. - # $1,923 capped at $869 (effective 2025-10-13) -> WBR = $869. + # $1,923 capped at $869 (effective 2025-10-06) -> WBR = $869. ny_ui_weekly_benefit_rate: 869 - name: Case 7, boundary - HQ exactly at low threshold uses low divisor 25. @@ -185,9 +185,9 @@ people: person1: # HQ $3,576 > $3,575 TRUE -> standard divisor 26. - # floor($3,576 / 26) = 137. - # $104 <= $137 <= $504 -> WBR = $137. - ny_ui_weekly_benefit_rate: 137 + # floor($3,576/26)=$137 < $143 formula floor -> raw lifted to $143. + # $104 <= $143 <= $504 -> WBR = $143. + ny_ui_weekly_benefit_rate: 143 - name: Case 9, boundary - HQ one dollar above low threshold in 2026, lifted by new minimum. period: 2026 @@ -207,9 +207,9 @@ people: person1: # HQ $3,576 > $3,575 -> standard divisor 26. - # floor($3,576 / 26) = 137. - # $137 < $140 (2026 minimum) -> lifted to $140. - ny_ui_weekly_benefit_rate: 140 + # floor($3,576/26)=$137 < $143 formula floor -> raw lifted to $143. + # $143 > $140 (2026 minimum), within $869 max -> WBR = $143. + ny_ui_weekly_benefit_rate: 143 - name: Case 10, 2/3-quarter tier 2 boundary - HQ exactly at tier-2 upper threshold uses divisor 26. period: 2025 diff --git a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_raw_weekly_benefit_rate.py b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_raw_weekly_benefit_rate.py index 74d47f92686..a85d6b7c4eb 100644 --- a/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_raw_weekly_benefit_rate.py +++ b/policyengine_us/variables/gov/states/ny/dol/unemployment_insurance/ny_ui_raw_weekly_benefit_rate.py @@ -19,13 +19,18 @@ def formula(person, period, parameters): # Four-quarter formula: high quarter wages divided by the standard # divisor (or the low divisor when wages are at or below the low - # threshold). - divisor_four_quarter = where( - high_quarter_wages > p.low_hq_threshold, - p.standard_divisor, - p.low_divisor, + # threshold). Divisor-26 cases have a $143 formula floor per P832 p.2. + above_low_threshold = high_quarter_wages > p.low_hq_threshold + raw_four_quarter_divisor_26 = max_( + np.floor(high_quarter_wages / p.standard_divisor), + p.formula_min_amount, + ) + raw_four_quarter_divisor_25 = np.floor(high_quarter_wages / p.low_divisor) + raw_four_quarter = where( + above_low_threshold, + raw_four_quarter_divisor_26, + raw_four_quarter_divisor_25, ) - raw_four_quarter = np.floor(high_quarter_wages / divisor_four_quarter) # Two- or three-quarter formula has three tiers: # Tier 1: high quarter wages above two-quarter threshold ($4,000) → @@ -35,9 +40,17 @@ def formula(person, period, parameters): # divisor. # Tier 3: high quarter wages at or below low threshold → high # quarter wages / low divisor. + # Tiers 1 and 2 use divisor 26 and therefore have a $143 formula floor + # per P832 p.2; tier 3 (divisor 25) does not. average_two_quarters = (high_quarter_wages + second_high_quarter_wages) / 2 - raw_two_three_tier_1 = np.floor(average_two_quarters / p.standard_divisor) - raw_two_three_tier_2 = np.floor(high_quarter_wages / p.standard_divisor) + raw_two_three_tier_1 = max_( + np.floor(average_two_quarters / p.standard_divisor), + p.formula_min_amount, + ) + raw_two_three_tier_2 = max_( + np.floor(high_quarter_wages / p.standard_divisor), + p.formula_min_amount, + ) raw_two_three_tier_3 = np.floor(high_quarter_wages / p.low_divisor) raw_two_three_quarter = select( diff --git a/policyengine_us/variables/gov/states/unemployment_compensation.py b/policyengine_us/variables/gov/states/unemployment_compensation.py index 0857864ab17..31639831dc0 100644 --- a/policyengine_us/variables/gov/states/unemployment_compensation.py +++ b/policyengine_us/variables/gov/states/unemployment_compensation.py @@ -9,3 +9,4 @@ class unemployment_compensation(Variable): documentation = "Income from unemployment compensation programs." definition_period = YEAR uprating = "calibration.gov.irs.soi.unemployment_compensation" + adds = ["ny_ui"] From 152c36a8cff3c41d60f114d5973176b6f85639e3 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:52:04 -0400 Subject: [PATCH 4/4] Add lessons from New York UI implementation Co-Authored-By: Claude Sonnet 4.6 --- lessons/agent-lessons.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 lessons/agent-lessons.md diff --git a/lessons/agent-lessons.md b/lessons/agent-lessons.md new file mode 100644 index 00000000000..4396aa0cecc --- /dev/null +++ b/lessons/agent-lessons.md @@ -0,0 +1,24 @@ +# Agent Lessons Learned + +Accumulated from /encode-policy-v2 and /backdate-program runs across all contributors. + +## New Lessons from New York UI (2026-04-23) + +### PARAMETER +- When a program has multiple divisor paths (e.g., divisor-25 vs. divisor-26), each path may carry its own regulatory floor distinct from the global minimum; encode per-path floors as a separate parameter (e.g., `formula_min_amount`) rather than relying on the global `min_amount` to cover all cases. +- When a parameter's effective date is described as a day-of-week in statute (e.g., "first Monday of October"), compute the actual calendar date rather than assuming a round number; off-by-one-week errors produce incorrect benefit amounts for every claim in the gap period. +- Parameters that serve two distinct regulatory purposes (e.g., WBR ceiling and partial-employment earnings cap) should be split into separate parameter files; using one parameter for both creates silent drift risk when the two values are updated independently by the agency. + +### FORMULA +- When a partial benefit calculation is specified as `ceil(max(...))`, the `ceil` is load-bearing: omit it and any odd-number input produces a fractional result rather than a whole dollar. Always match the exact rounding direction (floor vs. ceil) specified in the regulation for each formula step. +- For a variable with three or more mutually exclusive outcomes, use `select()` rather than nested `where()` calls. Nested `where()` has implicit fall-through to the last arm, which can silently assign the wrong outcome to cases that match none of the explicit conditions. +- When wiring a new state benefit variable, add it to the relevant federal aggregator (e.g., `unemployment_compensation`) as an explicit step; omitting this prevents the benefit from flowing into AGI and federal tax calculations. + +### REFERENCE +- Before writing any `#page=` anchor for a multi-page PDF, verify which physical page contains the actual parameter value — not the printed page number and not the page implied by the document title. A cover page or diagram can shift every subsequent page number by one. +- When a single PDF URL is copy-pasted as the source for multiple parameters, verify the page anchor independently for each parameter; bulk-copy of the base URL propagates the same wrong anchor to every file simultaneously. +- When a regulatory citation uses section numbers (e.g., §§ 522–523), confirm those sections govern the specific rule encoded, not just adjacent concepts. Statutory definitions and administrative computation rules often live in different sections. + +### VARIABLE +- Test cases for rounding-sensitive formulas must include inputs that produce non-integer intermediate values (e.g., odd WBR for a 0.5× calculation). Test cases using only even-divisor inputs will pass both the correct and the buggy (missing ceil/floor) implementations. +- When two parameters are mathematically coupled by construction (e.g., `rate_b = rate_a − 1`), either derive one from the other in the formula or add an explicit comment documenting the coupling and the requirement to update them together; silent coupling is a future maintenance hazard.