Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog_entry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- bump: minor
changes:
added:
- Add Utah HB 210 (2026) structural reform implementing the taxpayer credit add-on for married filers ($543 MFS, $1,086 joint/surviving spouse) with phaseout.
1 change: 0 additions & 1 deletion policyengine_us/entities.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from policyengine_core.entities import build_entity


Household = build_entity(
key="household",
plural="households",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
description: Utah HB 210 (2026) is in effect, modifying tax credits including a taxpayer credit add-on for married filers.

values:
0000-01-01: false

metadata:
unit: bool
period: year
label: Utah HB 210 in effect
reference:
- title: Utah HB 210 (2026)
href: https://le.utah.gov/~2026/bills/static/HB0210.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
description: Utah provides this additional taxpayer credit amount for married filers under HB 210 (2026).
SINGLE:
2026-01-01: 0
JOINT:
2026-01-01: 1_086
HEAD_OF_HOUSEHOLD:
2026-01-01: 0
SEPARATE:
2026-01-01: 543
SURVIVING_SPOUSE:
2026-01-01: 0

metadata:
unit: currency-USD
period: year
label: Utah HB 210 taxpayer credit add-on amount
reference:
- title: Utah HB 210 (2026), Section 2, amending 59-10-1018(3)
href: https://le.utah.gov/~2026/bills/static/HB0210.html
4 changes: 4 additions & 0 deletions policyengine_us/reforms/reforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
)
from .states.ut import (
create_ut_refundable_eitc_reform,
create_ut_hb210_reform,
)
from .additional_tax_bracket import (
create_additional_tax_bracket_reform,
Expand Down Expand Up @@ -272,6 +273,8 @@ def create_structural_reforms_from_parameters(parameters, period):

ut_refundable_eitc = create_ut_refundable_eitc_reform(parameters, period)

ut_hb210 = create_ut_hb210_reform(parameters, period)

american_worker_rebate_act = create_american_worker_rebate_act_reform(
parameters, period
)
Expand Down Expand Up @@ -352,6 +355,7 @@ def create_structural_reforms_from_parameters(parameters, period):
mi_surtax,
nyc_mamdani_income_tax,
ut_refundable_eitc,
ut_hb210,
additional_tax_bracket,
american_worker_rebate_act,
ctc_per_child_phase_out,
Expand Down
3 changes: 3 additions & 0 deletions policyengine_us/reforms/states/ut/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from .ut_refundable_eitc import (
create_ut_refundable_eitc_reform,
)
from .ut_hb210 import (
create_ut_hb210_reform,
)
76 changes: 76 additions & 0 deletions policyengine_us/reforms/states/ut/ut_hb210.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from policyengine_us.model_api import *
from policyengine_core.periods import period as period_


def create_ut_hb210() -> Reform:
"""
Utah HB 210 (2026) - Tax penalty removal bill that:
1. Adds a taxpayer credit add-on for married filers ($543 MFS, $1,086 joint)
2. Removes marriage penalties from phaseout thresholds (parameter changes)
3. Repeals the Utah EITC (parameter change - set rate to 0)

This reform implements provision #1 (the structural change).
Provisions #2 and #3 can be modeled via parameter changes.
"""

class ut_taxpayer_credit(Variable):
value_type = float
entity = TaxUnit
label = "Utah taxpayer credit"
unit = USD
documentation = "Form TC-40, line 20"
definition_period = YEAR
defined_for = StateCode.UT
reference = (
"https://le.utah.gov/xcode/Title59/Chapter10/59-10-S1018.html",
"https://le.utah.gov/~2026/bills/static/HB0210.html",
)

def formula(tax_unit, period, parameters):
# Base maximum credit (6% of deductions + exemption)
base_max = tax_unit("ut_taxpayer_credit_max", period)

# Add the married filer add-on per HB 210 Section 59-10-1018(3)
# The add-on is added before phaseout is applied
filing_status = tax_unit("filing_status", period)
p = parameters(
period
).gov.contrib.states.ut.hb210.taxpayer_credit_add_on
add_on = p.amount[filing_status]

# Total maximum credit including add-on
total_max = base_max + add_on

# Apply phaseout reduction to total credit (including add-on)
reduction = tax_unit("ut_taxpayer_credit_reduction", period)
return max_(total_max - reduction, 0)

class reform(Reform):
def apply(self):
self.update_variable(ut_taxpayer_credit)

return reform


def create_ut_hb210_reform(parameters, period, bypass: bool = False):
if bypass:
return create_ut_hb210()

p = parameters.gov.contrib.states.ut.hb210

reform_active = False
current_period = period_(period)

for i in range(5):
if p(current_period).in_effect:
reform_active = True
break
current_period = current_period.offset(1, "year")

if reform_active:
return create_ut_hb210()
else:
return None


ut_hb210 = create_ut_hb210_reform(None, None, bypass=True)
1 change: 0 additions & 1 deletion policyengine_us/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@

from typing import Annotated


COUNTRY_DIR = Path(__file__).parent

CURRENT_YEAR = 2024
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
# Utah HB 210 (2026) - Taxpayer credit add-on for married filers
# Per Section 59-10-1018(3):
# - $543 for married filing separately
# - $1,086 for joint filing status (including surviving spouse)
# - $0 for single, head of household

- name: HB 210 - Joint filers receive base credit plus $1,086 add-on
absolute_error_margin: 1
period: 2026
reforms: policyengine_us.reforms.states.ut.ut_hb210.ut_hb210
input:
gov.contrib.states.ut.hb210.in_effect: true
people:
person1:
age: 40
employment_income: 20_000
person2:
age: 38
employment_income: 10_000
tax_units:
tax_unit:
members: [person1, person2]
filing_status: JOINT
households:
household:
members: [person1, person2]
state_code: UT
output:
# Base credit ~1932 (6% of standard deduction ~32,200)
# Plus $1,086 add-on for joint filers
# Total ~3,018
ut_taxpayer_credit: 3_018

- name: HB 210 - Married filing separately receives base credit plus $543 add-on
absolute_error_margin: 1
period: 2026
reforms: policyengine_us.reforms.states.ut.ut_hb210.ut_hb210
input:
gov.contrib.states.ut.hb210.in_effect: true
people:
person1:
age: 40
employment_income: 30_000
tax_units:
tax_unit:
members: [person1]
filing_status: SEPARATE
households:
household:
members: [person1]
state_code: UT
output:
# Base credit ~818 (partial after phaseout)
# Plus $543 add-on for married filing separately
# Total ~1,361
ut_taxpayer_credit: 1_361

- name: HB 210 - Single filers receive base credit with no add-on
absolute_error_margin: 1
period: 2026
reforms: policyengine_us.reforms.states.ut.ut_hb210.ut_hb210
input:
gov.contrib.states.ut.hb210.in_effect: true
people:
person1:
age: 30
employment_income: 30_000
tax_units:
tax_unit:
members: [person1]
filing_status: SINGLE
households:
household:
members: [person1]
state_code: UT
output:
# Base credit ~818 (partial after phaseout)
# Single filers get no add-on ($0)
# Total ~818
ut_taxpayer_credit: 818

- name: HB 210 - Head of household receives base credit with no add-on
absolute_error_margin: 1
period: 2026
reforms: policyengine_us.reforms.states.ut.ut_hb210.ut_hb210
input:
gov.contrib.states.ut.hb210.in_effect: true
people:
person1:
age: 35
employment_income: 40_000
person2:
age: 10
is_tax_unit_dependent: true
tax_units:
tax_unit:
members: [person1, person2]
filing_status: HEAD_OF_HOUSEHOLD
households:
household:
members: [person1, person2]
state_code: UT
output:
# Base credit ~1,422 (partial after phaseout + dependent exemption)
# Head of household filers get no add-on ($0)
# Total ~1,422
ut_taxpayer_credit: 1_422

- name: HB 210 - Surviving spouse receives no add-on (not a married claimant)
absolute_error_margin: 1
period: 2026
reforms: policyengine_us.reforms.states.ut.ut_hb210.ut_hb210
input:
gov.contrib.states.ut.hb210.in_effect: true
people:
person1:
age: 50
employment_income: 50_000
person2:
age: 10
is_tax_unit_dependent: true
tax_units:
tax_unit:
members: [person1, person2]
filing_status: SURVIVING_SPOUSE
households:
household:
members: [person1, person2]
state_code: UT
output:
# Base credit ~1,896 (partial after phaseout + dependent exemption)
# Surviving spouse is NOT a married claimant per bill intent
# No add-on ($0)
# Total ~1,896
ut_taxpayer_credit: 1_896

- name: HB 210 - Joint vs Single comparison shows add-on benefit
absolute_error_margin: 1
period: 2026
reforms: policyengine_us.reforms.states.ut.ut_hb210.ut_hb210
input:
gov.contrib.states.ut.hb210.in_effect: true
people:
person1:
age: 30
employment_income: 10_000
person2:
age: 28
employment_income: 5_000
tax_units:
tax_unit:
members: [person1, person2]
filing_status: JOINT
households:
household:
members: [person1, person2]
state_code: UT
output:
# Base credit = 6% * standard deduction (~32,200) = ~1,932
# Income $15,000 is below $36,426 threshold, so no phaseout
# Plus $1,086 add-on for joint filers
# Total ~3,018
ut_taxpayer_credit: 3_018

- name: HB 210 - Phaseout reduces add-on at high income (joint)
absolute_error_margin: 1
period: 2026
reforms: policyengine_us.reforms.states.ut.ut_hb210.ut_hb210
input:
gov.contrib.states.ut.hb210.in_effect: true
people:
person1:
age: 40
employment_income: 150_000
person2:
age: 38
employment_income: 100_000
tax_units:
tax_unit:
members: [person1, person2]
filing_status: JOINT
households:
household:
members: [person1, person2]
state_code: UT
output:
# High income ($250k) is well above $36,426 threshold
# Income excess = $250,000 - $36,426 = $213,574
# Phaseout = $213,574 * 0.013 = $2,776.46
# Base max = ~$1,932 + add-on $1,086 = ~$3,018
# Final = max($3,018 - $2,776, 0) = ~$242
# Both base and add-on are reduced by phaseout
ut_taxpayer_credit: 252

- name: HB 210 - Phaseout fully eliminates credit at very high income
absolute_error_margin: 1
period: 2026
reforms: policyengine_us.reforms.states.ut.ut_hb210.ut_hb210
input:
gov.contrib.states.ut.hb210.in_effect: true
people:
person1:
age: 45
employment_income: 300_000
person2:
age: 43
employment_income: 200_000
tax_units:
tax_unit:
members: [person1, person2]
filing_status: JOINT
households:
household:
members: [person1, person2]
state_code: UT
output:
# Very high income ($500k) fully phases out credit
# Income excess = $500,000 - $36,426 = $463,574
# Phaseout = $463,574 * 0.013 = $6,026
# Total max = ~$3,018
# Final = max($3,018 - $6,026, 0) = $0
ut_taxpayer_credit: 0
6 changes: 2 additions & 4 deletions policyengine_us/tools/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ def add_n(word):

def print_variable_summary(variable_name: str):
variable = variables.get(variable_name)
return Markdown(
f"""
return Markdown(f"""
## {variable.name}
This variable models a{add_n(variable.entity.label)}**{variable.entity.label}**'s **{variable.label}**.
"""
)
""")
Loading