Skip to content
Open
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
1 change: 1 addition & 0 deletions changelog.d/fix-watca-alternative-max-tax.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix WATCA alternative maximum tax implementation to match bill text: use 25.5% tax cap on MAGI above exemption instead of deduction, implement binary eligibility at 175% threshold, switch cost-of-living exemption to CPI-U indexing, and add proper MAGI definitions for both the alternative tax and surtax.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description: The Working Americans' Tax Cut Act alternative maximum tax rate applied to MAGI above the cost of living exemption.
metadata:
label: WATCA alternative maximum tax rate
period: year
unit: /1
reference:
- title: Working Americans' Tax Cut Act Section 1A(a)
href: https://www.vanhollen.senate.gov/imo/media/doc/working_americans_tax_cut_act_bill_text.pdf#page=2

values:
2026-01-01: 0.255
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
description: The Working Americans' Tax Cut Act provides a cost of living exemption amount by filing status, indexed for inflation using the chained CPI.
description: The Working Americans' Tax Cut Act provides a cost of living exemption amount by filing status, indexed for inflation using CPI-U.
metadata:
label: WATCA cost of living exemption amount
period: year
Expand All @@ -7,15 +7,10 @@ metadata:
- filing_status
propagate_metadata_to_children: true
uprating:
parameter: gov.irs.uprating
rounding:
type: downwards
interval: 50
parameter: gov.bls.cpi.cpi_u
reference:
- title: Working Americans' Tax Cut Act bill summary (via Jeff Stein, WaPo)
href: https://x.com/JStein_WaPo/status/2029621495295619363
- title: "Democrat's plan would eliminate federal income taxes for half of U.S. workers"
href: https://www.washingtonpost.com/business/2026/03/05/middle-class-tax-relief-senate-bill/
- title: Working Americans' Tax Cut Act Section 1A(c)
href: https://www.vanhollen.senate.gov/imo/media/doc/working_americans_tax_cut_act_bill_text.pdf#page=3

SINGLE:
2026-01-01: 46_000
Expand All @@ -26,8 +21,11 @@ HEAD_OF_HOUSEHOLD:
JOINT:
2026-01-01: 92_000

# Surviving spouse treated as joint (sec 1(a)(2)). Not explicitly in bill.
SURVIVING_SPOUSE:
2026-01-01: 92_000

# Married filing separately falls under "not described in (B) or (C)",
# i.e., the 100% default category. Not explicitly in bill.
SEPARATE:
2026-01-01: 46_000
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description: The Working Americans' Tax Cut Act limits eligibility for the alternative maximum tax to filers with MAGI below this multiple of the cost of living exemption amount.
metadata:
label: WATCA cost of living exemption income limit multiple
period: year
unit: /1
reference:
- title: Working Americans' Tax Cut Act Section 1A(b)(1)
href: https://www.vanhollen.senate.gov/imo/media/doc/working_americans_tax_cut_act_bill_text.pdf#page=2

values:
2026-01-01: 1.75

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ metadata:
unit: bool
label: Working Americans' Tax Cut Act in effect
period: year
reference:
- title: Working Americans' Tax Cut Act Section 2(c), 3(d)
href: https://www.vanhollen.senate.gov/imo/media/doc/working_americans_tax_cut_act_bill_text.pdf#page=4
values:
0000-01-01: false
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ metadata:
unit: bool
label: WATCA millionaire surtax in effect
period: year
reference:
- title: Working Americans' Tax Cut Act Section 3(d)
href: https://www.vanhollen.senate.gov/imo/media/doc/working_americans_tax_cut_act_bill_text.pdf#page=8
values:
0000-01-01: true
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
description: The Working Americans' Tax Cut Act millionaire surtax rate for joint filers, based on adjusted gross income.
description: The Working Americans' Tax Cut Act millionaire surtax rate for joint filers, based on modified AGI.
metadata:
type: marginal_rate
threshold_unit: currency-USD
rate_unit: /1
period: year
label: WATCA millionaire surtax joint rate
reference:
- title: Working Americans' Tax Cut Act bill summary (via Jeff Stein, WaPo)
href: https://x.com/JStein_WaPo/status/2029621495295619363
- title: Working Americans' Tax Cut Act Section 59B(a), (c)
href: https://www.vanhollen.senate.gov/imo/media/doc/working_americans_tax_cut_act_bill_text.pdf#page=5

brackets:
- threshold:
0000-01-01: 0
2026-01-01: 0
rate:
0000-01-01: 0
2026-01-01: 0
- threshold:
0000-01-01: 1_500_000
values:
2026-01-01: 1_500_000
metadata:
uprating: gov.bls.cpi.cpi_u
rate:
0000-01-01: 0.05
2026-01-01: 0.05
- threshold:
0000-01-01: 3_000_000
values:
2026-01-01: 3_000_000
metadata:
uprating: gov.bls.cpi.cpi_u
rate:
0000-01-01: 0.10
2026-01-01: 0.10
- threshold:
0000-01-01: 7_500_000
values:
2026-01-01: 7_500_000
metadata:
uprating: gov.bls.cpi.cpi_u
rate:
0000-01-01: 0.12
2026-01-01: 0.12
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
description: The Working Americans' Tax Cut Act millionaire surtax rate for single filers, based on adjusted gross income.
description: The Working Americans' Tax Cut Act millionaire surtax rate for single filers, based on modified AGI.
metadata:
type: marginal_rate
threshold_unit: currency-USD
rate_unit: /1
period: year
label: WATCA millionaire surtax single rate
reference:
- title: Working Americans' Tax Cut Act bill summary (via Jeff Stein, WaPo)
href: https://x.com/JStein_WaPo/status/2029621495295619363
- title: Working Americans' Tax Cut Act Section 59B(a)
href: https://www.vanhollen.senate.gov/imo/media/doc/working_americans_tax_cut_act_bill_text.pdf#page=5

brackets:
- threshold:
0000-01-01: 0
2026-01-01: 0
rate:
0000-01-01: 0
2026-01-01: 0
- threshold:
0000-01-01: 1_000_000
values:
2026-01-01: 1_000_000
metadata:
uprating: gov.bls.cpi.cpi_u
rate:
0000-01-01: 0.05
2026-01-01: 0.05
- threshold:
0000-01-01: 2_000_000
values:
2026-01-01: 2_000_000
metadata:
uprating: gov.bls.cpi.cpi_u
rate:
0000-01-01: 0.10
2026-01-01: 0.10
- threshold:
0000-01-01: 5_000_000
values:
2026-01-01: 5_000_000
metadata:
uprating: gov.bls.cpi.cpi_u
rate:
0000-01-01: 0.12
2026-01-01: 0.12
Original file line number Diff line number Diff line change
@@ -1,40 +1,89 @@
from policyengine_us.model_api import *
from policyengine_core.periods import period as period_
from policyengine_core.periods import instant

WATCA_REFERENCES = [
{
"title": "Working Americans' Tax Cut Act bill summary (via Jeff Stein, WaPo)",
"href": "https://x.com/JStein_WaPo/status/2029621495295619363",
},
{
"title": "Democrat's plan would eliminate federal income"
" taxes for half of U.S. workers",
"href": "https://www.washingtonpost.com/business/"
"2026/03/05/middle-class-tax-relief-senate-bill/",
"title": "Working Americans' Tax Cut Act",
"href": "https://www.vanhollen.senate.gov/imo/media/doc/working_americans_tax_cut_act_bill_text.pdf",
},
]


def create_watca() -> Reform:
class watca_cost_of_living_exemption(Variable):
class watca_alternative_tax_magi(Variable):
value_type = float
entity = TaxUnit
label = "WATCA alternative tax modified AGI"
definition_period = YEAR
unit = USD
reference = WATCA_REFERENCES
documentation = "Section 1A(d): AGI + foreign income exclusions (sec 911, 931, 933) + non-taxable Social Security."

adds = [
"adjusted_gross_income",
"foreign_earned_income_exclusion",
"specified_possession_income",
"puerto_rico_income",
"tax_exempt_social_security",
]

class watca_surtax_magi(Variable):
value_type = float
entity = TaxUnit
label = "WATCA cost of living exemption"
label = "WATCA surtax modified AGI"
definition_period = YEAR
unit = USD
reference = WATCA_REFERENCES
documentation = (
"Section 59B(d): AGI - investment interest deduction (sec 163(d))."
)

def formula(tax_unit, period, parameters):
agi = tax_unit("adjusted_gross_income", period)
# Sec 163(d) limits the deduction to net investment income;
# PolicyEngine does not yet model that limitation, so gross
# investment interest expense is used as a proxy.
investment_interest = add(tax_unit, period, ["investment_interest_expense"])
return max_(0, agi - investment_interest)

class watca_alternative_tax_eligible(Variable):
value_type = bool
entity = TaxUnit
label = "Eligible for WATCA alternative maximum tax"
definition_period = YEAR
reference = WATCA_REFERENCES
documentation = "Section 1A(b): MAGI < 175% of exemption, and not claimed as dependent on another return."

def formula(tax_unit, period, parameters):
magi = tax_unit("watca_alternative_tax_magi", period)
filing_status = tax_unit("filing_status", period)
p = parameters(period).gov.contrib.congress.watca.cost_of_living_exemption
amount = p.amount[filing_status]
phase_out_end = amount * p.phase_out_multiple
phase_out_range = phase_out_end - amount
uncapped = (phase_out_end - agi) / phase_out_range
fraction = clip(uncapped, 0, 1)
return amount * fraction
exemption_amount = p.amount[filing_status]
income_limit = exemption_amount * p.income_limit_multiple
income_eligible = magi < income_limit
head_dependent = tax_unit("head_is_dependent_elsewhere", period)
spouse_dependent = tax_unit("spouse_is_dependent_elsewhere", period)
not_dependent = ~head_dependent & ~spouse_dependent
return income_eligible & not_dependent

class watca_alternative_max_tax(Variable):
value_type = float
entity = TaxUnit
label = "WATCA alternative maximum tax"
definition_period = YEAR
unit = USD
reference = WATCA_REFERENCES
documentation = (
"Section 1A(a): 25.5% of MAGI above the cost of living exemption."
)

def formula(tax_unit, period, parameters):
magi = tax_unit("watca_alternative_tax_magi", period)
filing_status = tax_unit("filing_status", period)
p = parameters(period).gov.contrib.congress.watca.cost_of_living_exemption
exemption_amount = p.amount[filing_status]
rate = p.alternative_tax_rate
return max_(0, magi - exemption_amount) * rate

class watca_millionaire_surtax(Variable):
value_type = float
Expand All @@ -43,44 +92,35 @@ class watca_millionaire_surtax(Variable):
definition_period = YEAR
unit = USD
reference = WATCA_REFERENCES
documentation = (
"Section 59B: Surtax on high income individuals based on modified AGI."
)

def formula(tax_unit, period, parameters):
agi = tax_unit("adjusted_gross_income", period)
magi = tax_unit("watca_surtax_magi", period)
p = parameters(period).gov.contrib.congress.watca.surtax
filing_status = tax_unit("filing_status", period)
# Sec 59B(c) specifies "joint return under section 6013".
# Surviving spouse is treated as joint here, following common
# IRS convention (sec 1(a)(2) treats surviving spouses as joint filers).
joint = (filing_status == filing_status.possible_values.JOINT) | (
filing_status == filing_status.possible_values.SURVIVING_SPOUSE
)
return where(
joint,
p.rate.joint.calc(agi),
p.rate.single.calc(agi),
p.rate.joint.calc(magi),
p.rate.single.calc(magi),
)

class taxable_income(Variable):
value_type = float
entity = TaxUnit
label = "IRS taxable income"
unit = USD
definition_period = YEAR

def formula(tax_unit, period, parameters):
agi = tax_unit("adjusted_gross_income", period)
exemptions = tax_unit("exemptions", period)
deductions = tax_unit("taxable_income_deductions", period)
watca_exemption = tax_unit("watca_cost_of_living_exemption", period)
return max_(0, agi - exemptions - deductions - watca_exemption)

class income_tax_before_credits(Variable):
value_type = float
entity = TaxUnit
definition_period = YEAR
label = "income tax before credits"
unit = USD
documentation = "Total (regular + AMT) income tax liability before credits"

def formula(tax_unit, period, parameters):
base = add(
standard_tax = add(
tax_unit,
period,
[
Expand All @@ -89,19 +129,35 @@ def formula(tax_unit, period, parameters):
"alternative_minimum_tax",
],
)
alternative_max = tax_unit("watca_alternative_max_tax", period)
eligible = tax_unit("watca_alternative_tax_eligible", period)
# The alternative max tax cap is not separately gated by
# in_effect because this variable only exists when the reform
# is loaded, which already requires in_effect = true.
tax_after_cap = where(
eligible,
min_(standard_tax, alternative_max),
standard_tax,
)
p = parameters(period).gov.contrib.congress.watca.surtax
surtax = where(
p.in_effect,
tax_unit("watca_millionaire_surtax", period),
0,
)
return base + surtax
# Known limitation: Sec 59B(e)(3) says the surtax should not
# be treated as tax for purposes of credits or AMT. Adding it
# here (before credits) means credits could offset it.
# Fixing this requires restructuring the tax computation chain.
return tax_after_cap + surtax

class reform(Reform):
def apply(self):
self.update_variable(watca_cost_of_living_exemption)
self.update_variable(watca_alternative_tax_magi)
self.update_variable(watca_surtax_magi)
self.update_variable(watca_alternative_tax_eligible)
self.update_variable(watca_alternative_max_tax)
self.update_variable(watca_millionaire_surtax)
self.update_variable(taxable_income)
self.update_variable(income_tax_before_credits)

return reform
Expand Down
Loading
Loading