diff --git a/changelog.d/fix-watca-alternative-max-tax.changed.md b/changelog.d/fix-watca-alternative-max-tax.changed.md new file mode 100644 index 00000000000..08f47ddcdf1 --- /dev/null +++ b/changelog.d/fix-watca-alternative-max-tax.changed.md @@ -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. diff --git a/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/alternative_tax_rate.yaml b/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/alternative_tax_rate.yaml new file mode 100644 index 00000000000..6d0705fb3ae --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/alternative_tax_rate.yaml @@ -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 diff --git a/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/amount.yaml b/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/amount.yaml index 830c4f49ab9..8679263cf22 100644 --- a/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/amount.yaml +++ b/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/amount.yaml @@ -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 @@ -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 @@ -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 diff --git a/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/income_limit_multiple.yaml b/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/income_limit_multiple.yaml new file mode 100644 index 00000000000..1be23b36abd --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/income_limit_multiple.yaml @@ -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 diff --git a/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/phase_out_multiple.yaml b/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/phase_out_multiple.yaml deleted file mode 100644 index 82b2fa4f935..00000000000 --- a/policyengine_us/parameters/gov/contrib/congress/watca/cost_of_living_exemption/phase_out_multiple.yaml +++ /dev/null @@ -1,10 +0,0 @@ -description: The Working Americans' Tax Cut Act phases out the cost of living exemption between the exemption amount and this multiple of the exemption amount. -metadata: - label: WATCA cost of living exemption phase-out multiple - period: year - unit: /1 - reference: - - title: Working Americans' Tax Cut Act bill summary (via Jeff Stein, WaPo) - href: https://x.com/JStein_WaPo/status/2029621495295619363 -values: - 0000-01-01: 1.75 diff --git a/policyengine_us/parameters/gov/contrib/congress/watca/in_effect.yaml b/policyengine_us/parameters/gov/contrib/congress/watca/in_effect.yaml index e900158e677..aadcec866e0 100644 --- a/policyengine_us/parameters/gov/contrib/congress/watca/in_effect.yaml +++ b/policyengine_us/parameters/gov/contrib/congress/watca/in_effect.yaml @@ -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 diff --git a/policyengine_us/parameters/gov/contrib/congress/watca/surtax/in_effect.yaml b/policyengine_us/parameters/gov/contrib/congress/watca/surtax/in_effect.yaml index 426086f7da9..70d03a86b84 100644 --- a/policyengine_us/parameters/gov/contrib/congress/watca/surtax/in_effect.yaml +++ b/policyengine_us/parameters/gov/contrib/congress/watca/surtax/in_effect.yaml @@ -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 diff --git a/policyengine_us/parameters/gov/contrib/congress/watca/surtax/rate/joint.yaml b/policyengine_us/parameters/gov/contrib/congress/watca/surtax/rate/joint.yaml index acb01027215..1a558f083e5 100644 --- a/policyengine_us/parameters/gov/contrib/congress/watca/surtax/rate/joint.yaml +++ b/policyengine_us/parameters/gov/contrib/congress/watca/surtax/rate/joint.yaml @@ -1,4 +1,4 @@ -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 @@ -6,23 +6,32 @@ metadata: 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 diff --git a/policyengine_us/parameters/gov/contrib/congress/watca/surtax/rate/single.yaml b/policyengine_us/parameters/gov/contrib/congress/watca/surtax/rate/single.yaml index 342299f501d..ef00c0448c8 100644 --- a/policyengine_us/parameters/gov/contrib/congress/watca/surtax/rate/single.yaml +++ b/policyengine_us/parameters/gov/contrib/congress/watca/surtax/rate/single.yaml @@ -1,4 +1,4 @@ -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 @@ -6,23 +6,32 @@ metadata: 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 diff --git a/policyengine_us/reforms/congress/watca/working_americans_tax_cut_act.py b/policyengine_us/reforms/congress/watca/working_americans_tax_cut_act.py index 9653962ad84..860462a6ed5 100644 --- a/policyengine_us/reforms/congress/watca/working_americans_tax_cut_act.py +++ b/policyengine_us/reforms/congress/watca/working_americans_tax_cut_act.py @@ -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 @@ -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, [ @@ -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 diff --git a/policyengine_us/tests/policy/contrib/congress/watca.yaml b/policyengine_us/tests/policy/contrib/congress/watca.yaml index a761d242b9b..500ed7e863b 100644 --- a/policyengine_us/tests/policy/contrib/congress/watca.yaml +++ b/policyengine_us/tests/policy/contrib/congress/watca.yaml @@ -1,129 +1,210 @@ # Working Americans' Tax Cut Act tests -# === Cost of Living Exemption === +# === Alternative Maximum Tax Eligibility (Binary) === -- name: Single filer below exemption amount (full exemption) +- name: Single filer below income limit (eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 30_000 + adjusted_gross_income: 80_000 filing_status: SINGLE output: - watca_cost_of_living_exemption: 46_000 + # Income limit: 46_000 * 1.75 = 80_500 + watca_alternative_tax_eligible: true -- name: Single filer at exactly exemption amount (full exemption) +- name: Single filer at exactly income limit (not eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 46_000 + adjusted_gross_income: 80_500 filing_status: SINGLE output: - watca_cost_of_living_exemption: 46_000 + # Income limit: 46_000 * 1.75 = 80_500; AGI >= limit means not eligible + watca_alternative_tax_eligible: false -- name: Single filer mid-phaseout (AGI = 60_500, midpoint of 46K to 80.5K) +- name: Single filer above income limit (not eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 63_250 + adjusted_gross_income: 100_000 filing_status: SINGLE output: - # Phase-out range: 46_000 to 80_500 (46_000 * 1.75) - # fraction = (80_500 - 63_250) / (80_500 - 46_000) = 17_250 / 34_500 = 0.5 - # exemption = 46_000 * 0.5 = 23_000 - watca_cost_of_living_exemption: 23_000 + watca_alternative_tax_eligible: false -- name: Single filer at exactly phase-out end (AGI = 80_500) +- name: Joint filer below income limit (eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 80_500 - filing_status: SINGLE + adjusted_gross_income: 160_000 + filing_status: JOINT output: - # Phase-out end: 46_000 * 1.75 = 80_500; fraction = 0 - watca_cost_of_living_exemption: 0 + # Income limit: 92_000 * 1.75 = 161_000 + watca_alternative_tax_eligible: true -- name: Single filer above phase-out (AGI >= 80_500) +- name: Joint filer above income limit (not eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 100_000 - filing_status: SINGLE + adjusted_gross_income: 165_000 + filing_status: JOINT output: - watca_cost_of_living_exemption: 0 + watca_alternative_tax_eligible: false -- name: Joint filer below exemption (full exemption) +- name: HOH filer below income limit (eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 50_000 + adjusted_gross_income: 110_000 + filing_status: HEAD_OF_HOUSEHOLD + output: + # Income limit: 64_400 * 1.75 = 112_700 + watca_alternative_tax_eligible: true + +- name: Joint filer at exactly income limit (not eligible) + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 161_000 filing_status: JOINT output: - watca_cost_of_living_exemption: 92_000 + # Income limit: 92_000 * 1.75 = 161_000; strict < means not eligible + watca_alternative_tax_eligible: false -- name: HOH filer at exemption amount (full exemption) +- name: HOH filer at exactly income limit (not eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 64_400 + adjusted_gross_income: 112_700 filing_status: HEAD_OF_HOUSEHOLD output: - watca_cost_of_living_exemption: 64_400 + watca_alternative_tax_eligible: false -- name: HOH filer above phase-out (AGI >= 112_700) +- name: Separate filer below income limit (eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 120_000 - filing_status: HEAD_OF_HOUSEHOLD + adjusted_gross_income: 70_000 + filing_status: SEPARATE output: - # Phase-out end: 64_400 * 1.75 = 112_700 - watca_cost_of_living_exemption: 0 + watca_alternative_tax_eligible: true -- name: Surviving spouse filer below exemption (full exemption, same as joint) +- name: Separate filer at exactly income limit (not eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 50_000 + adjusted_gross_income: 80_500 + filing_status: SEPARATE + output: + watca_alternative_tax_eligible: false + +- name: Surviving spouse below income limit (eligible) + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 150_000 filing_status: SURVIVING_SPOUSE output: - watca_cost_of_living_exemption: 92_000 + watca_alternative_tax_eligible: true -- name: Separate filer below exemption (full exemption, same as single) +- name: Surviving spouse at exactly income limit (not eligible) period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 30_000 - filing_status: SEPARATE + adjusted_gross_income: 161_000 + filing_status: SURVIVING_SPOUSE output: - watca_cost_of_living_exemption: 46_000 + watca_alternative_tax_eligible: false + +# === Alternative Maximum Tax Calculation === -# === Taxable Income Reduction === +- name: Alternative max tax for single filer at 60K AGI + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 60_000 + filing_status: SINGLE + output: + # (60_000 - 46_000) * 0.255 = 14_000 * 0.255 = 3_570 + watca_alternative_max_tax: 3_570 -- name: Taxable income reduced by cost of living exemption +- name: Alternative max tax for single filer below exemption period: 2026 - absolute_error_margin: 1 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true adjusted_gross_income: 30_000 filing_status: SINGLE - taxable_income_deductions: 0 - exemptions: 0 output: - # AGI=30K < exemption=46K, so full exemption - # max(0, 30_000 - 0 - 0 - 46_000) = max(0, -16_000) = 0 - watca_cost_of_living_exemption: 46_000 - taxable_income: 0 + # max(0, 30_000 - 46_000) * 0.255 = 0 + watca_alternative_max_tax: 0 + +- name: Alternative max tax for joint filer at 120K AGI + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 120_000 + filing_status: JOINT + output: + # (120_000 - 92_000) * 0.255 = 28_000 * 0.255 = 7_140 + watca_alternative_max_tax: 7_140 + +- name: Alternative max tax for joint filer below exemption + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 80_000 + filing_status: JOINT + output: + # max(0, 80_000 - 92_000) * 0.255 = 0 + watca_alternative_max_tax: 0 + +- name: Alternative max tax for HOH filer above exemption + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 80_000 + filing_status: HEAD_OF_HOUSEHOLD + output: + # (80_000 - 64_400) * 0.255 = 15_600 * 0.255 = 3_978 + watca_alternative_max_tax: 3_978 + +- name: Alternative max tax for separate filer + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 60_000 + filing_status: SEPARATE + output: + # (60_000 - 46_000) * 0.255 = 3_570 + watca_alternative_max_tax: 3_570 + +- name: Alternative max tax for surviving spouse + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 120_000 + filing_status: SURVIVING_SPOUSE + output: + # (120_000 - 92_000) * 0.255 = 7_140 + watca_alternative_max_tax: 7_140 # === Millionaire Surtax === @@ -190,7 +271,6 @@ adjusted_gross_income: 2_000_000 filing_status: SURVIVING_SPOUSE output: - # Joint brackets: (2_000_000 - 1_500_000) * 0.05 = 25_000 watca_millionaire_surtax: 25_000 - name: Separate filer uses single surtax brackets @@ -201,105 +281,272 @@ adjusted_gross_income: 1_500_000 filing_status: SEPARATE output: - # Single brackets: (1_500_000 - 1_000_000) * 0.05 = 25_000 watca_millionaire_surtax: 25_000 -- name: Surtax disabled excludes surtax from income tax +- name: Single filer at $6M (in 12% bracket) period: 2026 - absolute_error_margin: 3 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - gov.contrib.congress.watca.surtax.in_effect: false - adjusted_gross_income: 5_000_000 + adjusted_gross_income: 6_000_000 filing_status: SINGLE output: - # (2M-1M)*0.05 + (5M-2M)*0.10 = 50K + 300K = 350K - watca_millionaire_surtax: 350_000 - # Surtax computed but not included in income_tax_before_credits + # (2M-1M)*0.05 + (5M-2M)*0.10 + (6M-5M)*0.12 = 50_000 + 300_000 + 120_000 = 470_000 + watca_millionaire_surtax: 470_000 -# === Integration: surtax flows into income_tax_before_credits === +- name: Single filer at exactly $1M boundary (no surtax) + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 1_000_000 + filing_status: SINGLE + output: + watca_millionaire_surtax: 0 -- name: Surtax included in income_tax_before_credits +- name: Joint filer below $1.5M (no surtax) + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 1_400_000 + filing_status: JOINT + output: + watca_millionaire_surtax: 0 + +- name: HOH filer uses single surtax brackets period: 2026 - absolute_error_margin: 3 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true adjusted_gross_income: 1_500_000 - filing_status: SINGLE + filing_status: HEAD_OF_HOUSEHOLD output: + # HOH is not JOINT/SURVIVING_SPOUSE, so uses single brackets + # (1_500_000 - 1_000_000) * 0.05 = 25_000 watca_millionaire_surtax: 25_000 -# === CPI Indexation (post-2026) === +# === Modified AGI Tests === -- name: "2027: Single filer exemption indexed to $47,200" - period: 2027 +- name: Alternative tax MAGI includes foreign earned income + period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 30_000 + adjusted_gross_income: 70_000 + foreign_earned_income_exclusion: 10_000 filing_status: SINGLE output: - watca_cost_of_living_exemption: 47_200 + # MAGI = 70_000 + 10_000 = 80_000 + watca_alternative_tax_magi: 80_000 -- name: "2027: Joint filer exemption indexed to $94,400" - period: 2027 +- name: Alternative tax MAGI includes non-taxable Social Security + period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true adjusted_gross_income: 50_000 - filing_status: JOINT + tax_unit_social_security: 20_000 + tax_unit_taxable_social_security: 5_000 + filing_status: SINGLE output: - watca_cost_of_living_exemption: 94_400 + # MAGI = 50_000 + (20_000 - 5_000) = 65_000 + watca_alternative_tax_magi: 65_000 -- name: "2027: HOH filer exemption indexed to $66,100" - period: 2027 +- name: Alternative tax MAGI includes specified possession income + period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 50_000 - filing_status: HEAD_OF_HOUSEHOLD + adjusted_gross_income: 60_000 + specified_possession_income: 5_000 + filing_status: SINGLE + output: + watca_alternative_tax_magi: 65_000 + +- name: Alternative tax MAGI includes Puerto Rico income + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 60_000 + puerto_rico_income: 8_000 + filing_status: SINGLE + output: + watca_alternative_tax_magi: 68_000 + +- name: Surtax MAGI reduces by investment interest + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + employment_income: 2_000_000 + investment_interest_expense: 50_000 + filing_status: SINGLE + output: + # Surtax MAGI = 2_000_000 - 50_000 = 1_950_000 + watca_surtax_magi: 1_950_000 + # Surtax = (1_950_000 - 1_000_000) * 0.05 = 47_500 + watca_millionaire_surtax: 47_500 + +- name: Surtax MAGI floors at zero when investment interest exceeds AGI + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 20_000 + investment_interest_expense: 50_000 + filing_status: SINGLE + output: + # max(0, 20_000 - 50_000) = 0 + watca_surtax_magi: 0 + +# === Integration: income_tax_before_credits === + +- name: Eligible filer income tax capped at alternative max + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + employment_income: 60_000 + filing_status: SINGLE + output: + # MAGI = 60K < 80_500 threshold => eligible + # Alternative max = (60_000 - 46_000) * 0.255 = 3_570 + # Standard tax on ~45K taxable income > 3_570, so cap binds + watca_alternative_tax_eligible: true + income_tax_before_credits: 3_570 + +- name: Ineligible filer tax equals standard tax plus surtax + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + employment_income: 100_000 + filing_status: SINGLE output: - watca_cost_of_living_exemption: 66_100 + # AGI of 100K > 80_500 threshold => not eligible, no cap applied + # No surtax (below $1M) + # income_tax_before_credits = income_tax_main_rates + cap_gains + AMT + watca_alternative_tax_eligible: false + watca_millionaire_surtax: 0 + +# === Dependent Exclusion Tests === -- name: "2030: Single filer exemption indexed to $50,200" - period: 2030 +- name: Dependent claimed elsewhere not eligible for alternative tax + period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true adjusted_gross_income: 30_000 filing_status: SINGLE + head_is_dependent_elsewhere: true output: - watca_cost_of_living_exemption: 50_200 + # Even though income is below limit, not eligible because claimed as dependent + watca_alternative_tax_eligible: false -- name: "2030: Joint filer exemption indexed to $100,450" - period: 2030 +- name: Spouse claimed as dependent elsewhere not eligible + period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 50_000 + adjusted_gross_income: 30_000 filing_status: JOINT + spouse_is_dependent_elsewhere: true output: - watca_cost_of_living_exemption: 100_450 + watca_alternative_tax_eligible: false -- name: "2035: Single filer exemption indexed to $55,400" - period: 2035 +# === Edge Cases === + +- name: Zero income filer eligible for alternative tax + period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 30_000 + adjusted_gross_income: 0 + filing_status: SINGLE + output: + watca_alternative_tax_eligible: true + watca_alternative_max_tax: 0 + watca_alternative_tax_magi: 0 + +- name: Negative AGI floors alternative max tax at zero + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: -10_000 + filing_status: SINGLE + output: + watca_alternative_tax_eligible: true + # max(0, -10_000 - 46_000) * 0.255 = 0 + watca_alternative_max_tax: 0 + +- name: MAGI add-backs push filer over eligibility threshold + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 75_000 + foreign_earned_income_exclusion: 6_000 filing_status: SINGLE output: - watca_cost_of_living_exemption: 55_400 + # MAGI = 75_000 + 6_000 = 81_000 > 80_500 threshold + watca_alternative_tax_magi: 81_000 + watca_alternative_tax_eligible: false -- name: "2027: Single filer phase-out end adjusts with indexed amount" - period: 2027 +- name: Investment interest pushes millionaire below surtax threshold + period: 2026 reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 82_600 + employment_income: 1_050_000 + investment_interest_expense: 100_000 + filing_status: SINGLE + output: + # Surtax MAGI = 1_050_000 - 100_000 = 950_000 < $1M threshold + watca_surtax_magi: 950_000 + watca_millionaire_surtax: 0 + +- name: Combined MAGI add-backs all non-zero + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 50_000 + foreign_earned_income_exclusion: 5_000 + specified_possession_income: 3_000 + puerto_rico_income: 2_000 + tax_unit_social_security: 10_000 + tax_unit_taxable_social_security: 4_000 + filing_status: SINGLE + output: + # MAGI = 50_000 + 5_000 + 3_000 + 2_000 + (10_000 - 4_000) = 66_000 + watca_alternative_tax_magi: 66_000 + +- name: Both head and spouse claimed as dependents + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + adjusted_gross_income: 30_000 + filing_status: JOINT + head_is_dependent_elsewhere: true + spouse_is_dependent_elsewhere: true + output: + watca_alternative_tax_eligible: false + +# === Surtax Toggle Test === + +- name: Surtax disabled via surtax.in_effect parameter + period: 2026 + reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object + input: + gov.contrib.congress.watca.in_effect: true + gov.contrib.congress.watca.surtax.in_effect: false + employment_income: 2_000_000 filing_status: SINGLE output: - # Phase-out end: 47_200 * 1.75 = 82_600; fraction = 0 - watca_cost_of_living_exemption: 0 + # Surtax variable still computes but income_tax_before_credits should not include it + watca_alternative_tax_eligible: false + watca_millionaire_surtax: 50_000