From 05898e0bff3c374e4e7da25d543d473acd395841 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 06:30:28 -0500 Subject: [PATCH 1/5] Add Hawaii's employee temporary disability insurance contribution HRS 392-43 lets an employer withhold half the cost of coverage, up to 0.5% of weekly wages, and caps those wages at a maximum weekly wage base the Director publishes each year. Model the contribution at that limit from the published 2004-2026 wage bases, and add it to employee_state_payroll_tax so it reaches employee_payroll_tax and household net income. HRS 392-3 takes its wage exclusions from HRS 383-11, the same list Hawaii unemployment tax uses, so wages start from payroll_tax_gross_wages. That variable raised a TypeError before 2010 because the FICA pre-tax list started in 2010, so the list now applies to every year. Co-Authored-By: Claude Opus 5.5 --- .../hi-tdi-employee-contribution.added.md | 1 + .../fica_pre_tax_contributions.yaml | 2 +- .../employee_rate.yaml | 20 ++ .../maximum_weekly_wage_base.yaml | 83 +++++ .../qualification/minimum_wages.yaml | 16 + .../qualification/minimum_weekly_hours.yaml | 16 + .../qualification/minimum_weeks.yaml | 16 + .../test_hi_temporary_disability_insurance.py | 244 +++++++++++++++ .../tests/core/test_payroll_contributions.py | 9 + ...ary_disability_insurance_contribution.yaml | 288 ++++++++++++++++++ .../payroll/hi_employee_state_payroll_tax.py | 16 + ...orary_disability_insurance_contribution.py | 28 ++ ...emporary_disability_insurance_qualified.py | 33 ++ ...rary_disability_insurance_taxable_wages.py | 34 +++ .../tax/payroll/employee_state_payroll_tax.py | 6 +- 15 files changed, 810 insertions(+), 2 deletions(-) create mode 100644 changelog.d/hi-tdi-employee-contribution.added.md create mode 100644 policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/employee_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/maximum_weekly_wage_base.yaml create mode 100644 policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_wages.yaml create mode 100644 policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_weekly_hours.yaml create mode 100644 policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_weeks.yaml create mode 100644 policyengine_us/tests/core/test_hi_temporary_disability_insurance.py create mode 100644 policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml create mode 100644 policyengine_us/variables/gov/states/hi/tax/payroll/hi_employee_state_payroll_tax.py create mode 100644 policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.py create mode 100644 policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py create mode 100644 policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py diff --git a/changelog.d/hi-tdi-employee-contribution.added.md b/changelog.d/hi-tdi-employee-contribution.added.md new file mode 100644 index 00000000000..8a3851578da --- /dev/null +++ b/changelog.d/hi-tdi-employee-contribution.added.md @@ -0,0 +1 @@ +Add Hawaii's employee temporary disability insurance contribution under HRS 392-43, with the published maximum weekly wage base for 2004 through 2026, and count it in employee payroll tax and household net income. diff --git a/policyengine_us/parameters/gov/irs/gross_income/fica_pre_tax_contributions.yaml b/policyengine_us/parameters/gov/irs/gross_income/fica_pre_tax_contributions.yaml index 6834c47c44f..21f01c7a19b 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/fica_pre_tax_contributions.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/fica_pre_tax_contributions.yaml @@ -1,6 +1,6 @@ description: Payroll deductions that reduce FICA (Social Security and Medicare) wages without a filing-status-specific cap. values: - 2010-01-01: + 0000-01-01: - pre_tax_health_insurance_premiums - health_savings_account_payroll_contributions # Dependent care assistance the employer reasonably believes excludable diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/employee_rate.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/employee_rate.yaml new file mode 100644 index 00000000000..ed337771574 --- /dev/null +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/employee_rate.yaml @@ -0,0 +1,20 @@ +description: Hawaii limits the employee temporary disability insurance contribution to this share of weekly wages. +values: + # Zero marks years before the first notice read (2004), not a law without a + # contribution. See maximum_weekly_wage_base.yaml. + 0000-01-01: 0 + 2004-01-01: 0.005 + +metadata: + period: year + unit: /1 + label: Hawaii employee TDI maximum contribution rate + reference: + - title: Hawaii Revised Statutes Section 392-43(a) + href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm + - title: Hawaii DLIR, 2004 maximum weekly wage base notice + href: https://web.archive.org/web/20050226051453/http://hawaii.gov:80/labor/dcd/pdf/TDI/2004%20TDI%20Wage%20Base.pdf#page=1 + - title: Hawaii DLIR, 2026 maximum weekly wage base notice + href: https://labor.hawaii.gov/dcd/files/2025/12/2026-Maximum-Weekly-Wage-Base.pdf#page=1 + - title: Hawaii DLIR, Form TDI-15 (rev. June 2026) + href: https://labor.hawaii.gov/dcd/files/2023/05/TDI15-rev-2026.06-1.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/maximum_weekly_wage_base.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/maximum_weekly_wage_base.yaml new file mode 100644 index 00000000000..6eb9ecb9f9e --- /dev/null +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/maximum_weekly_wage_base.yaml @@ -0,0 +1,83 @@ +description: Hawaii counts weekly wages up to this amount toward the employee temporary disability insurance contribution. +values: + # Zero marks years before the first notice read (2004), not a law without a + # wage base. The Director publishes one amount a year under HRS 392-43(b)(2): + # the State's average annual wage / 52 * 1.21. + 0000-01-01: 0 + 2004-01-01: 720.70 + 2005-01-01: 752.44 + 2006-01-01: 791.70 + 2007-01-01: 820.26 + 2008-01-01: 842.56 + 2009-01-01: 877.69 + 2010-01-01: 901.70 + 2011-01-01: 884.29 + 2012-01-01: 903.28 + 2013-01-01: 921.78 + 2014-01-01: 940.05 + 2015-01-01: 951.23 + 2016-01-01: 982.36 + 2017-01-01: 1_023.31 + 2018-01-01: 1_068.62 + 2019-01-01: 1_088.08 + 2020-01-01: 1_119.44 + 2021-01-01: 1_102.90 + 2022-01-01: 1_200.30 + 2023-01-01: 1_318.48 + 2024-01-01: 1_374.78 + 2025-01-01: 1_441.72 + 2026-01-01: 1_500.21 + +metadata: + period: week + unit: currency-USD + label: Hawaii TDI maximum weekly wage base + reference: + - title: Hawaii Revised Statutes Section 392-43(b)(2) + href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm + - title: Hawaii DLIR, 2004 maximum weekly wage base notice + href: https://web.archive.org/web/20050226051453/http://hawaii.gov:80/labor/dcd/pdf/TDI/2004%20TDI%20Wage%20Base.pdf#page=1 + - title: Hawaii DLIR, 2005 maximum weekly wage base notice + href: https://web.archive.org/web/20050226052914/http://hawaii.gov:80/labor/dcd/pdf/general/2005_WAGE_BASE.pdf#page=1 + - title: Hawaii DLIR, 2006 maximum weekly wage base notice + href: https://web.archive.org/web/20060227223955/http://hawaii.gov:80/labor/dcd/pdf/general/2006_WAGE_BASE.pdf#page=1 + - title: Hawaii DLIR, 2007 maximum weekly wage base notice + href: https://web.archive.org/web/20080719002041/http://hawaii.gov/labor/dcd/PDF/general/2007_Wage_Base_12-1-06.pdf#page=1 + - title: Hawaii DLIR, 2008 maximum weekly wage base notice + href: https://web.archive.org/web/20080724052848/http://hawaii.gov/labor/dcd/PDF/general/WAGE%20BASE-2008%20%28PDF%29.pdf#page=1 + - title: Hawaii DLIR, 2009 maximum weekly wage base notice + href: https://web.archive.org/web/20121025001236/http://hawaii.gov/labor/dcd/PDF/general/2009%20Wage%20Base.pdf#page=1 + - title: Hawaii DLIR, 2010 maximum weekly wage base notice + href: https://web.archive.org/web/20101215215838/http://hawaii.gov/labor/dcd/PDF/general/2010%20Wage%20Base.pdf#page=1 + - title: Hawaii DLIR, 2011 maximum weekly wage base notice + href: https://web.archive.org/web/20101215215837/http://hawaii.gov/labor/dcd/PDF/general/2011%20Wage%20Base.pdf#page=1 + - title: Hawaii DLIR, 2012 maximum weekly wage base notice + href: https://web.archive.org/web/20121024102028/http://hawaii.gov/labor/dcd/PDF/general/2012%20Wage%20Base.pdf#page=1 + - title: Hawaii DLIR, 2013 maximum weekly wage base notice + href: https://web.archive.org/web/20141030021517/http://labor.hawaii.gov/dcd/files/2013/01/Old-Wage-Base.pdf#page=1 + - title: Hawaii DLIR, 2014 maximum weekly wage base notice + href: https://web.archive.org/web/20141030011206/http://labor.hawaii.gov/dcd/files/2013/01/New-Wage-Base.pdf#page=1 + - title: Hawaii DLIR, 2015 maximum weekly wage base notice + href: https://web.archive.org/web/20160824005208/http://labor.hawaii.gov:80/dcd/files/2013/01/2015-Wage-Base.pdf#page=1 + - title: Hawaii DLIR, 2016 maximum weekly wage base notice + href: https://web.archive.org/web/20160706000230/http://labor.hawaii.gov:80/dcd/files/2014/11/2016.pdf#page=1 + - title: Hawaii DLIR, 2017 maximum weekly wage base notice + href: https://web.archive.org/web/20171101222709/https://labor.hawaii.gov/dcd/files/2013/01/17Wbase.pdf#page=1 + - title: Hawaii DLIR, 2018 maximum weekly wage base notice + href: https://labor.hawaii.gov/dcd/files/2017/11/2018.pdf#page=1 + - title: Hawaii DLIR, 2019 maximum weekly wage base notice + href: https://labor.hawaii.gov/dcd/files/2018/11/2019wagebase.pdf#page=1 + - title: Hawaii DLIR, 2020 maximum weekly wage base notice + href: https://web.archive.org/web/20201017202041/https://labor.hawaii.gov/dcd/files/2019/11/newWBA.pdf#page=1 + - title: Hawaii DLIR, 2021 maximum weekly wage base notice + href: https://web.archive.org/web/20201204141806/https://labor.hawaii.gov/dcd/files/2019/11/newWBA.pdf#page=1 + - title: Hawaii DLIR, 2022 maximum weekly wage base notice + href: https://web.archive.org/web/20220819164238/https://labor.hawaii.gov/dcd/files/2019/11/newWBA.pdf#page=1 + - title: Hawaii DLIR, 2023 maximum weekly wage base notice + href: https://web.archive.org/web/20230306111219/https://labor.hawaii.gov/dcd/files/2019/11/newWBA.pdf#page=1 + - title: Hawaii DLIR, 2024 maximum weekly wage base notice + href: https://labor.hawaii.gov/dcd/files/2023/11/2024-Max-Weekly-Wage-Base-Weekly-Benefit-Amount.pdf#page=1 + - title: Hawaii DLIR, 2025 maximum weekly wage base notice + href: https://labor.hawaii.gov/dcd/files/2023/05/2025-Max-Weekly-Wage-Base-Rev-2025.03.pdf#page=1 + - title: Hawaii DLIR, 2026 maximum weekly wage base notice + href: https://labor.hawaii.gov/dcd/files/2025/12/2026-Maximum-Weekly-Wage-Base.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_wages.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_wages.yaml new file mode 100644 index 00000000000..7256c49dfb0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_wages.yaml @@ -0,0 +1,16 @@ +description: Hawaii counts an employee's weekly wages toward the temporary disability insurance contribution only if the employee earned at least this amount in the prior 52 weeks. +values: + # Act 30 of 1999 applies from 2000 and left this amount in place. Later acts + # did not change it. Zero marks earlier years, which this program does not model. + 0000-01-01: 0 + 2000-01-01: 400 + +metadata: + period: year + unit: currency-USD + label: Hawaii TDI minimum wages to count weekly wages + reference: + - title: Hawaii Revised Statutes Section 392-43(b)(1) + href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm + - title: Session Laws of Hawaii 1999, Act 30 + href: https://data.capitol.hawaii.gov/slh/Years/SLH1999/SLH1999_Act30.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_weekly_hours.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_weekly_hours.yaml new file mode 100644 index 00000000000..e97d742c76c --- /dev/null +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_weekly_hours.yaml @@ -0,0 +1,16 @@ +description: Hawaii treats a week as qualifying for the temporary disability insurance contribution only if the employee was paid for at least this many hours in that week. +values: + # Act 30 of 1999 applies from 2000 and left this count in place. Later acts + # did not change it. Zero marks earlier years, which this program does not model. + 0000-01-01: 0 + 2000-01-01: 20 + +metadata: + period: week + unit: hour + label: Hawaii TDI minimum paid hours in a qualifying week + reference: + - title: Hawaii Revised Statutes Section 392-43(b)(1) + href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm + - title: Session Laws of Hawaii 1999, Act 30 + href: https://data.capitol.hawaii.gov/slh/Years/SLH1999/SLH1999_Act30.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_weeks.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_weeks.yaml new file mode 100644 index 00000000000..ebc425bf7c4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/qualification/minimum_weeks.yaml @@ -0,0 +1,16 @@ +description: Hawaii counts an employee's weekly wages toward the temporary disability insurance contribution only if the employee worked at least this many qualifying weeks in the prior 52 weeks. +values: + # Act 30 of 1999 applies from 2000 and left this count in place. Later acts + # did not change it. Zero marks earlier years, which this program does not model. + 0000-01-01: 0 + 2000-01-01: 14 + +metadata: + period: year + unit: week + label: Hawaii TDI minimum qualifying weeks to count weekly wages + reference: + - title: Hawaii Revised Statutes Section 392-43(b)(1) + href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm + - title: Session Laws of Hawaii 1999, Act 30 + href: https://data.capitol.hawaii.gov/slh/Years/SLH1999/SLH1999_Act30.pdf#page=1 diff --git a/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py b/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py new file mode 100644 index 00000000000..60f3a597a58 --- /dev/null +++ b/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py @@ -0,0 +1,244 @@ +"""Invariants for Hawaii's employee temporary disability insurance contribution. + +YAML covers the policy examples. This module covers what one YAML case cannot +state: + +1. Code against published figures. The wage base parameter matches every DLIR + notice, each notice's base follows HRS 392-43(b)(2) from that notice's + average annual wage, and each notice's maximum weekly deduction is 0.5% of + its base. +2. The annual formula against the weekly statute. The law caps wages week by + week. For any wages spread over a worker's weeks, the annual amount is at + least the weekly sum, and the two match when wages are even. +3. Properties across drawn batches of workers: bounds, monotonicity in wages, + state masking, and aggregation to the tax unit. +4. Net income. Removing the contribution raises household net income by exactly + the contribution. + +Intended differences from the published figures: + +- The 2010 notice's 901.70 equals the unrounded product rounded once. Every + other notice matches rounding the weekly wage first, which gives 901.69 for + 2010. HRS 392-43(b)(2) sets no rounding rule, and the parameter holds the + published amount. +- A full-year worker over the cap pays 52 * 0.5% * base here. DLIR rounds each + week's maximum deduction to the cent, so 52 weeks of it differ by at most 26 + cents. +""" + +from decimal import ROUND_HALF_UP, Decimal + +import numpy as np +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation +from policyengine_us.system import system as SYSTEM + +CONTRIBUTION = "hi_employee_temporary_disability_insurance_contribution" +TOLERANCE = 0.01 # dollars +RATE = Decimal("0.005") # HRS 392-43(a) +FACTOR = Decimal("1.21") # HRS 392-43(b)(2) + +# Transcribed from each year's DLIR notice, independent of the parameter file: +# state average annual wage, maximum weekly wage base, maximum weekly deduction. +NOTICES = { + 2004: ("30972.13", "720.70", "3.60"), + 2005: ("32336.24", "752.44", "3.76"), + 2006: ("34023.65", "791.70", "3.96"), + 2007: ("35250.68", "820.26", "4.10"), + 2008: ("36209.17", "842.56", "4.21"), + 2009: ("37718.93", "877.69", "4.39"), + 2010: ("38750.59", "901.70", "4.51"), + 2011: ("38002.62", "884.29", "4.42"), + 2012: ("38818.32", "903.28", "4.52"), + 2013: ("39613.57", "921.78", "4.61"), + 2014: ("40398.56", "940.05", "4.70"), + 2015: ("40879.44", "951.23", "4.76"), + 2016: ("42217.41", "982.36", "4.91"), + 2017: ("43976.82", "1023.31", "5.12"), + 2018: ("45924.45", "1068.62", "5.34"), + 2019: ("46760.69", "1088.08", "5.44"), + 2020: ("48108.20", "1119.44", "5.60"), + 2021: ("47397.51", "1102.90", "5.51"), + 2022: ("51582.77", "1200.30", "6.00"), + 2023: ("56662.05", "1318.48", "6.59"), + 2024: ("59081.47", "1374.78", "6.87"), + 2025: ("61958.21", "1441.72", "7.21"), + 2026: ("64471.82", "1500.21", "7.50"), +} +YEARS = sorted(NOTICES) +GROUP_ENTITIES = ( + "tax_units", + "spm_units", + "families", + "marital_units", + "households", +) +TDI = SYSTEM.parameters.gov.states.hi.tax.payroll.temporary_disability_insurance + +# A batch's cost is mostly per-variable overhead, so each example is a batch of +# workers and there are few examples. +SETTINGS = dict( + max_examples=8, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) + + +def cents(amount): + return amount.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) + + +def base_for(year): + return float(NOTICES[year][1]) + + +def simulate(year, workers, **overrides): + period = str(year) + situation = {"people": {}, **{entity: {} for entity in GROUP_ENTITIES}} + for i, worker in enumerate(workers): + person = f"person_{i}" + situation["people"][person] = { + "age": {period: 40}, + "employment_income": {period: worker["wages"]}, + "pre_tax_health_insurance_premiums": {period: worker.get("premiums", 0)}, + "weeks_worked": {period: worker.get("weeks", 0)}, + "weekly_hours_worked_before_lsr": {period: worker.get("hours", 0)}, + **{name: {period: value} for name, value in overrides.items()}, + } + for entity in GROUP_ENTITIES: + situation[entity][f"{entity}_{i}"] = {"members": [person]} + situation["households"][f"households_{i}"]["state_code"] = { + period: worker.get("state", "HI") + } + return Simulation(tax_benefit_system=SYSTEM, situation=situation) + + +@pytest.mark.parametrize("year", YEARS) +def test_parameters_match_the_published_notice(year): + instant = f"{year}-01-01" + assert TDI.maximum_weekly_wage_base(instant) == pytest.approx( + base_for(year), abs=1e-9 + ) + assert TDI.employee_rate(instant) == float(RATE) + + +@pytest.mark.parametrize("year", YEARS) +def test_notice_follows_the_statutory_formula(year): + annual_wage, base, deduction = (Decimal(value) for value in NOTICES[year]) + rounded_once = cents(annual_wage / 52 * FACTOR) + weekly_wage_rounded_first = cents(cents(annual_wage / 52) * FACTOR) + assert base == (rounded_once if year == 2010 else weekly_wage_rounded_first) + assert deduction == cents(base * RATE) + assert abs(52 * base * RATE - 52 * deduction) <= Decimal("0.26") + + +workers = st.fixed_dictionaries( + { + "state": st.sampled_from(["HI", "HI", "HI", "TX"]), + "wages": st.one_of( + st.sampled_from([0, 399, 400, 1_000_000]), + st.integers(-5_000, 200_000), + ), + "premiums": st.one_of(st.just(0), st.integers(0, 10_000)), + "weeks": st.one_of(st.sampled_from([0, 13, 14, 52]), st.integers(1, 52)), + "hours": st.one_of(st.sampled_from([0, 19, 20, 40]), st.integers(1, 80)), + } +) + + +@settings(**SETTINGS) +@given( + year=st.sampled_from(YEARS), + batch=st.lists(workers, min_size=5, max_size=30), + bump=st.integers(1, 20_000), +) +def test_contribution_properties(year, batch, bump): + period = str(year) + sim = simulate(year, batch) + contribution = sim.calculate(CONTRIBUTION, period) + raised = simulate( + year, [{**worker, "wages": worker["wages"] + bump} for worker in batch] + ).calculate(CONTRIBUTION, period) + + in_hawaii = np.array([worker["state"] == "HI" for worker in batch]) + wages = np.array( + [max(0, worker["wages"] - worker["premiums"]) for worker in batch], + dtype=float, + ) + weeks = np.array([worker["weeks"] or 52 for worker in batch], dtype=float) + limit = float(RATE) * np.minimum(wages, base_for(year) * weeks) + + # Bounds, for every input. + assert (contribution >= 0).all() + assert (contribution <= limit + TOLERANCE).all() + # State masking. + assert (contribution[~in_hawaii] == 0).all() + # More wages never lower the contribution. + assert (raised >= contribution - TOLERANCE).all() + # Each worker files alone, so the tax unit total is that worker's amount. + assert sim.calculate("hi_employee_state_payroll_tax", period) == pytest.approx( + contribution, abs=TOLERANCE + ) + assert sim.calculate("employee_state_payroll_tax", period)[ + in_hawaii + ] == pytest.approx(contribution[in_hawaii], abs=TOLERANCE) + + +# At least 14 weeks of at least 30 dollars clears the $400 and 14-week test. +weekly_wages = st.lists(st.integers(30, 4_000), min_size=14, max_size=52) + + +@settings(**SETTINGS) +@given( + year=st.sampled_from(YEARS), + batch=st.lists(weekly_wages, min_size=3, max_size=15), +) +def test_annual_amount_is_the_limit_of_the_weekly_statute(year, batch): + base = base_for(year) + annual = simulate( + year, + [{"wages": sum(series), "weeks": len(series), "hours": 40} for series in batch], + ).calculate(CONTRIBUTION, str(year)) + + statute = np.array( + [sum(float(RATE) * min(wage, base) for wage in series) for series in batch] + ) + assert (annual >= statute - TOLERANCE).all() + + even = np.array( + [ + len(series) * float(RATE) * min(sum(series) / len(series), base) + for series in batch + ] + ) + assert annual == pytest.approx(even, abs=TOLERANCE) + + +def test_contribution_lowers_household_net_income_dollar_for_dollar(): + period = "2026" + batch = [{"wages": wages} for wages in (30_000, 60_000, 100_000)] + baseline = simulate(2026, batch) + without = simulate(2026, batch, **{CONTRIBUTION: 0}) + + contribution = baseline.calculate(CONTRIBUTION, period) + # 0.5% of 30,000 and 60,000, then 0.5% * 52 * 1,500.21. + assert contribution == pytest.approx([150, 300, 390.0546], abs=TOLERANCE) + + for variable in ( + "employee_state_payroll_tax", + "employee_payroll_tax", + "household_tax_before_refundable_credits", + ): + added = baseline.calculate(variable, period) - without.calculate( + variable, period + ) + assert added == pytest.approx(contribution, abs=TOLERANCE), variable + + lost = without.calculate("household_net_income", period) - baseline.calculate( + "household_net_income", period + ) + assert lost == pytest.approx(contribution, abs=TOLERANCE) diff --git a/policyengine_us/tests/core/test_payroll_contributions.py b/policyengine_us/tests/core/test_payroll_contributions.py index 6939b040785..016187c7aa6 100644 --- a/policyengine_us/tests/core/test_payroll_contributions.py +++ b/policyengine_us/tests/core/test_payroll_contributions.py @@ -303,6 +303,15 @@ def make_employer_total_simulation( }, id="DE", ), + pytest.param( + "HI", + { + "hi_employee_temporary_disability_insurance_contribution": 390.0546, + "hi_employee_state_payroll_tax": 390.0546, + "employee_state_payroll_tax": 390.0546, + }, + id="HI", + ), pytest.param( "MA", { diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml new file mode 100644 index 00000000000..b93c535e742 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml @@ -0,0 +1,288 @@ +# Each year's maximum weekly wage base comes from the Hawaii DLIR notice for +# that year, cited in maximum_weekly_wage_base.yaml. The 0.5% rate comes from +# HRS 392-43(a), and the $400, 14-week and 20-hour test from HRS 392-43(b)(1). + +- name: Hawaii 2024 contribution is 0.5% of wages under the cap. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 50_000 + state_code: HI + output: + hi_temporary_disability_insurance_qualified: true + hi_temporary_disability_insurance_taxable_wages: 50_000 + # 0.5% * 50,000 = 250.00. + hi_employee_temporary_disability_insurance_contribution: 250.00 + hi_employee_state_payroll_tax: 250.00 + employee_state_payroll_tax: 250.00 + +- name: Hawaii 2024 contribution stops at the 1,374.78 weekly wage base. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 100_000 + state_code: HI + output: + # 52 * 1,374.78 = 71,488.56. + hi_temporary_disability_insurance_taxable_wages: 71_488.56 + # 0.5% * 71,488.56 = 357.44. DLIR's 6.87 weekly maximum * 52 = 357.24, and + # the 0.20 gap comes from DLIR rounding each week's maximum to the cent. + hi_employee_temporary_disability_insurance_contribution: 357.44 + hi_employee_state_payroll_tax: 357.44 + employee_state_payroll_tax: 357.44 + +- name: Hawaii 2026 contribution is 0.5% of wages under the cap. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + state_code: HI + output: + # 0.5% * 60,000 = 300.00. + hi_employee_temporary_disability_insurance_contribution: 300.00 + employee_state_payroll_tax: 300.00 + +- name: Hawaii 2026 contribution stops at the 1,500.21 weekly wage base. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 100_000 + state_code: HI + output: + # 52 * 1,500.21 = 78,010.92. + hi_temporary_disability_insurance_taxable_wages: 78_010.92 + # 0.5% * 78,010.92 = 390.05. DLIR's 7.50 weekly maximum * 52 = 390.00. + hi_employee_temporary_disability_insurance_contribution: 390.05 + # Social Security 6.2% * 100,000 = 6,200.00, Medicare 1.45% * 100,000 = + # 1,450.00, and 6,200.00 + 1,450.00 + 390.05 = 8,040.05. + employee_payroll_tax: 8_040.05 + spm_unit_payroll_tax: 8_040.05 + +- name: Hawaii 2004, the first published year, uses the 720.70 weekly wage base. + period: 2004 + absolute_error_margin: 0.01 + input: + employment_income: 50_000 + state_code: HI + output: + # 52 * 720.70 = 37,476.40. + hi_temporary_disability_insurance_taxable_wages: 37_476.40 + # 0.5% * 37,476.40 = 187.38. + hi_employee_temporary_disability_insurance_contribution: 187.38 + +- name: Hawaii 2009 uses the 877.69 weekly wage base and counts pre-tax premiums out. + period: 2009 + absolute_error_margin: 0.01 + input: + employment_income: 50_000 + pre_tax_health_insurance_premiums: 10_000 + state_code: HI + output: + # 50,000 - 10,000 = 40,000, under 52 * 877.69 = 45,639.88. + hi_temporary_disability_insurance_taxable_wages: 40_000 + # 0.5% * 40,000 = 200.00. + hi_employee_temporary_disability_insurance_contribution: 200.00 + employee_state_payroll_tax: 200.00 + +- name: Hawaii models no contribution before the first published year. + period: 2003 + absolute_error_margin: 0.01 + input: + employment_income: 50_000 + state_code: HI + output: + hi_temporary_disability_insurance_taxable_wages: 0 + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii 2020 contribution stops at the 1,119.44 weekly wage base. + period: 2020 + absolute_error_margin: 0.01 + input: + employment_income: 100_000 + state_code: HI + output: + # 52 * 1,119.44 = 58,210.88. + hi_temporary_disability_insurance_taxable_wages: 58_210.88 + # 0.5% * 58,210.88 = 291.05. + hi_employee_temporary_disability_insurance_contribution: 291.05 + +- name: Hawaii 2021 contribution falls with the lower 1,102.90 weekly wage base. + period: 2021 + absolute_error_margin: 0.01 + input: + employment_income: 100_000 + state_code: HI + output: + # 52 * 1,102.90 = 57,350.80. + hi_temporary_disability_insurance_taxable_wages: 57_350.80 + # 0.5% * 57,350.80 = 286.75. + hi_employee_temporary_disability_insurance_contribution: 286.75 + +- name: Hawaii applies the weekly cap only to weeks worked. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 50_000 + weeks_worked: 26 + weekly_hours_worked_before_lsr: 40 + state_code: HI + output: + # 26 * 1,374.78 = 35,744.28. + hi_temporary_disability_insurance_taxable_wages: 35_744.28 + # 0.5% * 35,744.28 = 178.72. + hi_employee_temporary_disability_insurance_contribution: 178.72 + +- name: Hawaii taxes part-year wages in full when they stay under the weekly cap. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 20_000 + weeks_worked: 26 + weekly_hours_worked_before_lsr: 40 + state_code: HI + output: + # 26 * 1,374.78 = 35,744.28 exceeds 20,000. + hi_temporary_disability_insurance_taxable_wages: 20_000 + # 0.5% * 20,000 = 100.00. + hi_employee_temporary_disability_insurance_contribution: 100.00 + +- name: Hawaii counts wages at exactly 14 weeks and 20 hours. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 15_000 + weeks_worked: 14 + weekly_hours_worked_before_lsr: 20 + state_code: HI + output: + hi_temporary_disability_insurance_qualified: true + # 14 * 1,374.78 = 19,246.92 exceeds 15,000. + hi_temporary_disability_insurance_taxable_wages: 15_000 + # 0.5% * 15,000 = 75.00. + hi_employee_temporary_disability_insurance_contribution: 75.00 + +- name: Hawaii does not count wages at 13 weeks. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 15_000 + weeks_worked: 13 + weekly_hours_worked_before_lsr: 40 + state_code: HI + output: + hi_temporary_disability_insurance_qualified: false + hi_temporary_disability_insurance_taxable_wages: 0 + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii does not count wages under 20 hours a week. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 20_000 + weeks_worked: 52 + weekly_hours_worked_before_lsr: 19 + state_code: HI + output: + hi_temporary_disability_insurance_qualified: false + hi_temporary_disability_insurance_taxable_wages: 0 + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii counts wages at exactly 400. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 400 + state_code: HI + output: + hi_temporary_disability_insurance_qualified: true + # 0.5% * 400 = 2.00. + hi_employee_temporary_disability_insurance_contribution: 2.00 + +- name: Hawaii does not count wages under 400. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 399 + state_code: HI + output: + hi_temporary_disability_insurance_qualified: false + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii tests weeks when hours went unreported. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 15_000 + weeks_worked: 10 + state_code: HI + output: + hi_temporary_disability_insurance_qualified: false + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii tests hours when weeks went unreported. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 15_000 + weekly_hours_worked_before_lsr: 10 + state_code: HI + output: + hi_temporary_disability_insurance_qualified: false + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii leaves pre-tax health premiums out of wages. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 50_000 + pre_tax_health_insurance_premiums: 5_000 + state_code: HI + output: + hi_temporary_disability_insurance_taxable_wages: 45_000 + # 0.5% * 45,000 = 225.00. + hi_employee_temporary_disability_insurance_contribution: 225.00 + +- name: Hawaii ignores negative employment income. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: -5_000 + state_code: HI + output: + hi_temporary_disability_insurance_taxable_wages: 0 + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii contribution does not apply in other states. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 50_000 + state_code: CA + output: + hi_temporary_disability_insurance_taxable_wages: 0 + hi_employee_temporary_disability_insurance_contribution: 0 + hi_employee_state_payroll_tax: 0 + +- name: Hawaii caps each spouse's wages on their own. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + employment_income: 100_000 + person2: + employment_income: 40_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: HI + output: + # 52 * 1,500.21 = 78,010.92 for person1, and 40,000 is under the cap. + hi_temporary_disability_insurance_taxable_wages: [78_010.92, 40_000] + # 0.5% * 78,010.92 = 390.05 and 0.5% * 40,000 = 200.00. + hi_employee_temporary_disability_insurance_contribution: [390.05, 200.00] + # 390.05 + 200.00 = 590.05. + employee_state_payroll_tax: 590.05 diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/hi_employee_state_payroll_tax.py b/policyengine_us/variables/gov/states/hi/tax/payroll/hi_employee_state_payroll_tax.py new file mode 100644 index 00000000000..478d4e2b1ca --- /dev/null +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/hi_employee_state_payroll_tax.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class hi_employee_state_payroll_tax(Variable): + value_type = float + entity = Person + label = "Hawaii employee state payroll tax" + documentation = ( + "Employee-side Hawaii payroll-funded contributions. Hawaii's temporary " + "disability insurance contribution goes to the employer's plan or " + "insurer, not to the State." + ) + definition_period = YEAR + unit = USD + defined_for = StateCode.HI + adds = ["hi_employee_temporary_disability_insurance_contribution"] diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.py new file mode 100644 index 00000000000..2ef4f8075a0 --- /dev/null +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class hi_employee_temporary_disability_insurance_contribution(Variable): + value_type = float + entity = Person + label = "Hawaii employee temporary disability insurance contribution" + documentation = ( + "Employee-side Hawaii temporary disability insurance contribution at " + "the statutory limit. HRS 392-43(a) lets an employer withhold half the " + "cost of coverage, up to the employee rate times weekly wages, and " + "makes the employer pay the balance. Coverage cost varies by employer " + "and the model holds no premium data, so this assumes the employer " + "withholds the full rate limit." + ) + definition_period = YEAR + unit = USD + defined_for = StateCode.HI + reference = ( + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.hi.tax.payroll.temporary_disability_insurance + taxable_wages = person( + "hi_temporary_disability_insurance_taxable_wages", period + ) + return p.employee_rate * taxable_wages diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py new file mode 100644 index 00000000000..169675a4f6a --- /dev/null +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class hi_temporary_disability_insurance_qualified(Variable): + value_type = bool + entity = Person + label = "Wages count toward the Hawaii temporary disability insurance contribution" + documentation = ( + "HRS 392-43(b)(1) counts wages from a payroll period only if the prior " + "52 weeks hold enough wages and enough weeks with enough paid hours. " + "The model holds no prior-year work history, so this annual proxy tests " + "the simulation year's wages, weeks worked and usual weekly hours. Zero " + "weeks or zero hours mean the value went unreported, so that part of " + "the test passes." + ) + definition_period = YEAR + defined_for = StateCode.HI + reference = ( + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm", + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043_0005.htm", + ) + + def formula(person, period, parameters): + p = parameters( + period + ).gov.states.hi.tax.payroll.temporary_disability_insurance.qualification + wages = person("payroll_tax_gross_wages", period) + weeks = person("weeks_worked", period) + hours = person("weekly_hours_worked_before_lsr", period) + meets_wages = wages >= p.minimum_wages + meets_weeks = (weeks == 0) | (weeks >= p.minimum_weeks) + meets_hours = (hours == 0) | (hours >= p.minimum_weekly_hours) + return meets_wages & meets_weeks & meets_hours diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py new file mode 100644 index 00000000000..56683a68f2f --- /dev/null +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class hi_temporary_disability_insurance_taxable_wages(Variable): + value_type = float + entity = Person + label = "Hawaii temporary disability insurance taxable wages" + documentation = ( + "Wages subject to the Hawaii temporary disability insurance employee " + "contribution. HRS 392-3 excludes the payments HRS 383-11 lists, such " + "as employer-plan payments for medical expenses, so this starts from " + "payroll_tax_gross_wages. HRS 392-43(b)(2) caps wages week by week, so " + "the annual cap multiplies the maximum weekly wage base by weeks " + "worked, or by 52 when weeks worked went unreported. An even weekly " + "wage reaches the largest amount the weekly cap allows, so this amount " + "is an upper limit for a worker with one employer." + ) + definition_period = YEAR + unit = USD + defined_for = StateCode.HI + reference = ( + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0003.htm", + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm", + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.hi.tax.payroll.temporary_disability_insurance + wages = person("payroll_tax_gross_wages", period) + weeks = person("weeks_worked", period) + counted_weeks = where(weeks > 0, min_(weeks, WEEKS_IN_YEAR), WEEKS_IN_YEAR) + capped_wages = min_(wages, p.maximum_weekly_wage_base * counted_weeks) + qualified = person("hi_temporary_disability_insurance_qualified", period) + return where(qualified, capped_wages, 0) diff --git a/policyengine_us/variables/gov/states/tax/payroll/employee_state_payroll_tax.py b/policyengine_us/variables/gov/states/tax/payroll/employee_state_payroll_tax.py index 7956a031799..b7de702db7c 100644 --- a/policyengine_us/variables/gov/states/tax/payroll/employee_state_payroll_tax.py +++ b/policyengine_us/variables/gov/states/tax/payroll/employee_state_payroll_tax.py @@ -5,6 +5,7 @@ "co_employee_state_payroll_tax", "ct_employee_state_payroll_tax", "de_employee_state_payroll_tax", + "hi_employee_state_payroll_tax", "ma_employee_state_payroll_tax", "me_employee_state_payroll_tax", "mn_employee_state_payroll_tax", @@ -24,7 +25,10 @@ class employee_state_payroll_tax(Variable): label = "Employee state payroll taxes and contributions" documentation = ( "Employee-side mandatory state payroll taxes and payroll-funded " - "contributions, aggregated from jurisdiction-specific rules." + "contributions, aggregated from jurisdiction-specific rules. Hawaii " + "lets employers withhold its temporary disability insurance " + "contribution without requiring it, and the model assumes they " + "withhold the full limit." ) definition_period = YEAR unit = USD From 683f457d0b8509ec63518157a19abb20714ad02d Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 07:12:36 -0500 Subject: [PATCH 2/5] Define Hawaii TDI wages from HRS 392-3 and 383-11 The contribution read the federal payroll wage base, which rests on federal rules Hawaii did not enact. Hawaii's text leaves out what an employer pays to medical and retirement plans, including salary reductions, and lists no dependent care payment. Build wages from those two sections, record the reading as a source-conflict candidate with short excerpts, and restore the shared FICA list's start date, which only the federal base needed. Co-Authored-By: Claude Opus 5.5 --- .../fica_pre_tax_contributions.yaml | 2 +- .../excluded_payments.yaml | 31 ++++ .../test_hi_temporary_disability_insurance.py | 33 ++++- ...ary_disability_insurance_contribution.yaml | 48 +++++++ ..._temporary_disability_insurance_wages.yaml | 136 ++++++++++++++++++ ...emporary_disability_insurance_qualified.py | 2 +- ...rary_disability_insurance_taxable_wages.py | 16 +-- ...hi_temporary_disability_insurance_wages.py | 33 +++++ source_conflicts/candidates.yaml | 41 ++++++ .../dlir-ui-employer-handbook-excerpt.txt | 4 + .../sources/us-hi/hrs-383-11-excerpt.txt | 6 + .../sources/us-hi/hrs-392-3-excerpt.txt | 5 + 12 files changed, 344 insertions(+), 13 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml create mode 100644 policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py create mode 100644 source_conflicts/sources/us-hi/dlir-ui-employer-handbook-excerpt.txt create mode 100644 source_conflicts/sources/us-hi/hrs-383-11-excerpt.txt create mode 100644 source_conflicts/sources/us-hi/hrs-392-3-excerpt.txt diff --git a/policyengine_us/parameters/gov/irs/gross_income/fica_pre_tax_contributions.yaml b/policyengine_us/parameters/gov/irs/gross_income/fica_pre_tax_contributions.yaml index 21f01c7a19b..6834c47c44f 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/fica_pre_tax_contributions.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/fica_pre_tax_contributions.yaml @@ -1,6 +1,6 @@ description: Payroll deductions that reduce FICA (Social Security and Medicare) wages without a filing-status-specific cap. values: - 0000-01-01: + 2010-01-01: - pre_tax_health_insurance_premiums - health_savings_account_payroll_contributions # Dependent care assistance the employer reasonably believes excludable diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml new file mode 100644 index 00000000000..eabeee3af7a --- /dev/null +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml @@ -0,0 +1,31 @@ +description: Hawaii leaves these payments out of wages for the temporary disability insurance contribution. +values: + # HRS 383-11(1)(C) covers what an employer pays under a plan for medical or + # hospitalization expenses, including amounts paid for insurance or into a fund. + 0000-01-01: + - pre_tax_health_insurance_premiums + - health_savings_account_payroll_contributions + # The law did not change in 2015. The model's elective deferral limit starts + # then, and the contribution variables below read it. + 2015-01-01: + - pre_tax_health_insurance_premiums + - health_savings_account_payroll_contributions + # HRS 383-11(4)(A) covers what an employer pays on an individual's behalf to + # a trust described in IRC 401(a). It sets no condition on income tax + # treatment, so Roth deferrals come out with traditional ones. + - traditional_401k_contributions + - roth_401k_contributions + # HRS 383-11(1)(A) covers what an employer pays for annuities under a plan + # on account of retirement. + - traditional_403b_contributions + - roth_403b_contributions + +metadata: + period: year + unit: list + label: Hawaii TDI payments excluded from wages + reference: + - title: Hawaii Revised Statutes Section 392-3 + href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0003.htm + - title: Hawaii Revised Statutes Section 383-11 + href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm diff --git a/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py b/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py index 60f3a597a58..94419b1f595 100644 --- a/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py +++ b/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py @@ -69,6 +69,14 @@ 2026: ("64471.82", "1500.21", "7.50"), } YEARS = sorted(NOTICES) +# HRS 383-11(1)(A) and (4)(A). The model's elective deferral limit starts in 2015. +DEFERRALS = ( + "traditional_401k_contributions", + "roth_401k_contributions", + "traditional_403b_contributions", + "roth_403b_contributions", +) +FIRST_DEFERRAL_YEAR = 2015 GROUP_ENTITIES = ( "tax_units", "spm_units", @@ -105,6 +113,17 @@ def simulate(year, workers, **overrides): "age": {period: 40}, "employment_income": {period: worker["wages"]}, "pre_tax_health_insurance_premiums": {period: worker.get("premiums", 0)}, + "dependent_care_employer_benefits": { + period: worker.get("dependent_care", 0) + }, + **{ + kind: { + period: worker.get("deferral", 0) + if kind == worker.get("deferral_kind") + else 0 + } + for kind in DEFERRALS + }, "weeks_worked": {period: worker.get("weeks", 0)}, "weekly_hours_worked_before_lsr": {period: worker.get("hours", 0)}, **{name: {period: value} for name, value in overrides.items()}, @@ -144,6 +163,9 @@ def test_notice_follows_the_statutory_formula(year): st.integers(-5_000, 200_000), ), "premiums": st.one_of(st.just(0), st.integers(0, 10_000)), + "deferral": st.one_of(st.just(0), st.integers(0, 10_000)), + "deferral_kind": st.sampled_from(DEFERRALS), + "dependent_care": st.one_of(st.just(0), st.integers(0, 5_000)), "weeks": st.one_of(st.sampled_from([0, 13, 14, 52]), st.integers(1, 52)), "hours": st.one_of(st.sampled_from([0, 19, 20, 40]), st.integers(1, 80)), } @@ -165,8 +187,17 @@ def test_contribution_properties(year, batch, bump): ).calculate(CONTRIBUTION, period) in_hawaii = np.array([worker["state"] == "HI" for worker in batch]) + counts_deferral = year >= FIRST_DEFERRAL_YEAR wages = np.array( - [max(0, worker["wages"] - worker["premiums"]) for worker in batch], + [ + max( + 0, + worker["wages"] + - worker["premiums"] + - (worker["deferral"] if counts_deferral else 0), + ) + for worker in batch + ], dtype=float, ) weeks = np.array([worker["weeks"] or 52 for worker in batch], dtype=float) diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml index b93c535e742..d4499fbfed0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml @@ -242,6 +242,54 @@ # 0.5% * 45,000 = 225.00. hi_employee_temporary_disability_insurance_contribution: 225.00 +- name: Hawaii leaves a 401(k) deferral out of the contribution. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + traditional_401k_contributions: 4_000 + state_code: HI + output: + # 60,000 - 4,000 = 56,000, and 0.5% * 56,000 = 280.00. + hi_employee_temporary_disability_insurance_contribution: 280.00 + +- name: Hawaii counts dependent care benefits in the contribution. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + dependent_care_employer_benefits: 5_000 + state_code: HI + output: + # 0.5% * 60,000 = 300.00. + hi_employee_temporary_disability_insurance_contribution: 300.00 + +- name: Hawaii still applies the cap when wages after a deferral exceed it. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 100_000 + traditional_401k_contributions: 10_000 + state_code: HI + output: + # 100,000 - 10,000 = 90,000 exceeds 52 * 1,500.21 = 78,010.92. + hi_temporary_disability_insurance_taxable_wages: 78_010.92 + # 0.5% * 78,010.92 = 390.05. + hi_employee_temporary_disability_insurance_contribution: 390.05 + +- name: Hawaii tests the 400 minimum against wages after excluded payments. + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 1_000 + traditional_401k_contributions: 700 + state_code: HI + output: + # 1,000 - 700 = 300, under 400. + hi_temporary_disability_insurance_wages: 300 + hi_temporary_disability_insurance_qualified: false + hi_employee_temporary_disability_insurance_contribution: 0 + - name: Hawaii ignores negative employment income. period: 2024 absolute_error_margin: 0.01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml new file mode 100644 index 00000000000..e5f20e41f8a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml @@ -0,0 +1,136 @@ +# HRS 392-3 counts all remuneration and leaves out the payments HRS 383-11 lists. +# The expected values below subtract those payments by hand. + +- name: Hawaii wages leave out a traditional 401(k) deferral. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + traditional_401k_contributions: 4_000 + state_code: HI + output: + # HRS 383-11(4)(A): 60,000 - 4,000 = 56,000. + hi_temporary_disability_insurance_wages: 56_000 + # The federal base keeps the deferral. + payroll_tax_gross_wages: 60_000 + +- name: Hawaii wages leave out a Roth 401(k) deferral. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + roth_401k_contributions: 4_000 + state_code: HI + output: + # HRS 383-11(4)(A) sets no income tax condition: 60,000 - 4,000 = 56,000. + hi_temporary_disability_insurance_wages: 56_000 + +- name: Hawaii wages leave out traditional and Roth 403(b) deferrals. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + traditional_403b_contributions: 3_000 + roth_403b_contributions: 1_000 + state_code: HI + output: + # HRS 383-11(1)(A): 60,000 - 3,000 - 1,000 = 56,000. + hi_temporary_disability_insurance_wages: 56_000 + +- name: Hawaii wages leave out pre-tax health premiums and payroll HSA contributions. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + pre_tax_health_insurance_premiums: 3_000 + health_savings_account_payroll_contributions: 2_000 + state_code: HI + output: + # HRS 383-11(1)(C): 60,000 - 3,000 - 2,000 = 55,000. + hi_temporary_disability_insurance_wages: 55_000 + +- name: Hawaii wages keep dependent care benefits, which HRS 383-11 does not list. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + dependent_care_employer_benefits: 5_000 + state_code: HI + output: + hi_temporary_disability_insurance_wages: 60_000 + # The federal base removes them: 60,000 - 5,000 = 55,000. + payroll_tax_gross_wages: 55_000 + +- name: Hawaii wages leave out only the deferral the 2026 limit allows. + period: 2026 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 100_000 + traditional_401k_contributions_desired: 30_000 + state_code: HI + output: + # The 2026 limit under age 50 is 24,500: 100,000 - 24,500 = 75,500. + traditional_401k_contributions: 24_500 + hi_temporary_disability_insurance_wages: 75_500 + +- name: Hawaii wages leave out deferrals in 2015, the first year the model holds a limit. + period: 2015 + absolute_error_margin: 0.01 + input: + age: 55 + employment_income: 60_000 + traditional_401k_contributions: 4_000 + state_code: HI + output: + # 60,000 - 4,000 = 56,000. + hi_temporary_disability_insurance_wages: 56_000 + +- name: Hawaii wages keep deferrals in 2014, before the model holds a limit. + period: 2014 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + traditional_401k_contributions: 4_000 + state_code: HI + output: + hi_temporary_disability_insurance_wages: 60_000 + +- name: Hawaii wages leave out premiums in 2004. + period: 2004 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + pre_tax_health_insurance_premiums: 3_000 + state_code: HI + output: + # 60,000 - 3,000 = 57,000. + hi_temporary_disability_insurance_wages: 57_000 + +- name: Hawaii wages stop at zero when excluded payments exceed pay. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 3_000 + pre_tax_health_insurance_premiums: 5_000 + state_code: HI + output: + hi_temporary_disability_insurance_wages: 0 + +- name: Hawaii wages stop at zero for negative employment income. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: -5_000 + state_code: HI + output: + hi_temporary_disability_insurance_wages: 0 + +- name: Hawaii wages do not apply in other states. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + state_code: NV + output: + hi_temporary_disability_insurance_wages: 0 diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py index 169675a4f6a..bdf1c1aa4b0 100644 --- a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py @@ -24,7 +24,7 @@ def formula(person, period, parameters): p = parameters( period ).gov.states.hi.tax.payroll.temporary_disability_insurance.qualification - wages = person("payroll_tax_gross_wages", period) + wages = person("hi_temporary_disability_insurance_wages", period) weeks = person("weeks_worked", period) hours = person("weekly_hours_worked_before_lsr", period) meets_wages = wages >= p.minimum_wages diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py index 56683a68f2f..a654e9f9737 100644 --- a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py @@ -7,26 +7,22 @@ class hi_temporary_disability_insurance_taxable_wages(Variable): label = "Hawaii temporary disability insurance taxable wages" documentation = ( "Wages subject to the Hawaii temporary disability insurance employee " - "contribution. HRS 392-3 excludes the payments HRS 383-11 lists, such " - "as employer-plan payments for medical expenses, so this starts from " - "payroll_tax_gross_wages. HRS 392-43(b)(2) caps wages week by week, so " - "the annual cap multiplies the maximum weekly wage base by weeks " - "worked, or by 52 when weeks worked went unreported. An even weekly " - "wage reaches the largest amount the weekly cap allows, so this amount " - "is an upper limit for a worker with one employer." + "contribution. HRS 392-43(b)(2) caps wages week by week, so the annual " + "cap multiplies the maximum weekly wage base by weeks worked, or by 52 " + "when weeks worked went unreported. An even weekly wage reaches the " + "largest amount the weekly cap allows, so this amount is an upper limit " + "for a worker with one employer." ) definition_period = YEAR unit = USD defined_for = StateCode.HI reference = ( - "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0003.htm", - "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm", "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm", ) def formula(person, period, parameters): p = parameters(period).gov.states.hi.tax.payroll.temporary_disability_insurance - wages = person("payroll_tax_gross_wages", period) + wages = person("hi_temporary_disability_insurance_wages", period) weeks = person("weeks_worked", period) counted_weeks = where(weeks > 0, min_(weeks, WEEKS_IN_YEAR), WEEKS_IN_YEAR) capped_wages = min_(wages, p.maximum_weekly_wage_base * counted_weeks) diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py new file mode 100644 index 00000000000..38ca933b356 --- /dev/null +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class hi_temporary_disability_insurance_wages(Variable): + value_type = float + entity = Person + label = "Hawaii temporary disability insurance wages" + documentation = ( + "Wages as HRS 392-3 defines them: all remuneration, less the payments " + "HRS 383-11 lists. That list covers what an employer pays under a plan " + "for medical expenses or retirement and what it pays to a trust " + "described in IRC 401(a). HRS 383-11(5) stops at payments made without " + "a deduction from pay, and paragraphs (1) and (4) carry no such limit, " + "so salary-reduction amounts for these plans come out. The list names " + "no dependent care payment, so dependent care benefits stay in. The " + "federal payroll wage base differs because Congress added rules for " + "elective deferrals, cafeteria plans and dependent care that Hawaii did " + "not enact. Before 2015 retirement deferrals stay in, because the " + "model's elective deferral limit starts in 2015." + ) + definition_period = YEAR + unit = USD + defined_for = StateCode.HI + reference = ( + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0003.htm", + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.hi.tax.payroll.temporary_disability_insurance + remuneration = person("employment_income", period) + excluded = add(person, period, p.excluded_payments) + return max_(remuneration - excluded, 0) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 43d9aa13941..30d49067efe 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -2933,6 +2933,47 @@ candidates: prs: [] state: unreviewed note: PE-US follows state rules; verify their effective text throughout the historical periods. +- id: us-hi:tdi-wages-salary-reductions + program: hi-tdi + years: + from: 2004 + type: calendar + question: Do amounts an employer pays into a retirement or medical plan out of an employee's salary count as wages for + Hawaii's temporary disability insurance contribution, and do dependent care benefits? + sources: + - kind: statute + citation: HRS 392-3 (wages), adopting HRS 383-11(1)(A), (1)(C), (4)(A) and (5) + url: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm + - kind: regulation + citation: HAR 12-11-1, which takes wages from HRS 392-3 and says nothing on salary reductions + url: https://labor.hawaii.gov/dcd/files/2012/11/TDI-Admin-Rules.pdf#page=5 + - kind: guidance + citation: Hawaii DLIR Unemployment Insurance Division, Handbook for Employers, on the wages that chapter 383 reaches + url: https://labor.hawaii.gov/ui/test-handbook-for-employers/ + readings: + statute: A salary-reduction amount the employer pays under a medical or retirement plan, or to a section 401(a) trust, + is a listed payment, so it falls outside wages. HRS 383-11(5) limits one paragraph to payments without a deduction + from pay, and paragraphs (1) and (4) carry no such limit. The list names no dependent care payment, so those benefits + stay in wages. + other: The federal payroll wage base keeps elective deferrals in and takes cafeteria-plan amounts and dependent care + out, through IRC 3306(r)(1)(A), (b)(5)(G) and (b)(13), which Hawaii did not enact. A second alternative treats every + salary reduction as the employee's own remuneration, so all of it stays in wages. The rule and the handbook address + neither alternative. + example: In 2026, $60,000 of salary with a $4,000 traditional 401(k) deferral gives a $280 contribution under the statute, + versus $300 on the federal base. $60,000 with $5,000 of dependent care benefits gives $300, versus $275 on the federal + base. + pe_us: + follows: statute + code: + - policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml + - policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10677 + state: ruled + note: The code follows the statute's text because we found no agency reading of salary reductions in the temporary + disability rules, the unemployment insurance rules (HAR 12-5) or the employer handbook. A published agency reading + would reopen this under the agency-breaks-ties principle if the text leaves the question open. Short excerpts are + in source_conflicts/sources/us-hi/. - id: us-ia:alternate-tax-claimed-spouse program: income-tax years: diff --git a/source_conflicts/sources/us-hi/dlir-ui-employer-handbook-excerpt.txt b/source_conflicts/sources/us-hi/dlir-ui-employer-handbook-excerpt.txt new file mode 100644 index 00000000000..6e4177c7678 --- /dev/null +++ b/source_conflicts/sources/us-hi/dlir-ui-employer-handbook-excerpt.txt @@ -0,0 +1,4 @@ +Source: https://labor.hawaii.gov/ui/test-handbook-for-employers/ +Short excerpt of the employer handbook's wages section, copied from the official HTML page. + +a few exclusions, such as payments to welfare plans, pension payments to retired workers diff --git a/source_conflicts/sources/us-hi/hrs-383-11-excerpt.txt b/source_conflicts/sources/us-hi/hrs-383-11-excerpt.txt new file mode 100644 index 00000000000..360e1fc0bfa --- /dev/null +++ b/source_conflicts/sources/us-hi/hrs-383-11-excerpt.txt @@ -0,0 +1,6 @@ +Source: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm +Short excerpts of HRS 383-11(4), (4)(A) and (5), copied from the official HTML page. + +any payment by an employing unit to, or on behalf of, an individual +to a trust described in section 401(a) +without deduction from the remuneration diff --git a/source_conflicts/sources/us-hi/hrs-392-3-excerpt.txt b/source_conflicts/sources/us-hi/hrs-392-3-excerpt.txt new file mode 100644 index 00000000000..c8ecd53b1d7 --- /dev/null +++ b/source_conflicts/sources/us-hi/hrs-392-3-excerpt.txt @@ -0,0 +1,5 @@ +Source: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0003.htm +Short excerpts of the definition of wages in HRS 392-3, copied from the official HTML page. + +all remuneration for services +Wages do not include the amount of any payment specified in section 383-11 From 8c4c9ce8d04ee70dd9020b2968915f751f650fe2 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 9 Nov 2026 08:29:45 -0500 Subject: [PATCH 3/5] Apply first review's fixes to Hawaii TDI Leave military basic pay out of Hawaii wages under HRS 392-5(6), let the wages test pass on the previous year's weeks and hours, and take retirement deferrals out from 2004. Extend the federal elective deferral and catch-up limits back to 2004 from the IRS table, which also corrects 2015-2017 to $18,000. Add the program to programs.yaml, split the source-conflict regulation captures by page, and update the Hawaii marginal rate case for the contribution. Co-Authored-By: Claude Opus 5.5 --- .../hi-tdi-employee-contribution.fixed.md | 1 + .../catch_up/age_threshold.yaml | 2 +- .../catch_up/limit/k401.yaml | 30 ++- .../retirement_contributions/limit/401k.yaml | 10 +- .../excluded_payments.yaml | 12 +- policyengine_us/programs.yaml | 12 + .../test_hi_temporary_disability_insurance.py | 57 ++++- .../medicare/test_irmaa_first_modeled_year.py | 4 +- .../retirement/k401_catch_up_limit.yaml | 45 ++++ ...ary_disability_insurance_contribution.yaml | 224 ++++++++++++++++++ ..._temporary_disability_insurance_wages.yaml | 52 +++- .../retirement/elective_deferral_limit.yaml | 59 +++++ ...al_tax_rate_including_health_benefits.yaml | 4 +- ...emporary_disability_insurance_qualified.py | 27 ++- ...rary_disability_insurance_taxable_wages.py | 3 +- ...hi_temporary_disability_insurance_wages.py | 8 +- source_conflicts/candidates.yaml | 9 +- .../sources/us-hi/har-12-11-excerpt.txt | 5 + .../sources/us-hi/hrs-383-11-excerpt.txt | 10 +- 19 files changed, 531 insertions(+), 43 deletions(-) create mode 100644 changelog.d/hi-tdi-employee-contribution.fixed.md create mode 100644 source_conflicts/sources/us-hi/har-12-11-excerpt.txt diff --git a/changelog.d/hi-tdi-employee-contribution.fixed.md b/changelog.d/hi-tdi-employee-contribution.fixed.md new file mode 100644 index 00000000000..97b419cc5d9 --- /dev/null +++ b/changelog.d/hi-tdi-employee-contribution.fixed.md @@ -0,0 +1 @@ +Extend the federal 401(k) elective deferral and catch-up limits back to 2004 from the IRS cost-of-living table, which sets the 2015 through 2017 elective deferral limit at $18,000 rather than $18,500. diff --git a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/age_threshold.yaml b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/age_threshold.yaml index e9fce231f72..ed255c327a3 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/age_threshold.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/age_threshold.yaml @@ -1,6 +1,6 @@ description: The US limits catch-up pension contributions to individuals this age or older. values: - 2021-01-01: 50 + 2004-01-01: 50 metadata: unit: year period: year diff --git a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/limit/k401.yaml b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/limit/k401.yaml index 6bb4db946b3..cd2977c7be7 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/limit/k401.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/limit/k401.yaml @@ -3,16 +3,20 @@ description: The IRS limits 401(k) catch-up contributions to this amount based o brackets: - threshold: values: - 2018-01-01: 0 + 2004-01-01: 0 amount: values: - 2018-01-01: 0 + 2004-01-01: 0 - threshold: values: - 2018-01-01: 50 + 2004-01-01: 50 amount: values: - 2018-01-01: 6_000 + 2004-01-01: 3_000 + 2005-01-01: 4_000 + 2006-01-01: 5_000 + 2009-01-01: 5_500 + 2015-01-01: 6_000 2020-01-01: 6_500 2023-01-01: 7_500 2024-01-01: 7_500 @@ -26,10 +30,14 @@ brackets: interval: 500 - threshold: values: - 2018-01-01: 60 + 2004-01-01: 60 amount: values: - 2018-01-01: 6_000 + 2004-01-01: 3_000 + 2005-01-01: 4_000 + 2006-01-01: 5_000 + 2009-01-01: 5_500 + 2015-01-01: 6_000 2020-01-01: 6_500 2023-01-01: 7_500 2024-01-01: 7_500 @@ -45,10 +53,14 @@ brackets: interval: 500 - threshold: values: - 2018-01-01: 64 + 2004-01-01: 64 amount: values: - 2018-01-01: 6_000 + 2004-01-01: 3_000 + 2005-01-01: 4_000 + 2006-01-01: 5_000 + 2009-01-01: 5_500 + 2015-01-01: 6_000 2020-01-01: 6_500 2023-01-01: 7_500 2024-01-01: 7_500 @@ -75,5 +87,5 @@ metadata: href: https://www.irs.gov/newsroom/401k-limit-increases-to-23500-for-2025-ira-limit-remains-7000 - title: IRS announcement - 401(k) limit increases for 2026 href: https://www.irs.gov/newsroom/401k-limit-increases-to-24500-for-2026-ira-limit-increases-to-7500 - - title: Cost-of-Living Adjustments for Retirement Items + - title: "Cost-of-Living Adjustments for Retirement Items #page 1,3-6" href: https://www.irs.gov/pub/irs-tege/cola-table.pdf#page=1 diff --git a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/limit/401k.yaml b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/limit/401k.yaml index 77a423bfe68..925f7b6f8ca 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/limit/401k.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/limit/401k.yaml @@ -1,5 +1,13 @@ description: The US limits annual 401(k) contributions to this amount. values: + 2004-01-01: 13_000 + 2005-01-01: 14_000 + 2006-01-01: 15_000 + 2007-01-01: 15_500 + 2009-01-01: 16_500 + 2012-01-01: 17_000 + 2013-01-01: 17_500 + 2015-01-01: 18_000 2018-01-01: 18_500 2019-01-01: 19_000 2020-01-01: 19_500 @@ -21,5 +29,5 @@ metadata: - title: 26 CFR § 1.402(g)-1 - Limitation on exclusion for elective deferrals. (d))(i) href: https://law.cornell.edu/cfr/text/26/1.402(g)-1 # Inflation adjusted amounts - - title: Cost-of-Living Adjustments for Retirement Items + - title: "Cost-of-Living Adjustments for Retirement Items #page 1,3-6" href: https://www.irs.gov/pub/irs-tege/cola-table.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml index eabeee3af7a..57d792c0c21 100644 --- a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml @@ -2,14 +2,18 @@ description: Hawaii leaves these payments out of wages for the temporary disabil values: # HRS 383-11(1)(C) covers what an employer pays under a plan for medical or # hospitalization expenses, including amounts paid for insurance or into a fund. + # HRS 392-5(6) leaves service in the employ of the United States government + # out of employment. 0000-01-01: - pre_tax_health_insurance_premiums - health_savings_account_payroll_contributions - # The law did not change in 2015. The model's elective deferral limit starts - # then, and the contribution variables below read it. - 2015-01-01: + - military_basic_pay + # The law did not change in 2004. The federal elective deferral limit that the + # contribution variables below read starts then, as does the contribution rate. + 2004-01-01: - pre_tax_health_insurance_premiums - health_savings_account_payroll_contributions + - military_basic_pay # HRS 383-11(4)(A) covers what an employer pays on an individual's behalf to # a trust described in IRC 401(a). It sets no condition on income tax # treatment, so Roth deferrals come out with traditional ones. @@ -27,5 +31,7 @@ metadata: reference: - title: Hawaii Revised Statutes Section 392-3 href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0003.htm + - title: Hawaii Revised Statutes Section 392-5 + href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0005.htm - title: Hawaii Revised Statutes Section 383-11 href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 95ca1cfdbfe..77530634aba 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -2189,6 +2189,18 @@ programs: variable: ca_fera parameter_prefix: gov.states.ca.cpuc.fera + - id: hi_tdi + name: Hawaii Temporary Disability Insurance + full_name: Hawaii Temporary Disability Insurance employee contribution + category: Taxes + agency: Hawaii Department of Labor and Industrial Relations + status: partial + coverage: HI + variable: hi_employee_temporary_disability_insurance_contribution + parameter_prefix: gov.states.hi.tax.payroll.temporary_disability_insurance + verified_start_year: 2004 + notes: Models the employee contribution at the HRS 392-43(a) limit; benefits and employer costs are out of scope. + - id: il_fpp name: Illinois Family Planning Program full_name: Illinois HFS Family Planning Program diff --git a/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py b/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py index 94419b1f595..072a4677fa1 100644 --- a/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py +++ b/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py @@ -12,7 +12,9 @@ least the weekly sum, and the two match when wages are even. 3. Properties across drawn batches of workers: bounds, monotonicity in wages, state masking, and aggregation to the tax unit. -4. Net income. Removing the contribution raises household net income by exactly +4. Qualification. Previous-year history can only add workers, and exactly the + workers whose history clears the weeks and hours minimums. +5. Net income. Removing the contribution raises household net income by exactly the contribution. Intended differences from the published figures: @@ -37,6 +39,7 @@ from policyengine_us.system import system as SYSTEM CONTRIBUTION = "hi_employee_temporary_disability_insurance_contribution" +QUALIFIED = "hi_temporary_disability_insurance_qualified" TOLERANCE = 0.01 # dollars RATE = Decimal("0.005") # HRS 392-43(a) FACTOR = Decimal("1.21") # HRS 392-43(b)(2) @@ -69,14 +72,13 @@ 2026: ("64471.82", "1500.21", "7.50"), } YEARS = sorted(NOTICES) -# HRS 383-11(1)(A) and (4)(A). The model's elective deferral limit starts in 2015. +# HRS 383-11(1)(A) and (4)(A). DEFERRALS = ( "traditional_401k_contributions", "roth_401k_contributions", "traditional_403b_contributions", "roth_403b_contributions", ) -FIRST_DEFERRAL_YEAR = 2015 GROUP_ENTITIES = ( "tax_units", "spm_units", @@ -106,6 +108,7 @@ def base_for(year): def simulate(year, workers, **overrides): period = str(year) + previous = str(year - 1) situation = {"people": {}, **{entity: {} for entity in GROUP_ENTITIES}} for i, worker in enumerate(workers): person = f"person_{i}" @@ -113,6 +116,7 @@ def simulate(year, workers, **overrides): "age": {period: 40}, "employment_income": {period: worker["wages"]}, "pre_tax_health_insurance_premiums": {period: worker.get("premiums", 0)}, + "military_basic_pay": {period: worker.get("military", 0)}, "dependent_care_employer_benefits": { period: worker.get("dependent_care", 0) }, @@ -124,8 +128,14 @@ def simulate(year, workers, **overrides): } for kind in DEFERRALS }, - "weeks_worked": {period: worker.get("weeks", 0)}, - "weekly_hours_worked_before_lsr": {period: worker.get("hours", 0)}, + "weeks_worked": { + previous: worker.get("previous_weeks", 0), + period: worker.get("weeks", 0), + }, + "weekly_hours_worked_before_lsr": { + previous: worker.get("previous_hours", 0), + period: worker.get("hours", 0), + }, **{name: {period: value} for name, value in overrides.items()}, } for entity in GROUP_ENTITIES: @@ -163,6 +173,7 @@ def test_notice_follows_the_statutory_formula(year): st.integers(-5_000, 200_000), ), "premiums": st.one_of(st.just(0), st.integers(0, 10_000)), + "military": st.one_of(st.just(0), st.integers(0, 10_000)), "deferral": st.one_of(st.just(0), st.integers(0, 10_000)), "deferral_kind": st.sampled_from(DEFERRALS), "dependent_care": st.one_of(st.just(0), st.integers(0, 5_000)), @@ -187,14 +198,14 @@ def test_contribution_properties(year, batch, bump): ).calculate(CONTRIBUTION, period) in_hawaii = np.array([worker["state"] == "HI" for worker in batch]) - counts_deferral = year >= FIRST_DEFERRAL_YEAR wages = np.array( [ max( 0, worker["wages"] - worker["premiums"] - - (worker["deferral"] if counts_deferral else 0), + - worker["military"] + - worker["deferral"], ) for worker in batch ], @@ -219,6 +230,38 @@ def test_contribution_properties(year, batch, bump): ] == pytest.approx(contribution[in_hawaii], abs=TOLERANCE) +@settings(**SETTINGS) +@given( + year=st.sampled_from(YEARS), + batch=st.lists( + st.tuples( + workers, + st.sampled_from([0, 13, 14, 52]), + st.sampled_from([0, 19, 20, 40]), + ), + min_size=5, + max_size=30, + ), +) +def test_previous_year_history_only_adds_workers_who_clear_it(year, batch): + period = str(year) + alone = simulate(year, [worker for worker, _, _ in batch]).calculate( + QUALIFIED, period + ) + with_history = simulate( + year, + [ + {**worker, "previous_weeks": weeks, "previous_hours": hours} + for worker, weeks, hours in batch + ], + ).calculate(QUALIFIED, period) + + in_hawaii = np.array([worker["state"] == "HI" for worker, _, _ in batch]) + clears = np.array([weeks >= 14 and hours >= 20 for _, weeks, hours in batch]) + assert (with_history[in_hawaii] == (alone | clears)[in_hawaii]).all() + assert not with_history[~in_hawaii].any() + + # At least 14 weeks of at least 30 dollars clears the $400 and 14-week test. weekly_wages = st.lists(st.integers(30, 4_000), min_size=14, max_size=52) diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicare/test_irmaa_first_modeled_year.py b/policyengine_us/tests/policy/baseline/gov/hhs/medicare/test_irmaa_first_modeled_year.py index d2a94141895..adf1ee8df81 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicare/test_irmaa_first_modeled_year.py +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicare/test_irmaa_first_modeled_year.py @@ -57,8 +57,8 @@ def test_first_modeled_year_is_the_backdating_floor(): # The constant must match how far CountryTaxBenefitSystem backdates: a # parameter first dated after the floor is defined from it, not before. limit = SYSTEM.parameters.gov.irs.gross_income.retirement_contributions.limit - assert limit.children["401k"](f"{FIRST_MODELED_YEAR}-01-01") > 0 - assert limit.children["401k"](f"{FIRST_MODELED_YEAR - 1}-12-31") is None + assert limit.children["ira"](f"{FIRST_MODELED_YEAR}-01-01") > 0 + assert limit.children["ira"](f"{FIRST_MODELED_YEAR - 1}-12-31") is None @pytest.mark.parametrize("year", UNMODELED_LAG_YEARS) diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/retirement/k401_catch_up_limit.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/retirement/k401_catch_up_limit.yaml index 81bb15a436e..0b75d6afefd 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/retirement/k401_catch_up_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/retirement/k401_catch_up_limit.yaml @@ -125,3 +125,48 @@ age: 64 output: k401_catch_up_limit: 8_000 + +# Earlier years come from the IRS cost-of-living table, 414(v)(2)(B)(i), +# https://www.irs.gov/pub/irs-tege/cola-table.pdf. + +- name: Case 18, age 49 in 2004 receives no catch-up. + period: 2004 + input: + age: 49 + output: + k401_catch_up_limit: 0 + +- name: Case 19, age 50 in 2004 receives 2004 standard limit. + period: 2004 + input: + age: 50 + output: + k401_catch_up_limit: 3_000 + +- name: Case 20, age 50 in 2008 receives 2008 standard limit. + period: 2008 + input: + age: 50 + output: + k401_catch_up_limit: 5_000 + +- name: Case 21, age 62 in 2009 receives 2009 standard limit. + period: 2009 + input: + age: 62 + output: + k401_catch_up_limit: 5_500 + +- name: Case 22, age 50 in 2014 receives 2014 standard limit. + period: 2014 + input: + age: 50 + output: + k401_catch_up_limit: 5_500 + +- name: Case 23, age 50 in 2017 receives 2017 standard limit. + period: 2017 + input: + age: 50 + output: + k401_catch_up_limit: 6_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml index d4499fbfed0..c3b183457b5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml @@ -334,3 +334,227 @@ hi_employee_temporary_disability_insurance_contribution: [390.05, 200.00] # 390.05 + 200.00 = 590.05. employee_state_payroll_tax: 590.05 + +- name: Hawaii leaves a 2014 deferral out of the contribution. + period: 2014 + absolute_error_margin: 0.01 + input: + employment_income: 30_000 + traditional_401k_contributions: 4_000 + state_code: HI + output: + # 0.5% * (30,000 - 4,000) = 130, under 52 * 940.05 = 48,882.60. + hi_employee_temporary_disability_insurance_contribution: 130 + +- name: Hawaii leaves out only the deferral the 2009 limit allows. + period: 2009 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 50_000 + traditional_401k_contributions_desired: 20_000 + state_code: HI + output: + # 50,000 - 16,500 = 33,500, under 52 * 877.69 = 45,639.88. + hi_temporary_disability_insurance_wages: 33_500 + # 0.5% * 33,500 = 167.50. + hi_employee_temporary_disability_insurance_contribution: 167.50 + +- name: Hawaii leaves out a 2009 catch-up deferral. + period: 2009 + absolute_error_margin: 0.01 + input: + age: 55 + employment_income: 50_000 + traditional_401k_contributions_desired: 25_000 + state_code: HI + output: + # 16,500 + 5,500 = 22,000 of deferrals, and 50,000 - 22,000 = 28,000. + hi_temporary_disability_insurance_wages: 28_000 + # 0.5% * 28,000 = 140. + hi_employee_temporary_disability_insurance_contribution: 140 + +- name: Hawaii charges no contribution on active-duty pay alone. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + military_basic_pay: 60_000 + state_code: HI + output: + hi_temporary_disability_insurance_wages: 0 + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii charges a service member's civilian wages. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 70_000 + military_basic_pay: 60_000 + state_code: HI + output: + # 0.5% * (70,000 - 60,000) = 50. + hi_employee_temporary_disability_insurance_contribution: 50 + +- name: Hawaii counts a short final year when the previous year passes. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + employment_income: + 2025: 52_000 + 2026: 1_000 + weeks_worked: + 2025: 52 + 2026: 1 + weekly_hours_worked_before_lsr: + 2025: 40 + 2026: 40 + households: + household: + members: [person1] + state_code: HI + output: + hi_temporary_disability_insurance_qualified: true + # One week's 1,000 falls under the 1,500.21 cap: 0.5% * 1,000 = 5. + hi_employee_temporary_disability_insurance_contribution: 5 + +- name: Hawaii counts final-year wages under 400 when the previous year passes. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + employment_income: + 2025: 52_000 + 2026: 300 + weeks_worked: + 2025: 52 + 2026: 1 + weekly_hours_worked_before_lsr: + 2025: 40 + 2026: 40 + households: + household: + members: [person1] + state_code: HI + output: + hi_temporary_disability_insurance_qualified: true + # 0.5% * 300 = 1.50. + hi_employee_temporary_disability_insurance_contribution: 1.50 + +- name: Hawaii passes a previous year at exactly 14 weeks and 20 hours. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + employment_income: + 2025: 10_000 + 2026: 1_000 + weeks_worked: + 2025: 14 + 2026: 1 + weekly_hours_worked_before_lsr: + 2025: 20 + 2026: 40 + households: + household: + members: [person1] + state_code: HI + output: + hi_temporary_disability_insurance_qualified: true + hi_employee_temporary_disability_insurance_contribution: 5 + +- name: Hawaii does not pass a previous year of 13 weeks. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + employment_income: + 2025: 10_000 + 2026: 1_000 + weeks_worked: + 2025: 13 + 2026: 1 + weekly_hours_worked_before_lsr: + 2025: 40 + 2026: 40 + households: + household: + members: [person1] + state_code: HI + output: + hi_temporary_disability_insurance_qualified: false + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii does not pass a previous year under 20 hours a week. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + employment_income: + 2025: 10_000 + 2026: 1_000 + weeks_worked: + 2025: 52 + 2026: 1 + weekly_hours_worked_before_lsr: + 2025: 19 + 2026: 40 + households: + household: + members: [person1] + state_code: HI + output: + hi_temporary_disability_insurance_qualified: false + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii does not read unreported previous-year hours as a pass. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + employment_income: + 2025: 52_000 + 2026: 1_000 + weeks_worked: + 2025: 52 + 2026: 1 + weekly_hours_worked_before_lsr: + 2026: 40 + households: + household: + members: [person1] + state_code: HI + output: + hi_temporary_disability_insurance_qualified: false + hi_employee_temporary_disability_insurance_contribution: 0 + +- name: Hawaii passes on the simulation year when the previous year fails. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + employment_income: + 2025: 1_000 + 2026: 20_000 + weeks_worked: + 2025: 2 + 2026: 52 + weekly_hours_worked_before_lsr: + 2025: 40 + 2026: 40 + households: + household: + members: [person1] + state_code: HI + output: + hi_temporary_disability_insurance_qualified: true + # 0.5% * 20,000 = 100. + hi_employee_temporary_disability_insurance_contribution: 100 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml index e5f20e41f8a..cd0ca7d9c86 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml @@ -74,8 +74,8 @@ traditional_401k_contributions: 24_500 hi_temporary_disability_insurance_wages: 75_500 -- name: Hawaii wages leave out deferrals in 2015, the first year the model holds a limit. - period: 2015 +- name: Hawaii wages leave out deferrals in 2004, the first year the model holds a limit. + period: 2004 absolute_error_margin: 0.01 input: age: 55 @@ -86,9 +86,33 @@ # 60,000 - 4,000 = 56,000. hi_temporary_disability_insurance_wages: 56_000 -- name: Hawaii wages keep deferrals in 2014, before the model holds a limit. +- name: Hawaii wages leave out only the deferral the 2004 limit allows. + period: 2004 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 100_000 + traditional_401k_contributions_desired: 30_000 + state_code: HI + output: + # The 2004 limit under age 50 is 13,000: 100,000 - 13,000 = 87,000. + traditional_401k_contributions: 13_000 + hi_temporary_disability_insurance_wages: 87_000 + +- name: Hawaii wages leave out deferrals in 2014. period: 2014 absolute_error_margin: 0.01 + input: + employment_income: 60_000 + traditional_401k_contributions: 4_000 + state_code: HI + output: + # 60,000 - 4,000 = 56,000. + hi_temporary_disability_insurance_wages: 56_000 + +- name: Hawaii wages keep deferrals in 2003, before the model holds a limit. + period: 2003 + absolute_error_margin: 0.01 input: employment_income: 60_000 traditional_401k_contributions: 4_000 @@ -96,6 +120,28 @@ output: hi_temporary_disability_insurance_wages: 60_000 +- name: Hawaii wages leave out military basic pay. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + military_basic_pay: 60_000 + state_code: HI + output: + # HRS 392-5(6): 60,000 - 60,000 = 0. + hi_temporary_disability_insurance_wages: 0 + +- name: Hawaii wages keep a service member's civilian pay. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 70_000 + military_basic_pay: 60_000 + state_code: HI + output: + # 70,000 - 60,000 = 10,000. + hi_temporary_disability_insurance_wages: 10_000 + - name: Hawaii wages leave out premiums in 2004. period: 2004 absolute_error_margin: 0.01 diff --git a/policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_limit.yaml b/policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_limit.yaml index 1b435e8471c..2f23757cd22 100644 --- a/policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_limit.yaml +++ b/policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_limit.yaml @@ -119,3 +119,62 @@ output: elective_deferral_limit: 32_500 traditional_401k_contributions: 32_500 + +# The expected values below come from the IRS cost-of-living table, 402(g)(1) +# and 414(v)(2)(B)(i), https://www.irs.gov/pub/irs-tege/cola-table.pdf. + +- name: Case 11, the 2004 limit applies. + period: 2004 + input: + age: 40 + traditional_401k_contributions_desired: 20_000 + output: + elective_deferral_limit: 13_000 + traditional_401k_contributions: 13_000 + +- name: Case 12, the 2004 limit adds the 2004 catch-up. + period: 2004 + input: + age: 55 + traditional_401k_contributions_desired: 20_000 + output: + # 13,000 + 3,000 = 16,000. + elective_deferral_limit: 16_000 + traditional_401k_contributions: 16_000 + +- name: Case 13, the 2009 limit applies. + period: 2009 + input: + age: 40 + output: + elective_deferral_limit: 16_500 + +- name: Case 14, the 2014 limit adds the 2014 catch-up. + period: 2014 + input: + age: 55 + output: + # 17,500 + 5,500 = 23,000. + elective_deferral_limit: 23_000 + +- name: Case 15, the 2017 limit applies. + period: 2017 + input: + age: 40 + output: + elective_deferral_limit: 18_000 + +- name: Case 16, the 2017 limit adds the 2017 catch-up. + period: 2017 + input: + age: 55 + output: + # 18,000 + 6,000 = 24,000. + elective_deferral_limit: 24_000 + +- name: Case 17, the limit rises to 18,500 in 2018. + period: 2018 + input: + age: 40 + output: + elective_deferral_limit: 18_500 diff --git a/policyengine_us/tests/policy/baseline/household/marginal_tax_rate_including_health_benefits.yaml b/policyengine_us/tests/policy/baseline/household/marginal_tax_rate_including_health_benefits.yaml index 9525270bad6..71e43a29510 100644 --- a/policyengine_us/tests/policy/baseline/household/marginal_tax_rate_including_health_benefits.yaml +++ b/policyengine_us/tests/policy/baseline/household/marginal_tax_rate_including_health_benefits.yaml @@ -43,8 +43,8 @@ state_fips: 15 # HI employment_income: 0 healthcare_benefit_value: 0 - output: - marginal_tax_rate_including_health_benefits: -0.0306 + output: + marginal_tax_rate_including_health_benefits: -0.0256 - name: Michigan No income and yes healthcare benefits absolute_error_margin: 0.01 diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py index bdf1c1aa4b0..eb9890d41d7 100644 --- a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_qualified.py @@ -8,10 +8,16 @@ class hi_temporary_disability_insurance_qualified(Variable): documentation = ( "HRS 392-43(b)(1) counts wages from a payroll period only if the prior " "52 weeks hold enough wages and enough weeks with enough paid hours. " - "The model holds no prior-year work history, so this annual proxy tests " - "the simulation year's wages, weeks worked and usual weekly hours. Zero " - "weeks or zero hours mean the value went unreported, so that part of " - "the test passes." + "This annual proxy passes a worker in either of two ways. The first " + "tests the simulation year's wages, weeks worked and usual weekly " + "hours, and there zero weeks or zero hours mean the value went " + "unreported, so that part of the test passes. The second tests the " + "previous year's weeks worked and usual weekly hours, and it needs " + "both on file. A single year of inputs leaves the previous year at " + "zero, so a worker with a short year and no history on file does not " + "pass. Usual weekly hours stand in for each week's hours, so a worker " + "whose usual hours fall under the minimum does not pass even with " + "enough qualifying weeks." ) definition_period = YEAR defined_for = StateCode.HI @@ -30,4 +36,15 @@ def formula(person, period, parameters): meets_wages = wages >= p.minimum_wages meets_weeks = (weeks == 0) | (weeks >= p.minimum_weeks) meets_hours = (hours == 0) | (hours >= p.minimum_weekly_hours) - return meets_wages & meets_weeks & meets_hours + passes_in_year = meets_wages & meets_weeks & meets_hours + # The previous year passes only on positive evidence, because zero + # there means no history on file. The minimum weeks and hours make + # 280 paid hours, which reach the minimum wages at about $1.43 an + # hour, so the wages part of the test needs no separate read. + last_year = period.last_year + weeks_last_year = person("weeks_worked", last_year) + hours_last_year = person("weekly_hours_worked_before_lsr", last_year) + passes_last_year = (weeks_last_year >= p.minimum_weeks) & ( + hours_last_year >= p.minimum_weekly_hours + ) + return passes_in_year | passes_last_year diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py index a654e9f9737..db3ee500989 100644 --- a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_taxable_wages.py @@ -11,7 +11,8 @@ class hi_temporary_disability_insurance_taxable_wages(Variable): "cap multiplies the maximum weekly wage base by weeks worked, or by 52 " "when weeks worked went unreported. An even weekly wage reaches the " "largest amount the weekly cap allows, so this amount is an upper limit " - "for a worker with one employer." + "for a worker with one employer who passes the annual qualification " + "test." ) definition_period = YEAR unit = USD diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py index 38ca933b356..32a75624efa 100644 --- a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.py @@ -15,14 +15,18 @@ class hi_temporary_disability_insurance_wages(Variable): "no dependent care payment, so dependent care benefits stay in. The " "federal payroll wage base differs because Congress added rules for " "elective deferrals, cafeteria plans and dependent care that Hawaii did " - "not enact. Before 2015 retirement deferrals stay in, because the " - "model's elective deferral limit starts in 2015." + "not enact. HRS 392-5(6) leaves service for the United States " + "government out of employment, so military basic pay comes out too. " + "The model's convention puts basic pay inside employment income, and " + "a service member's civilian wages stay in. The model identifies no " + "other federal employees, so their pay stays in." ) definition_period = YEAR unit = USD defined_for = StateCode.HI reference = ( "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0003.htm", + "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0005.htm", "https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm", ) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 2b3ad08e551..470c015534f 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -3159,8 +3159,11 @@ candidates: citation: HRS 392-3 (wages), adopting HRS 383-11(1)(A), (1)(C), (4)(A) and (5) url: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm - kind: regulation - citation: HAR 12-11-1, which takes wages from HRS 392-3 and says nothing on salary reductions + citation: HAR 12-11-1, which takes wages from HRS 392-3 url: https://labor.hawaii.gov/dcd/files/2012/11/TDI-Admin-Rules.pdf#page=5 + - kind: regulation + citation: HAR 12-11-47(a), on pay in kind given rather than deducted from money wages + url: https://labor.hawaii.gov/dcd/files/2012/11/TDI-Admin-Rules.pdf#page=17 - kind: guidance citation: Hawaii DLIR Unemployment Insurance Division, Handbook for Employers, on the wages that chapter 383 reaches url: https://labor.hawaii.gov/ui/test-handbook-for-employers/ @@ -3171,8 +3174,8 @@ candidates: stay in wages. other: The federal payroll wage base keeps elective deferrals in and takes cafeteria-plan amounts and dependent care out, through IRC 3306(r)(1)(A), (b)(5)(G) and (b)(13), which Hawaii did not enact. A second alternative treats every - salary reduction as the employee's own remuneration, so all of it stays in wages. The rule and the handbook address - neither alternative. + salary reduction as the employee's own remuneration, so all of it stays in wages. The rules address pay in kind but + name no plan contribution or salary reduction, and the handbook addresses neither alternative. example: In 2026, $60,000 of salary with a $4,000 traditional 401(k) deferral gives a $280 contribution under the statute, versus $300 on the federal base. $60,000 with $5,000 of dependent care benefits gives $300, versus $275 on the federal base. diff --git a/source_conflicts/sources/us-hi/har-12-11-excerpt.txt b/source_conflicts/sources/us-hi/har-12-11-excerpt.txt new file mode 100644 index 00000000000..36d1d6fc1b0 --- /dev/null +++ b/source_conflicts/sources/us-hi/har-12-11-excerpt.txt @@ -0,0 +1,5 @@ +Source: https://labor.hawaii.gov/dcd/files/2012/11/TDI-Admin-Rules.pdf +Short excerpts of HAR 12-11-1 (wages) and HAR 12-11-47(a) (remuneration in kind), copied from the official PDF. + +"Wages" shall be as defined in section 392-3, HRS. +in addition to or in lieu of (rather than as a deduction from) money wages diff --git a/source_conflicts/sources/us-hi/hrs-383-11-excerpt.txt b/source_conflicts/sources/us-hi/hrs-383-11-excerpt.txt index 360e1fc0bfa..6413e8a9dbc 100644 --- a/source_conflicts/sources/us-hi/hrs-383-11-excerpt.txt +++ b/source_conflicts/sources/us-hi/hrs-383-11-excerpt.txt @@ -1,6 +1,8 @@ Source: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0383/HRS_0383-0011.htm -Short excerpts of HRS 383-11(4), (4)(A) and (5), copied from the official HTML page. +Short excerpts of HRS 383-11(1)(A), (1)(C), (4), (4)(A) and (5), copied from the official HTML page. -any payment by an employing unit to, or on behalf of, an individual -to a trust described in section 401(a) -without deduction from the remuneration +Retirement +Medical or hospitalization expenses +by an employing unit to, or on behalf of, an individual +trust described in section 401(a) +without deduction from From deca0e3638de3967bebb2ee5ece8575edf2136c8 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 9 Nov 2026 12:27:56 -0500 Subject: [PATCH 4/5] Scale Hawaii's TDI contribution by the employer's deduction share HRS 392-43(a) permits the employer to withhold the contribution without requiring it, like New York's PFL and DBL. Following main's #10285, the employee amount is the 0.5% limit times state_payroll_premium_deduction_share, which defaults to 1. Hawaii joins the programs whose employer cost the model doesn't hold, in the documentation of employee_state_payroll_tax, employer_additional_state_payroll_tax and the share input, and in the share invariants test. Three YAML cases cover a share of 0.5, 0 and 1.5. Co-Authored-By: Claude Opus 5.5 --- policyengine_us/programs.yaml | 2 +- ...roll_premium_deduction_share_invariants.py | 21 +++++----- ...ary_disability_insurance_contribution.yaml | 38 +++++++++++++++++++ ...orary_disability_insurance_contribution.py | 17 +++++---- .../employer_additional_state_payroll_tax.py | 5 ++- .../variables/input/employer_payroll.py | 16 ++++---- 6 files changed, 71 insertions(+), 28 deletions(-) diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 77530634aba..d13eca8e4b3 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -2199,7 +2199,7 @@ programs: variable: hi_employee_temporary_disability_insurance_contribution parameter_prefix: gov.states.hi.tax.payroll.temporary_disability_insurance verified_start_year: 2004 - notes: Models the employee contribution at the HRS 392-43(a) limit; benefits and employer costs are out of scope. + notes: Models the employee contribution as the HRS 392-43(a) limit times the employer's deduction share, which defaults to 1; benefits and employer costs are out of scope. - id: il_fpp name: Illinois Family Planning Program diff --git a/policyengine_us/tests/core/test_state_payroll_premium_deduction_share_invariants.py b/policyengine_us/tests/core/test_state_payroll_premium_deduction_share_invariants.py index fa28532f644..63aaaa49f1d 100644 --- a/policyengine_us/tests/core/test_state_payroll_premium_deduction_share_invariants.py +++ b/policyengine_us/tests/core/test_state_payroll_premium_deduction_share_invariants.py @@ -3,10 +3,10 @@ In some state programs the law caps what the employer may deduct from wages and leaves it to decide how much of that to deduct: Colorado FAMLI, Delaware Paid Leave, Maine and Massachusetts PFML, Minnesota Paid Leave and the Vermont -Child Care Contribution, whose premium the statute puts on the employer; New -York PFL and DBL, which the employer is authorized but not required to -collect; and Washington PFML, whose employee share the employer may deduct up -to and may pay in any part. +Child Care Contribution, whose premium the statute puts on the employer; +Hawaii TDI and New York PFL and DBL, which the employer is authorized but not +required to collect; and Washington PFML, whose employee share the employer +may deduct up to and may pay in any part. `employer_state_payroll_premium_deduction_share` says how much of the permitted employee share the employer deducts (default 1). Hypothesis draws workers in those states, in states whose contributions are mandatory @@ -22,8 +22,8 @@ the share. 3. Where the employer side is modeled (CO, DE, MA, ME, VT, WA), employee plus employer premium does not depend on the share: the employer pays exactly - what it does not deduct. Minnesota and New York employer costs are not - modeled, so their employer amount is zero at any share. + what it does not deduct. Hawaii, Minnesota and New York employer costs are + not modeled, so their employer amount is zero at any share. 4. A larger share never lowers the employee amount or raises the employer amount. 5. With employer-level wage totals equal to the worker's own wages, capped at @@ -53,12 +53,13 @@ from policyengine_us.system import system YEARS = (2026, 2027) -OPTIONAL_STATES = ("CO", "DE", "MA", "ME", "MN", "NY", "VT", "WA") +OPTIONAL_STATES = ("CO", "DE", "HI", "MA", "ME", "MN", "NY", "VT", "WA") MANDATORY_STATES = ("CA", "CT", "NJ", "OR", "PA", "RI") EMPLOYER_MODELED_STATES = ("CO", "DE", "MA", "ME", "VT", "WA") OPTIONAL_EMPLOYEE_VARIABLES = ( "co_employee_famli_contribution", "de_employee_paid_leave_contribution", + "hi_employee_temporary_disability_insurance_contribution", "ma_employee_paid_leave_contribution", "me_employee_paid_leave_contribution", "mn_employee_paid_leave_contribution", @@ -67,8 +68,8 @@ "vt_employee_child_care_contribution", "wa_employee_paid_leave_contribution", ) -# Below the 2026 Social Security wage base, so every program's wage base is -# the worker's wages in both years. +# Below the 2026 Social Security wage base, so Massachusetts' wage base is the +# worker's wages in both years (property 6). UNCAPPED_WAGES = 184_500 SOCIAL_SECURITY_CAP = { year: system.parameters(f"{year}-01-01").gov.irs.payroll.social_security.cap @@ -174,7 +175,7 @@ def test_state_payroll_premium_deduction_share_invariants(rows): wages = np.array([row[1] for row in rows]) shares = np.clip(np.array([[row[3], row[4], 1.0] for row in rows]), 0, 1) modeled = np.isin(states, EMPLOYER_MODELED_STATES) - unmodeled = np.isin(states, ("MN", "NY")) + unmodeled = np.isin(states, ("HI", "MN", "NY")) uncapped = wages <= UNCAPPED_WAGES optional_by_year = {} employer_by_year = {} diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml index c3b183457b5..9ab108bc940 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml @@ -558,3 +558,41 @@ hi_temporary_disability_insurance_qualified: true # 0.5% * 20,000 = 100. hi_employee_temporary_disability_insurance_contribution: 100 + +- name: Hawaii scales the contribution by the employer's deduction share. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 60_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: HI + output: + # HRS 392-43(a) lets the employer withhold up to 0.5% * 60,000 = 300 and + # leaves the amount to it. Withholding half gives 0.5 * 300 = 150. + hi_employee_temporary_disability_insurance_contribution: 150 + hi_employee_state_payroll_tax: 150 + employee_state_payroll_tax: 150 + +- name: Hawaii charges nothing when the employer withholds nothing. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0 + state_code: HI + output: + # 52 * 1,500.21 = 78,010.92. + hi_temporary_disability_insurance_taxable_wages: 78_010.92 + hi_employee_temporary_disability_insurance_contribution: 0 + employee_state_payroll_tax: 0 + +- name: Hawaii holds a deduction share above 1 at the 0.5% limit. + period: 2026 + absolute_error_margin: 0.01 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 1.5 + state_code: HI + output: + # The employer may withhold at most 0.5% * 78,010.92 = 390.05. + hi_employee_temporary_disability_insurance_contribution: 390.05 diff --git a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.py b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.py index 2ef4f8075a0..4d5aaeaa358 100644 --- a/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.py +++ b/policyengine_us/variables/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.py @@ -6,12 +6,14 @@ class hi_employee_temporary_disability_insurance_contribution(Variable): entity = Person label = "Hawaii employee temporary disability insurance contribution" documentation = ( - "Employee-side Hawaii temporary disability insurance contribution at " - "the statutory limit. HRS 392-43(a) lets an employer withhold half the " - "cost of coverage, up to the employee rate times weekly wages, and " - "makes the employer pay the balance. Coverage cost varies by employer " - "and the model holds no premium data, so this assumes the employer " - "withholds the full rate limit." + "Employee-side Hawaii temporary disability insurance contribution. " + "HRS 392-43(a) authorizes the employer, without requiring it, to " + "withhold half the cost of coverage, up to the employee rate times " + "weekly wages, and makes the employer pay the balance. Coverage cost " + "varies by employer and the model holds no premium data, so it takes " + "the rate limit as the permitted amount; this is that amount times " + "state_payroll_premium_deduction_share. The employer's cost of " + "coverage is not modeled." ) definition_period = YEAR unit = USD @@ -25,4 +27,5 @@ def formula(person, period, parameters): taxable_wages = person( "hi_temporary_disability_insurance_taxable_wages", period ) - return p.employee_rate * taxable_wages + permitted = p.employee_rate * taxable_wages + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/tax/payroll/employer_additional_state_payroll_tax.py b/policyengine_us/variables/gov/states/tax/payroll/employer_additional_state_payroll_tax.py index 0bbb5e52be0..6ccdbd3444a 100644 --- a/policyengine_us/variables/gov/states/tax/payroll/employer_additional_state_payroll_tax.py +++ b/policyengine_us/variables/gov/states/tax/payroll/employer_additional_state_payroll_tax.py @@ -22,8 +22,9 @@ class employer_additional_state_payroll_tax(Variable): "Employer-side state payroll taxes and payroll-funded contributions " "other than state unemployment insurance, including any part of a " "permitted employee premium the employer does not deduct " - "(employer_state_payroll_premium_deduction_share). Minnesota Paid " - "Leave and the New York PFL and DBL employer costs are not modeled." + "(employer_state_payroll_premium_deduction_share). Hawaii TDI, " + "Minnesota Paid Leave and the New York PFL and DBL employer costs are " + "not modeled." ) definition_period = YEAR unit = USD diff --git a/policyengine_us/variables/input/employer_payroll.py b/policyengine_us/variables/input/employer_payroll.py index 48b93d8f61e..c996f59e1c1 100644 --- a/policyengine_us/variables/input/employer_payroll.py +++ b/policyengine_us/variables/input/employer_payroll.py @@ -35,14 +35,14 @@ class employer_state_payroll_premium_deduction_share(Variable): "Share of the largest employee premium the law lets the employer " "deduct from wages that the employer actually deducts, for state " "programs where the law caps the deduction and leaves the amount to " - "the employer: Colorado FAMLI, Delaware Paid Leave, Maine and " - "Massachusetts Paid Family and Medical Leave, Minnesota Paid Leave, " - "New York Paid Family Leave and Disability Benefits, the Vermont " - "Child Care Contribution and Washington Paid Family and Medical " - "Leave. 1, the default, deducts the full permitted share; 0 deducts " - "nothing. Outside Minnesota and New York, whose employer cost is not " - "modeled, the employer-side variables carry any part the employer " - "does not deduct. For the state paid family and medical leave funds, " + "the employer: Colorado FAMLI, Delaware Paid Leave, Hawaii TDI, Maine " + "and Massachusetts Paid Family and Medical Leave, Minnesota Paid " + "Leave, New York Paid Family Leave and Disability Benefits, the " + "Vermont Child Care Contribution and Washington Paid Family and " + "Medical Leave. 1, the default, deducts the full permitted share; 0 " + "deducts nothing. Outside Hawaii, Minnesota and New York, whose " + "employer cost is not modeled, the employer-side variables carry any " + "part the employer does not deduct. For the state paid family and medical leave funds, " "the federal treatment of an employer's payment of the employee " "share as the employee's wages (Rev. Rul. 2025-4; Notice 2026-6) is " "not modeled. Values outside 0 to 1 are treated as the nearer bound." From 92b57da31a1a7828594df296854a5ebbe9a76d2c Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 9 Nov 2026 14:08:09 -0500 Subject: [PATCH 5/5] Add Hawaii's 2003 TDI maximum weekly wage base DLIR's Disability Compensation Division published a $702.38 maximum weekly wage base for 2003 (notice dated December 15, 2002): the State average annual wage of $30,184.73 / 52 * 1.21 under HRS 392-43(b)(2), with a $3.51 maximum weekly deduction. - Add 702.38 for 2003 to the wage base and start the 0.5% rate and the deferral exclusions in 2003. - Extend the federal 401(k) elective deferral limit ($12,000), catch-up ($2,000) and catch-up age (50) back to 2003 from the IRS cost-of-living table, and cite 26 USC 414(v)(5)(A) for the age test. - Add 2003 to the stored notice table, add 2003 YAML cases, move the zero-boundary cases to 2002, and move hi_tdi's verified_start_year to 2003. Co-Authored-By: Claude Opus 5.5 --- changelog.d/hi-tdi-2003-wage-base.added.md | 1 + .../catch_up/age_threshold.yaml | 5 ++- .../catch_up/limit/k401.yaml | 13 ++++--- .../retirement_contributions/limit/401k.yaml | 1 + .../employee_rate.yaml | 8 ++--- .../excluded_payments.yaml | 4 +-- .../maximum_weekly_wage_base.yaml | 5 ++- policyengine_us/programs.yaml | 2 +- .../test_hi_temporary_disability_insurance.py | 2 ++ .../retirement/k401_catch_up_limit.yaml | 28 +++++++++++++++ ...ary_disability_insurance_contribution.yaml | 17 ++++++++-- ..._temporary_disability_insurance_wages.yaml | 34 ++++++++++++++++--- .../retirement/elective_deferral_limit.yaml | 19 +++++++++++ 13 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 changelog.d/hi-tdi-2003-wage-base.added.md diff --git a/changelog.d/hi-tdi-2003-wage-base.added.md b/changelog.d/hi-tdi-2003-wage-base.added.md new file mode 100644 index 00000000000..3f1a519afb3 --- /dev/null +++ b/changelog.d/hi-tdi-2003-wage-base.added.md @@ -0,0 +1 @@ +Add Hawaii's 2003 maximum weekly wage base for the employee temporary disability insurance contribution, and extend the federal 401(k) elective deferral and catch-up limits back to 2003 from the IRS cost-of-living table. diff --git a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/age_threshold.yaml b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/age_threshold.yaml index ed255c327a3..44192da600e 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/age_threshold.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/age_threshold.yaml @@ -1,6 +1,6 @@ description: The US limits catch-up pension contributions to individuals this age or older. values: - 2004-01-01: 50 + 2003-01-01: 50 metadata: unit: year period: year @@ -8,3 +8,6 @@ metadata: reference: - title: 26 CFR § 1.414(v)-1 - Catch-up contributions. (g)(3)(ii) href: https://www.law.cornell.edu/cfr/text/26/1.414(v)-1#g_3_ii + # The regulation applies from 2004; the statute sets the age test from 2002. + - title: 26 USC 414(v)(5)(A) + href: https://www.law.cornell.edu/uscode/text/26/414#v_5_A diff --git a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/limit/k401.yaml b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/limit/k401.yaml index cd2977c7be7..e08e4045f11 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/limit/k401.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/catch_up/limit/k401.yaml @@ -3,15 +3,16 @@ description: The IRS limits 401(k) catch-up contributions to this amount based o brackets: - threshold: values: - 2004-01-01: 0 + 2003-01-01: 0 amount: values: - 2004-01-01: 0 + 2003-01-01: 0 - threshold: values: - 2004-01-01: 50 + 2003-01-01: 50 amount: values: + 2003-01-01: 2_000 2004-01-01: 3_000 2005-01-01: 4_000 2006-01-01: 5_000 @@ -30,9 +31,10 @@ brackets: interval: 500 - threshold: values: - 2004-01-01: 60 + 2003-01-01: 60 amount: values: + 2003-01-01: 2_000 2004-01-01: 3_000 2005-01-01: 4_000 2006-01-01: 5_000 @@ -53,9 +55,10 @@ brackets: interval: 500 - threshold: values: - 2004-01-01: 64 + 2003-01-01: 64 amount: values: + 2003-01-01: 2_000 2004-01-01: 3_000 2005-01-01: 4_000 2006-01-01: 5_000 diff --git a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/limit/401k.yaml b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/limit/401k.yaml index 925f7b6f8ca..f79a023ef3e 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/limit/401k.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/retirement_contributions/limit/401k.yaml @@ -1,5 +1,6 @@ description: The US limits annual 401(k) contributions to this amount. values: + 2003-01-01: 12_000 2004-01-01: 13_000 2005-01-01: 14_000 2006-01-01: 15_000 diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/employee_rate.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/employee_rate.yaml index ed337771574..cb7764daa4b 100644 --- a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/employee_rate.yaml +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/employee_rate.yaml @@ -1,9 +1,9 @@ description: Hawaii limits the employee temporary disability insurance contribution to this share of weekly wages. values: - # Zero marks years before the first notice read (2004), not a law without a + # Zero marks years before the first notice read (2003), not a law without a # contribution. See maximum_weekly_wage_base.yaml. 0000-01-01: 0 - 2004-01-01: 0.005 + 2003-01-01: 0.005 metadata: period: year @@ -12,8 +12,8 @@ metadata: reference: - title: Hawaii Revised Statutes Section 392-43(a) href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm - - title: Hawaii DLIR, 2004 maximum weekly wage base notice - href: https://web.archive.org/web/20050226051453/http://hawaii.gov:80/labor/dcd/pdf/TDI/2004%20TDI%20Wage%20Base.pdf#page=1 + - title: Hawaii DLIR, 2003 maximum weekly wage base notice + href: https://web.archive.org/web/20030315040801/http://dlir.state.hi.us:80/dcd/WC%20weekly%20wage%20base.pdf#page=1 - title: Hawaii DLIR, 2026 maximum weekly wage base notice href: https://labor.hawaii.gov/dcd/files/2025/12/2026-Maximum-Weekly-Wage-Base.pdf#page=1 - title: Hawaii DLIR, Form TDI-15 (rev. June 2026) diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml index 57d792c0c21..706163c785a 100644 --- a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/excluded_payments.yaml @@ -8,9 +8,9 @@ values: - pre_tax_health_insurance_premiums - health_savings_account_payroll_contributions - military_basic_pay - # The law did not change in 2004. The federal elective deferral limit that the + # The law did not change in 2003. The federal elective deferral limit that the # contribution variables below read starts then, as does the contribution rate. - 2004-01-01: + 2003-01-01: - pre_tax_health_insurance_premiums - health_savings_account_payroll_contributions - military_basic_pay diff --git a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/maximum_weekly_wage_base.yaml b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/maximum_weekly_wage_base.yaml index 6eb9ecb9f9e..776dc58bc8b 100644 --- a/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/maximum_weekly_wage_base.yaml +++ b/policyengine_us/parameters/gov/states/hi/tax/payroll/temporary_disability_insurance/maximum_weekly_wage_base.yaml @@ -1,9 +1,10 @@ description: Hawaii counts weekly wages up to this amount toward the employee temporary disability insurance contribution. values: - # Zero marks years before the first notice read (2004), not a law without a + # Zero marks years before the first notice read (2003), not a law without a # wage base. The Director publishes one amount a year under HRS 392-43(b)(2): # the State's average annual wage / 52 * 1.21. 0000-01-01: 0 + 2003-01-01: 702.38 2004-01-01: 720.70 2005-01-01: 752.44 2006-01-01: 791.70 @@ -35,6 +36,8 @@ metadata: reference: - title: Hawaii Revised Statutes Section 392-43(b)(2) href: https://data.capitol.hawaii.gov/hrscurrent/Vol07_Ch0346-0398/HRS0392/HRS_0392-0043.htm + - title: Hawaii DLIR, 2003 maximum weekly wage base notice + href: https://web.archive.org/web/20030315040801/http://dlir.state.hi.us:80/dcd/WC%20weekly%20wage%20base.pdf#page=1 - title: Hawaii DLIR, 2004 maximum weekly wage base notice href: https://web.archive.org/web/20050226051453/http://hawaii.gov:80/labor/dcd/pdf/TDI/2004%20TDI%20Wage%20Base.pdf#page=1 - title: Hawaii DLIR, 2005 maximum weekly wage base notice diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index d13eca8e4b3..a181c5d7713 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -2198,7 +2198,7 @@ programs: coverage: HI variable: hi_employee_temporary_disability_insurance_contribution parameter_prefix: gov.states.hi.tax.payroll.temporary_disability_insurance - verified_start_year: 2004 + verified_start_year: 2003 notes: Models the employee contribution as the HRS 392-43(a) limit times the employer's deduction share, which defaults to 1; benefits and employer costs are out of scope. - id: il_fpp diff --git a/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py b/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py index 072a4677fa1..343878867fe 100644 --- a/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py +++ b/policyengine_us/tests/core/test_hi_temporary_disability_insurance.py @@ -46,7 +46,9 @@ # Transcribed from each year's DLIR notice, independent of the parameter file: # state average annual wage, maximum weekly wage base, maximum weekly deduction. +# The 2003 notice survives only as a scan, so its figures come from the image. NOTICES = { + 2003: ("30184.73", "702.38", "3.51"), 2004: ("30972.13", "720.70", "3.60"), 2005: ("32336.24", "752.44", "3.76"), 2006: ("34023.65", "791.70", "3.96"), diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/retirement/k401_catch_up_limit.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/retirement/k401_catch_up_limit.yaml index 0b75d6afefd..f7c7e12f47f 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/retirement/k401_catch_up_limit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/retirement/k401_catch_up_limit.yaml @@ -170,3 +170,31 @@ age: 50 output: k401_catch_up_limit: 6_000 + +- name: Case 24, age 49 in 2003 receives no catch-up. + period: 2003 + input: + age: 49 + output: + k401_catch_up_limit: 0 + +- name: Case 25, age 50 in 2003 receives 2003 standard limit. + period: 2003 + input: + age: 50 + output: + k401_catch_up_limit: 2_000 + +- name: Case 26, age 62 in 2003 receives 2003 standard limit. + period: 2003 + input: + age: 62 + output: + k401_catch_up_limit: 2_000 + +- name: Case 27, age 70 in 2003 receives 2003 standard limit. + period: 2003 + input: + age: 70 + output: + k401_catch_up_limit: 2_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml index 9ab108bc940..8f46f56fa90 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_employee_temporary_disability_insurance_contribution.yaml @@ -58,7 +58,20 @@ employee_payroll_tax: 8_040.05 spm_unit_payroll_tax: 8_040.05 -- name: Hawaii 2004, the first published year, uses the 720.70 weekly wage base. +- name: Hawaii 2003, the first published year, uses the 702.38 weekly wage base. + period: 2003 + absolute_error_margin: 0.01 + input: + employment_income: 50_000 + state_code: HI + output: + # 52 * 702.38 = 36,523.76. + hi_temporary_disability_insurance_taxable_wages: 36_523.76 + # 0.5% * 36,523.76 = 182.62. + hi_employee_temporary_disability_insurance_contribution: 182.62 + employee_state_payroll_tax: 182.62 + +- name: Hawaii 2004 uses the 720.70 weekly wage base. period: 2004 absolute_error_margin: 0.01 input: @@ -85,7 +98,7 @@ employee_state_payroll_tax: 200.00 - name: Hawaii models no contribution before the first published year. - period: 2003 + period: 2002 absolute_error_margin: 0.01 input: employment_income: 50_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml index cd0ca7d9c86..6549c857408 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/payroll/temporary_disability_insurance/hi_temporary_disability_insurance_wages.yaml @@ -74,8 +74,8 @@ traditional_401k_contributions: 24_500 hi_temporary_disability_insurance_wages: 75_500 -- name: Hawaii wages leave out deferrals in 2004, the first year the model holds a limit. - period: 2004 +- name: Hawaii wages leave out deferrals in 2003, the first year the model holds a limit. + period: 2003 absolute_error_margin: 0.01 input: age: 55 @@ -86,6 +86,32 @@ # 60,000 - 4,000 = 56,000. hi_temporary_disability_insurance_wages: 56_000 +- name: Hawaii wages leave out only the deferral the 2003 limit allows. + period: 2003 + absolute_error_margin: 0.01 + input: + age: 40 + employment_income: 100_000 + traditional_401k_contributions_desired: 30_000 + state_code: HI + output: + # The 2003 limit under age 50 is 12,000: 100,000 - 12,000 = 88,000. + traditional_401k_contributions: 12_000 + hi_temporary_disability_insurance_wages: 88_000 + +- name: Hawaii wages leave out the 2003 catch-up from age 50. + period: 2003 + absolute_error_margin: 0.01 + input: + age: 50 + employment_income: 100_000 + traditional_401k_contributions_desired: 30_000 + state_code: HI + output: + # 12,000 plus the 2,000 catch-up is 14,000: 100,000 - 14,000 = 86,000. + traditional_401k_contributions: 14_000 + hi_temporary_disability_insurance_wages: 86_000 + - name: Hawaii wages leave out only the deferral the 2004 limit allows. period: 2004 absolute_error_margin: 0.01 @@ -110,8 +136,8 @@ # 60,000 - 4,000 = 56,000. hi_temporary_disability_insurance_wages: 56_000 -- name: Hawaii wages keep deferrals in 2003, before the model holds a limit. - period: 2003 +- name: Hawaii wages keep deferrals in 2002, before the model holds a limit. + period: 2002 absolute_error_margin: 0.01 input: employment_income: 60_000 diff --git a/policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_limit.yaml b/policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_limit.yaml index 2f23757cd22..05af27f935d 100644 --- a/policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_limit.yaml +++ b/policyengine_us/tests/policy/baseline/household/expense/retirement/elective_deferral_limit.yaml @@ -178,3 +178,22 @@ age: 40 output: elective_deferral_limit: 18_500 + +- name: Case 18, the 2003 limit applies. + period: 2003 + input: + age: 40 + traditional_401k_contributions_desired: 20_000 + output: + elective_deferral_limit: 12_000 + traditional_401k_contributions: 12_000 + +- name: Case 19, the 2003 limit adds the 2003 catch-up. + period: 2003 + input: + age: 55 + traditional_401k_contributions_desired: 20_000 + output: + # 12,000 + 2,000 = 14,000. + elective_deferral_limit: 14_000 + traditional_401k_contributions: 14_000