diff --git a/changelog.d/wa-millionaires-tax.added.md b/changelog.d/wa-millionaires-tax.added.md new file mode 100644 index 00000000000..461bbabbff9 --- /dev/null +++ b/changelog.d/wa-millionaires-tax.added.md @@ -0,0 +1 @@ +Add Washington millionaires tax (9.9% on income above $1M) and WFTC age expansion (18+) per ESSB 6346. Removes contributed reform since bill is now law. diff --git a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/charitable_deduction/cap/individual.yaml b/policyengine_us/parameters/gov/contrib/states/wa/sb6346/charitable_deduction/cap/individual.yaml deleted file mode 100644 index d6f8d582335..00000000000 --- a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/charitable_deduction/cap/individual.yaml +++ /dev/null @@ -1,12 +0,0 @@ -description: Washington limits the charitable contribution deduction to this amount per individual under the SSB 6346 reform. - -values: - 2028-01-01: 100_000 - -metadata: - unit: currency-USD - period: year - label: Washington SSB 6346 individual charitable deduction cap - reference: - - title: SSB 6346, Sec. 307 - Charitable Contributions - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=10 diff --git a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/charitable_deduction/cap/joint.yaml b/policyengine_us/parameters/gov/contrib/states/wa/sb6346/charitable_deduction/cap/joint.yaml deleted file mode 100644 index 298b9b479c3..00000000000 --- a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/charitable_deduction/cap/joint.yaml +++ /dev/null @@ -1,12 +0,0 @@ -description: Washington limits the combined charitable contribution deduction for married couples to this amount under the SSB 6346 reform. - -values: - 2028-01-01: 100_000 - -metadata: - unit: currency-USD - period: year - label: Washington SSB 6346 joint charitable deduction cap - reference: - - title: SSB 6346, Sec. 307 - Charitable Contributions - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=10 diff --git a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/wa/sb6346/in_effect.yaml deleted file mode 100644 index c4270ebe8db..00000000000 --- a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/in_effect.yaml +++ /dev/null @@ -1,12 +0,0 @@ -description: Washington uses this indicator to determine whether the SSB 6346 income tax reform is in effect. - -values: - 2024-01-01: false - -metadata: - unit: bool - period: year - label: Washington SSB 6346 income tax reform in effect - reference: - - title: SSB 6346, 69th Legislature, 2025-2026 - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=1 diff --git a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/rate.yaml b/policyengine_us/parameters/gov/contrib/states/wa/sb6346/rate.yaml deleted file mode 100644 index a1166deeb0a..00000000000 --- a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/rate.yaml +++ /dev/null @@ -1,12 +0,0 @@ -description: Washington sets the income tax rate to this share under the SSB 6346 reform. - -values: - 2028-01-01: 0.099 - -metadata: - unit: /1 - period: year - label: Washington SSB 6346 income tax rate - reference: - - title: SSB 6346, Sec. 201(1) - Tax Imposed - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=6 diff --git a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/standard_deduction/amount.yaml b/policyengine_us/parameters/gov/contrib/states/wa/sb6346/standard_deduction/amount.yaml deleted file mode 100644 index 4d0e7de520b..00000000000 --- a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/standard_deduction/amount.yaml +++ /dev/null @@ -1,21 +0,0 @@ -description: Washington provides this amount as the standard deduction under the SSB 6346 reform. - -values: - 2028-01-01: 1_000_000 - -metadata: - unit: currency-USD - period: year - label: Washington SSB 6346 standard deduction - uprating: gov.bls.cpi.cpi_u - # Sec. 312 specifies Seattle-area CPI-U for indexing starting Oct 2029 - # (for tax year 2030). Using national CPI-U as a proxy until we add - # Seattle-area CPI data. Fixed at $1M for 2028-2029. - rounding: - type: nearest - interval: 1_000 - reference: - - title: SSB 6346, Sec. 310 - One million dollar standard deduction - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=10 - - title: SSB 6346, Sec. 312(1) - Index for inflation - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=11 diff --git a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/wftc/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/wa/sb6346/wftc/in_effect.yaml deleted file mode 100644 index 91bd69c832d..00000000000 --- a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/wftc/in_effect.yaml +++ /dev/null @@ -1,15 +0,0 @@ -description: Washington uses this indicator to determine whether the SSB 6346 Working Families Tax Credit age expansion is in effect. - -values: - 2024-01-01: false - 2029-01-01: true - -metadata: - unit: bool - period: year - label: Washington SSB 6346 WFTC age expansion in effect - reference: - - title: SSB 6346, Sec. 901(2)(a)(ii)(C) - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=53 - - title: SSB 6346, Sec. 1005(1) - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=63 diff --git a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/wftc/min_age.yaml b/policyengine_us/parameters/gov/contrib/states/wa/sb6346/wftc/min_age.yaml deleted file mode 100644 index 1b7c8624d98..00000000000 --- a/policyengine_us/parameters/gov/contrib/states/wa/sb6346/wftc/min_age.yaml +++ /dev/null @@ -1,16 +0,0 @@ -description: Washington sets this age threshold for expanded Working Families Tax Credit eligibility under the SSB 6346 reform. - -values: - 2029-01-01: 18 - -# PolicyEngine does not model the WFTC's claim-year timing separately from the -# simulated tax year, so the later effective date in Sec. 1005(1) is enforced -# through the companion wftc/in_effect parameter rather than by backdating this -# threshold before 2029. -metadata: - unit: year - period: year - label: Washington SSB 6346 WFTC minimum age threshold - reference: - - title: SSB 6346, Sec. 901(2)(a)(ii)(C) - href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=53 diff --git a/policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/in_effect.yaml b/policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/in_effect.yaml new file mode 100644 index 00000000000..a4062b81c32 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/in_effect.yaml @@ -0,0 +1,13 @@ +description: Washington uses this indicator to determine whether the Working Families Tax Credit age expansion applies. +values: + 2000-01-01: false + 2029-01-01: true +metadata: + unit: bool + period: year + label: Washington WFTC age expansion in effect + reference: + - title: ESSB 6346, Sec. 901 - Working Families Tax Credit expansion + href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=61 + - title: ESSB 6346, Sec. 1205(1) - Effective date + href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=110 diff --git a/policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/min_age.yaml b/policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/min_age.yaml new file mode 100644 index 00000000000..e35301f1a39 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/min_age.yaml @@ -0,0 +1,11 @@ +description: Washington sets this age as the minimum for eligibility under the Working Families Tax Credit age expansion. +values: + 2000-01-01: 0 + 2029-01-01: 18 +metadata: + unit: year + period: year + label: Washington WFTC minimum age for expansion + reference: + - title: ESSB 6346, Sec. 901(2)(a)(ii)(D) - Age requirement + href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=61 diff --git a/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/deductions/charitable/cap.yaml b/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/deductions/charitable/cap.yaml new file mode 100644 index 00000000000..cb257e8d977 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/deductions/charitable/cap.yaml @@ -0,0 +1,10 @@ +description: Washington limits charitable deductions to this amount under the millionaires tax. +values: + 2028-01-01: 100_000 +metadata: + unit: currency-USD + period: year + label: Washington millionaires tax charitable deduction cap + reference: + - title: ESSB 6346, Sec. 309(1) - Charitable contributions + href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=14 diff --git a/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/deductions/standard.yaml b/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/deductions/standard.yaml new file mode 100644 index 00000000000..62b67830155 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/deductions/standard.yaml @@ -0,0 +1,19 @@ +description: Washington deducts this amount as the standard deduction under the millionaires tax. +values: + 2028-01-01: 1_000_000 +metadata: + unit: currency-USD + period: year + label: Washington millionaires tax standard deduction + uprating: gov.bls.cpi.cpi_u + # Sec. 316 specifies Seattle-area CPI-U for indexing starting Oct 2029 + # (for tax year 2030). Using national CPI-U as a proxy until we add + # Seattle-area CPI data. Fixed at $1M for 2028-2029. + rounding: + type: nearest + interval: 1_000 + reference: + - title: ESSB 6346, Sec. 314 - One million dollar standard deduction + href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=15 + - title: ESSB 6346, Sec. 316(1) - Index for inflation + href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=15 diff --git a/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/in_effect.yaml b/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/in_effect.yaml new file mode 100644 index 00000000000..61d6caa895e --- /dev/null +++ b/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/in_effect.yaml @@ -0,0 +1,11 @@ +description: Washington applies the millionaires tax if this is true. +values: + 2000-01-01: false + 2028-01-01: true +metadata: + unit: bool + period: year + label: Washington millionaires tax in effect + reference: + - title: ESSB 6346, Sec. 201(1) - Tax Imposed + href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=8 diff --git a/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/rate.yaml b/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/rate.yaml new file mode 100644 index 00000000000..454f7aaeaef --- /dev/null +++ b/policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/rate.yaml @@ -0,0 +1,10 @@ +description: Washington taxes income at this rate under the millionaires tax. +values: + 2028-01-01: 0.099 +metadata: + unit: /1 + period: year + label: Washington millionaires tax rate + reference: + - title: ESSB 6346, Sec. 201(1) - Tax Imposed + href: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=8 diff --git a/policyengine_us/reforms/reforms.py b/policyengine_us/reforms/reforms.py index f774002d35c..46f15a2d67b 100644 --- a/policyengine_us/reforms/reforms.py +++ b/policyengine_us/reforms/reforms.py @@ -184,9 +184,6 @@ from .congress.watca import ( create_watca_reform, ) -from .states.wa.sb6346.sb6346 import ( - create_wa_sb6346_reform, -) from .states.ga.sb520 import ( @@ -411,7 +408,6 @@ def create_structural_reforms_from_parameters(parameters, period): nc_eitc = create_nc_eitc_reform(parameters, period) mi_ctc = create_mi_ctc_reform(parameters, period) watca = create_watca_reform(parameters, period) - wa_sb6346 = create_wa_sb6346_reform(parameters, period) al_eitc = create_al_eitc_reform(parameters, period) ar_eitc = create_ar_eitc_reform(parameters, period) az_eitc = create_az_eitc_reform(parameters, period) @@ -516,7 +512,6 @@ def create_structural_reforms_from_parameters(parameters, period): nc_eitc, mi_ctc, watca, - wa_sb6346, al_eitc, ar_eitc, az_eitc, diff --git a/policyengine_us/reforms/states/wa/sb6346/__init__.py b/policyengine_us/reforms/states/wa/sb6346/__init__.py deleted file mode 100644 index 9fca7b7fed4..00000000000 --- a/policyengine_us/reforms/states/wa/sb6346/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .sb6346 import create_wa_sb6346_reform, wa_sb6346 diff --git a/policyengine_us/reforms/states/wa/sb6346/sb6346.py b/policyengine_us/reforms/states/wa/sb6346/sb6346.py deleted file mode 100644 index 7f3596eb131..00000000000 --- a/policyengine_us/reforms/states/wa/sb6346/sb6346.py +++ /dev/null @@ -1,194 +0,0 @@ -from policyengine_us.model_api import * -from policyengine_core.periods import period as period_ - - -def create_wa_sb6346() -> Reform: - """ - WA SSB 6346 - 9.9% income tax on high earners. - - Imposes a 9.9% tax on Washington taxable income (federal AGI minus - a $1M standard deduction and capped charitable deduction). - - Reference: https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf - """ - - class wa_income_tax_base_income(Variable): - value_type = float - entity = TaxUnit - label = "Washington base income under SSB 6346" - unit = USD - definition_period = YEAR - reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=5" - defined_for = StateCode.WA - adds = ["adjusted_gross_income"] - - class wa_income_tax_charitable_deduction(Variable): - value_type = float - entity = TaxUnit - label = "Washington income tax charitable deduction under SSB 6346" - unit = USD - definition_period = YEAR - reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=10" - defined_for = StateCode.WA - - def formula(tax_unit, period, parameters): - p = parameters(period).gov.contrib.states.wa.sb6346.charitable_deduction.cap - filing_status = tax_unit("filing_status", period) - charitable = add( - tax_unit, - period, - ["charitable_cash_donations", "charitable_non_cash_donations"], - ) - is_joint = filing_status == filing_status.possible_values.JOINT - cap = where(is_joint, p.joint, p.individual) - return min_(charitable, cap) - - class wa_income_tax_standard_deduction(Variable): - value_type = float - entity = TaxUnit - label = "Washington income tax standard deduction under SSB 6346" - unit = USD - definition_period = YEAR - reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=10" - defined_for = StateCode.WA - adds = ["gov.contrib.states.wa.sb6346.standard_deduction.amount"] - - class wa_income_tax_taxable_income(Variable): - value_type = float - entity = TaxUnit - label = "Washington taxable income under SSB 6346" - unit = USD - definition_period = YEAR - reference = ( - "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=10", - "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=11", - ) - defined_for = StateCode.WA - - def formula(tax_unit, period, parameters): - in_effect = parameters(period).gov.contrib.states.wa.sb6346.in_effect - base_income = tax_unit("wa_income_tax_base_income", period) - charitable_deduction = tax_unit( - "wa_income_tax_charitable_deduction", period - ) - standard_deduction = tax_unit("wa_income_tax_standard_deduction", period) - return where( - in_effect, - max_(base_income - charitable_deduction - standard_deduction, 0), - 0, - ) - - class wa_income_tax_before_refundable_credits(Variable): - value_type = float - entity = TaxUnit - label = "Washington income tax before refundable credits" - unit = USD - definition_period = YEAR - reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=6" - defined_for = StateCode.WA - - def formula(tax_unit, period, parameters): - p = parameters(period).gov.contrib.states.wa.sb6346 - in_effect = p.in_effect - taxable_income = tax_unit("wa_income_tax_taxable_income", period) - sb6346_tax = taxable_income * p.rate - capital_gains_tax = tax_unit("wa_capital_gains_tax", period) - return where(in_effect, sb6346_tax + capital_gains_tax, capital_gains_tax) - - class wa_income_tax(Variable): - value_type = float - entity = TaxUnit - label = "Washington income tax" - unit = USD - definition_period = YEAR - reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=6" - defined_for = StateCode.WA - adds = ["wa_income_tax_before_refundable_credits"] - subtracts = ["wa_refundable_credits"] - - class wa_working_families_tax_credit(Variable): - value_type = float - entity = TaxUnit - label = "Washington Working Families Tax Credit" - unit = USD - definition_period = YEAR - reference = ( - "https://app.leg.wa.gov/RCW/default.aspx?cite=82.08.0206", - "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Bills/6346-S.pdf#page=53", - ) - defined_for = StateCode.WA - - def formula(tax_unit, period, parameters): - eitc = tax_unit("eitc", period) - eitc_eligible = eitc > 0 - # SSB 6346 Sec. 901(2)(a)(ii)(C): individuals who do not meet - # the EITC age requirement but are at least age 18. - reform_in_effect = parameters(period).gov.contrib.states.wa.sb6346.in_effect - sb6346_p = parameters(period).gov.contrib.states.wa.sb6346.wftc - expansion_in_effect = reform_in_effect & sb6346_p.in_effect - age_head = tax_unit("age_head", period) - age_spouse = tax_unit("age_spouse", period) - filer_at_least_min_age = expansion_in_effect & ( - (age_head >= sb6346_p.min_age) | (age_spouse >= sb6346_p.min_age) - ) - earned_income = tax_unit("filer_adjusted_earnings", period) - has_earned_income = earned_income > 0 - eligible = eitc_eligible | (filer_at_least_min_age & has_earned_income) - p = parameters( - period - ).gov.states.wa.tax.income.credits.working_families_tax_credit - eitc_child_count = tax_unit("eitc_child_count", period) - max_amount = p.amount.calc(eitc_child_count) - eitc_agi_limit = tax_unit("eitc_agi_limit", period) - phase_out_start_reduction = p.phase_out.start_below_eitc.calc( - eitc_child_count - ) - phase_out_start = eitc_agi_limit - phase_out_start_reduction - phase_out_rate = (max_amount - p.min_amount) / phase_out_start_reduction - excess = max_(0, earned_income - phase_out_start) - reduction = max_(0, excess * phase_out_rate) - phased_out_amount = max_amount - reduction - amount_if_eligible = where( - phased_out_amount > 0, - max_(p.min_amount, phased_out_amount), - 0, - ) - return amount_if_eligible * eligible - - class reform(Reform): - def apply(self): - self.update_variable(wa_income_tax_base_income) - self.update_variable(wa_income_tax_charitable_deduction) - self.update_variable(wa_income_tax_standard_deduction) - self.update_variable(wa_income_tax_taxable_income) - self.update_variable(wa_income_tax_before_refundable_credits) - self.update_variable(wa_income_tax) - self.update_variable(wa_working_families_tax_credit) - - return reform - - -def create_wa_sb6346_reform(parameters, period, bypass=False): - if bypass: - return create_wa_sb6346() - - p = parameters.gov.contrib.states.wa.sb6346 - - reform_active = False - current_period = period_(period) - - # Match the standard five-year structural reform lookahead used across - # the repo so future-year simulations can pick up contributed reforms. - for _ 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_wa_sb6346() - else: - return None - - -wa_sb6346 = create_wa_sb6346_reform(None, None, bypass=True) diff --git a/policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml index 422d42cf1ec..e3b86a448e9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml @@ -1,4 +1,7 @@ -- name: Ineligible without EITC. +# Washington Working Families Tax Credit tests +# RCW 82.08.0206 and ESSB 6346 Sec. 901 (age expansion) + +- name: Case 1, ineligible without EITC. period: 2022 absolute_error_margin: 0 input: @@ -6,7 +9,7 @@ output: wa_working_families_tax_credit: 0 -- name: Single eligible person with no income will get the maximum credit. +- name: Case 2, single eligible person with no income gets maximum credit. period: 2022 absolute_error_margin: 0 input: @@ -17,7 +20,7 @@ output: wa_working_families_tax_credit: 300 -- name: Family with income over the limit doesn't receive it. +- name: Case 3, family with income over the limit receives no credit. period: 2022 absolute_error_margin: 0 input: @@ -28,7 +31,7 @@ output: wa_working_families_tax_credit: 0 -- name: At EITC AGI limit, credit phases to $50 minimum per RCW 82.08.0206(3)(f). +- name: Case 4, at EITC AGI limit credit phases to $50 minimum. period: 2024 absolute_error_margin: 0.01 input: @@ -38,9 +41,10 @@ eitc_agi_limit: 50_000 filer_adjusted_earnings: 50_000 output: + # Per RCW 82.08.0206(3)(f), minimum credit is $50 wa_working_families_tax_credit: 50 -- name: Mid-phaseout gives correctly reduced credit. +- name: Case 5, mid-phaseout gives correctly reduced credit. period: 2024 absolute_error_margin: 0.01 input: @@ -52,7 +56,7 @@ output: wa_working_families_tax_credit: 345 -- name: Joint filer with 1 child and moderate income receives credit. +- name: Case 6, joint filer with 1 child and moderate income receives credit. period: 2024 absolute_error_margin: 50 input: @@ -81,3 +85,68 @@ state_code: WA output: wa_working_families_tax_credit: 640 + +# ESSB 6346 Sec. 901 - WFTC Age Expansion tests (effective 2029) + +- name: Case 7, age 18+ without EITC gets WFTC under 2029 age expansion. + period: 2029 + absolute_error_margin: 1 + input: + state_code: WA + age_head: 20 + eitc: 0 + filer_adjusted_earnings: 10_000 + eitc_child_count: 0 + output: + # Eligible via age expansion: age 18+, has earned income + # Amount is inflation-adjusted from $300 (2022) to ~$367 (2029) + wa_working_families_tax_credit: 367 + +- name: Case 8, age 17 without EITC gets no WFTC in 2029. + period: 2029 + input: + state_code: WA + age_head: 17 + eitc: 0 + filer_adjusted_earnings: 10_000 + eitc_child_count: 0 + output: + # Not EITC eligible and under age 18 minimum + wa_working_families_tax_credit: 0 + +- name: Case 9, age 18+ without earned income gets no WFTC in 2029. + period: 2029 + input: + state_code: WA + age_head: 25 + eitc: 0 + filer_adjusted_earnings: 0 + eitc_child_count: 0 + output: + # Age expansion requires earned income + wa_working_families_tax_credit: 0 + +- name: Case 10, WFTC age expansion not in effect before 2029. + period: 2028 + input: + state_code: WA + age_head: 20 + eitc: 0 + filer_adjusted_earnings: 10_000 + eitc_child_count: 0 + output: + # Age expansion starts 2029, no EITC eligibility + wa_working_families_tax_credit: 0 + +- name: Case 11, traditional EITC-eligible filer still works in 2029. + period: 2029 + absolute_error_margin: 1 + input: + state_code: WA + eitc: 1 + filer_adjusted_earnings: 0 + eitc_child_count: 0 + output: + # Standard EITC pathway still works + # Amount is inflation-adjusted from $300 (2022) to ~$367 (2029) + wa_working_families_tax_credit: 367 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.yaml b/policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.yaml new file mode 100644 index 00000000000..d835eaa33ad --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.yaml @@ -0,0 +1,163 @@ +# Washington Millionaires Tax tests +# ESSB 6346 imposes a 9.9% tax on Washington taxable income above $1,000,000 +# Effective January 1, 2028 + +- name: Case 1, single filer with $2M income. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 2_000_000 + output: + # Taxable income = $2M - $1M standard deduction = $1M + # Tax = $1M * 9.9% = $99,000 + wa_millionaires_tax: 99_000 + +- name: Case 2, single filer with $1.5M income. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 1_500_000 + output: + # Taxable income = $1.5M - $1M standard deduction = $500K + # Tax = $500K * 9.9% = $49,500 + wa_millionaires_tax: 49_500 + +- name: Case 3, single filer below $1M threshold. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 900_000 + output: + # Income below $1M standard deduction, no tax owed + wa_millionaires_tax: 0 + +- name: Case 4, single filer exactly at $1M threshold. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 1_000_000 + output: + # Taxable income = $1M - $1M = $0 + wa_millionaires_tax: 0 + +- name: Case 5, single filer just above $1M threshold. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 1_001_000 + output: + # Taxable income = $1,001,000 - $1M = $1,000 + # Tax = $1,000 * 9.9% = $99 + wa_millionaires_tax: 99 + +- name: Case 6, non-WA resident not subject to tax. + period: 2028 + absolute_error_margin: 1 + input: + state_code: CA + adjusted_gross_income: 2_000_000 + output: + wa_millionaires_tax: 0 + +- name: Case 7, charitable deduction reduces taxable income. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 2_000_000 + charitable_cash_donations: 50_000 + output: + # Taxable = $2M - $1M standard - $50K charitable = $950K + # Tax = $950K * 9.9% = $94,050 + wa_millionaires_tax: 94_050 + +- name: Case 8, charitable deduction capped at $100K. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 2_500_000 + charitable_cash_donations: 200_000 + output: + # Charitable deduction capped at $100K + # Taxable = $2.5M - $1M standard - $100K charitable = $1.4M + # Tax = $1.4M * 9.9% = $138,600 + wa_millionaires_tax: 138_600 + +- name: Case 9, joint filers share $1M standard deduction. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + filing_status: JOINT + adjusted_gross_income: 2_000_000 + output: + # Married couples share the $1M deduction (not doubled) + # Taxable = $2M - $1M = $1M + # Tax = $1M * 9.9% = $99,000 + wa_millionaires_tax: 99_000 + +- name: Case 10, no tax before 2028. + period: 2027 + input: + state_code: WA + adjusted_gross_income: 2_000_000 + output: + wa_millionaires_tax: 0 + +- name: Case 11, non-cash charitable donations reduce taxable income. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 2_000_000 + charitable_non_cash_donations: 75_000 + output: + # Taxable = $2M - $1M standard - $75K charitable = $925K + # Tax = $925K * 9.9% = $91,575 + wa_millionaires_tax: 91_575 + +- name: Case 12, combined cash and non-cash donations capped at $100K. + period: 2028 + absolute_error_margin: 1 + input: + state_code: WA + adjusted_gross_income: 2_500_000 + charitable_cash_donations: 80_000 + charitable_non_cash_donations: 60_000 + output: + # Charitable = $80K + $60K = $140K, capped at $100K + # Taxable = $2.5M - $1M standard - $100K charitable = $1.4M + # Tax = $1.4M * 9.9% = $138,600 + wa_millionaires_tax: 138_600 + +- name: Case 13, zero income. + period: 2028 + input: + state_code: WA + adjusted_gross_income: 0 + output: + wa_millionaires_tax: 0 + +- name: Case 14, negative AGI from self-employment losses. + period: 2028 + input: + state_code: WA + adjusted_gross_income: -500_000 + output: + wa_millionaires_tax: 0 + +- name: Case 15, charitable deduction zeroes out taxable income. + period: 2028 + input: + state_code: WA + adjusted_gross_income: 1_050_000 + charitable_cash_donations: 100_000 + output: + # Taxable = $1.05M - $1M standard - $100K charitable = -$50K = $0 + wa_millionaires_tax: 0 diff --git a/policyengine_us/tests/policy/contrib/states/wa/sb6346/sb6346.yaml b/policyengine_us/tests/policy/contrib/states/wa/sb6346/sb6346.yaml deleted file mode 100644 index 7e99de87a02..00000000000 --- a/policyengine_us/tests/policy/contrib/states/wa/sb6346/sb6346.yaml +++ /dev/null @@ -1,638 +0,0 @@ -# WA SSB 6346 Income Tax Reform Tests -# Tests the 9.9% income tax on Washington taxable income: -# tax = max(0, AGI - charitable_deduction - standard_deduction) * 0.099 -# Standard deduction: $1,000,000 (same for single and married) -# Charitable deduction cap: $100,000 individual, $100,000 joint - -- name: Case 1, single high earner with charitable below cap. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 2_000_000 - charitable_cash_donations: 50_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # AGI = $2,000,000 - wa_income_tax_base_income: 2_000_000 - # Charitable: $50,000 < $100,000 cap -> full $50,000 - wa_income_tax_charitable_deduction: 50_000 - # Standard deduction: $1,000,000 - wa_income_tax_standard_deduction: 1_000_000 - # Taxable: $2,000,000 - $50,000 - $1,000,000 = $950,000 - wa_income_tax_taxable_income: 950_000 - # Tax: $950,000 * 0.099 = $94,050 - wa_income_tax: 94_050 - -- name: Case 2, single filer below threshold. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 500_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # AGI = $500,000 - # Taxable: max(0, $500,000 - $0 - $1,000,000) = $0 - wa_income_tax_taxable_income: 0 - # Tax: $0 - wa_income_tax: 0 - -- name: Case 3, married joint high earners with charitable under joint cap. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 45 - is_tax_unit_head: true - employment_income: 1_500_000 - charitable_cash_donations: 40_000 - person2: - age: 43 - is_tax_unit_spouse: true - employment_income: 1_500_000 - charitable_cash_donations: 40_000 - tax_units: - tax_unit: - members: [person1, person2] - filing_status: JOINT - households: - household: - members: [person1, person2] - state_code: WA - output: - # AGI = $1,500,000 + $1,500,000 = $3,000,000 - wa_income_tax_base_income: 3_000_000 - # Charitable: $40,000 + $40,000 = $80,000 < $100,000 joint cap - wa_income_tax_charitable_deduction: 80_000 - # Standard deduction: $1,000,000 - wa_income_tax_standard_deduction: 1_000_000 - # Taxable: $3,000,000 - $80,000 - $1,000,000 = $1,920,000 - wa_income_tax_taxable_income: 1_920_000 - # Tax: $1,920,000 * 0.099 = $190,080 - wa_income_tax: 190_080 - -- name: Case 4, married joint below threshold. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 45 - is_tax_unit_head: true - employment_income: 400_000 - person2: - age: 43 - is_tax_unit_spouse: true - employment_income: 400_000 - tax_units: - tax_unit: - members: [person1, person2] - filing_status: JOINT - households: - household: - members: [person1, person2] - state_code: WA - output: - # AGI = $800,000 < $1,000,000 standard deduction - # Taxable: max(0, $800,000 - $0 - $1,000,000) = $0 - wa_income_tax: 0 - -- name: Case 5, single filer just above threshold with modest charitable. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 1_050_000 - charitable_cash_donations: 20_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # AGI = $1,050,000 - # Charitable: $20,000 < $100,000 cap -> full $20,000 - wa_income_tax_charitable_deduction: 20_000 - # Taxable: $1,050,000 - $20,000 - $1,000,000 = $30,000 - wa_income_tax_taxable_income: 30_000 - # Tax: $30,000 * 0.099 = $2,970 - wa_income_tax: 2_970 - -- name: Case 6, exactly at standard deduction threshold. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 1_000_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # AGI = $1,000,000 - # Taxable: max(0, $1,000,000 - $0 - $1,000,000) = $0 - wa_income_tax_taxable_income: 0 - wa_income_tax: 0 - -- name: Case 7, non-WA resident gets zero tax. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 5_000_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: CA - output: - # defined_for = StateCode.WA, so CA resident gets $0 - wa_income_tax: 0 - -- name: Case 8, single filer with charitable exceeding individual cap. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 2_000_000 - charitable_cash_donations: 200_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # AGI = $2,000,000 - wa_income_tax_base_income: 2_000_000 - # Charitable: $200,000 > $100,000 individual cap -> capped at $100,000 - wa_income_tax_charitable_deduction: 100_000 - # Standard deduction: $1,000,000 - wa_income_tax_standard_deduction: 1_000_000 - # Taxable: $2,000,000 - $100,000 - $1,000,000 = $900,000 - wa_income_tax_taxable_income: 900_000 - # Tax: $900,000 * 0.099 = $89,100 - wa_income_tax: 89_100 - -- name: Case 9, WFTC age expansion - single age 22, no children, $10,000 earnings. - period: 2029 - absolute_error_margin: 10 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 22 - employment_income: 10_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # Age 22 < 25 so no federal EITC, but SSB 6346 expands WFTC to age 18+. - # With $10,000 earned income and 0 children, should receive the maximum WFTC for childless filers. - wa_working_families_tax_credit: 367 - -- name: Case 10, WFTC age expansion - single age 22, no children, $0 earnings. - period: 2029 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 22 - employment_income: 0 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # No earned income -> not eligible for WFTC even with age expansion. - wa_working_families_tax_credit: 0 - -- name: Case 11, WFTC existing path - single age 30, no children, $15,000 earnings. - period: 2029 - absolute_error_margin: 10 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 30 - employment_income: 15_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # Age 30 qualifies for federal EITC (age 25-64), earned income > 0. - # Should receive WFTC via the existing EITC-eligible path. - wa_working_families_tax_credit: 367 - -- name: Case 12, married joint filer with charitable exceeding joint cap. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 45 - is_tax_unit_head: true - employment_income: 1_500_000 - charitable_cash_donations: 60_000 - person2: - age: 43 - is_tax_unit_spouse: true - employment_income: 1_500_000 - charitable_cash_donations: 60_000 - tax_units: - tax_unit: - members: [person1, person2] - filing_status: JOINT - households: - household: - members: [person1, person2] - state_code: WA - output: - # Charitable: $60,000 + $60,000 = $120,000 > $100,000 joint cap. - wa_income_tax_charitable_deduction: 100_000 - # Taxable: $3,000,000 - $100,000 - $1,000,000 = $1,900,000 - wa_income_tax_taxable_income: 1_900_000 - # Tax: $1,900,000 * 0.099 = $188,100 - wa_income_tax: 188_100 - -- name: Case 13, WFTC age expansion - single age 17, no children, $10,000 earnings. - period: 2029 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 17 - employment_income: 10_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # Age 17 is below the SSB 6346 minimum age threshold. - wa_working_families_tax_credit: 0 - -- name: Case 14, WFTC age expansion - single age 18, no children, $10,000 earnings. - period: 2029 - absolute_error_margin: 10 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 18 - employment_income: 10_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # Age 18 qualifies for the SSB 6346 WFTC expansion. - wa_working_families_tax_credit: 367 - -- name: Case 15, reform toggle off leaves WA income tax unchanged. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: false - people: - person1: - age: 40 - employment_income: 2_000_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - wa_income_tax: 0 - -- name: Case 16, WFTC spouse age expansion - head under 18, spouse 22, joint filers. - period: 2029 - absolute_error_margin: 10 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 16 - is_tax_unit_head: true - employment_income: 5_000 - person2: - age: 22 - is_tax_unit_spouse: true - employment_income: 5_000 - tax_units: - tax_unit: - members: [person1, person2] - filing_status: JOINT - households: - household: - members: [person1, person2] - state_code: WA - output: - # Head age 16 < 18 and both < 25 so no federal EITC. - # SSB 6346 expansion: age_spouse (22) >= min_age (18) -> eligible. - # Combined earned income = $10,000, 0 children -> childless maximum WFTC. - wa_working_families_tax_credit: 367 - -- name: Case 17, non-cash charitable donations capped at individual limit. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 1_500_000 - charitable_non_cash_donations: 150_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # AGI = $1,500,000 - wa_income_tax_base_income: 1_500_000 - # Non-cash charitable: $150,000 > $100,000 individual cap -> capped at $100,000 - wa_income_tax_charitable_deduction: 100_000 - # Standard deduction: $1,000,000 - wa_income_tax_standard_deduction: 1_000_000 - # Taxable: $1,500,000 - $100,000 - $1,000,000 = $400,000 - wa_income_tax_taxable_income: 400_000 - # Tax: $400,000 * 0.099 = $39,600 - wa_income_tax: 39_600 - -- name: Case 18, capital gains combined with SSB 6346 income tax. - period: 2028 - absolute_error_margin: 0.01 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 2_000_000 - long_term_capital_gains: 1_500_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # AGI includes employment + LTCG = $3,500,000 - wa_income_tax_base_income: 3_500_000 - # SSB 6346 taxable: $3,500,000 - $0 charitable - $1,000,000 std = $2,500,000 - wa_income_tax_taxable_income: 2_500_000 - # SSB 6346 income tax: $2,500,000 * 0.099 = $247,500 - # WA capital gains tax on the same return is $89,998 in 2028 under current parameters. - wa_capital_gains_tax: 89_998 - # before_credits = $247,500 + $89,998 = $337,498 - wa_income_tax_before_refundable_credits: 337_498 - # WFTC = $0 (income far above EITC limit) - # wa_income_tax = before_credits - 0 = before_credits - wa_income_tax: 337_498 - -- name: Case 19, negative AGI floors taxable income and tax at zero. - period: 2029 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - self_employment_income: -500_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # AGI is negative from self-employment losses - # Taxable: max(0, negative_AGI - deductions) = 0 - wa_income_tax_taxable_income: 0 - # Tax: 0 (no tax on negative/zero income) - wa_income_tax: 0 - -- name: Case 20, WFTC offsets WA income tax when refundable credits are smaller than tax due. - period: 2029 - absolute_error_margin: 10 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 22 - employment_income: 10_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - wa_capital_gains_tax: 500 - households: - household: - members: [person1] - state_code: WA - output: - # Base income is below the $1M standard deduction, so SSB 6346 tax is $0. - wa_income_tax_taxable_income: 0 - # A direct capital gains tax input creates positive WA tax before refundable credits. - wa_income_tax_before_refundable_credits: 500 - # Age 22 + earned income triggers the expanded WFTC path. - wa_working_families_tax_credit: 367 - # Final WA income tax remains positive because tax due exceeds the refundable credit. - wa_income_tax: 133.3 - -- name: Case 21, WFTC age expansion does not apply in 2028. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 22 - employment_income: 10_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # The income tax reform is active in 2028, but the WFTC age expansion is not. - wa_working_families_tax_credit: 0 - -- name: Case 22, WFTC can exceed WA tax owed and produce a negative net tax. - period: 2029 - absolute_error_margin: 10 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 22 - employment_income: 10_000 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - # No SSB 6346 income tax is due below the $1M standard deduction. - wa_income_tax_before_refundable_credits: 0 - # The expanded WFTC remains refundable when it exceeds tax owed. - wa_working_families_tax_credit: 367 - wa_income_tax: -367 - -- name: Case 23, head of household uses the individual charitable deduction cap. - period: 2028 - absolute_error_margin: 1 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 2_000_000 - charitable_cash_donations: 150_000 - tax_units: - tax_unit: - members: [person1] - filing_status: HEAD_OF_HOUSEHOLD - households: - household: - members: [person1] - state_code: WA - output: - wa_income_tax_charitable_deduction: 100_000 - wa_income_tax_taxable_income: 900_000 - wa_income_tax: 89_100 - -- name: Case 24, one dollar above the standard deduction threshold. - period: 2028 - absolute_error_margin: 0.01 - reforms: policyengine_us.reforms.states.wa.sb6346.sb6346.wa_sb6346 - input: - gov.contrib.states.wa.sb6346.in_effect: true - people: - person1: - age: 40 - employment_income: 1_000_001 - tax_units: - tax_unit: - members: [person1] - filing_status: SINGLE - households: - household: - members: [person1] - state_code: WA - output: - wa_income_tax_taxable_income: 1 - wa_income_tax_before_refundable_credits: 0.099 - wa_income_tax: 0.099 diff --git a/policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py b/policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py index 2d75d6bf2c4..4a4a40d95e6 100644 --- a/policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py +++ b/policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py @@ -7,13 +7,24 @@ class wa_working_families_tax_credit(Variable): label = "Washington Working Families Tax Credit" unit = USD definition_period = YEAR - reference = "https://app.leg.wa.gov/RCW/default.aspx?cite=82.08.0206" + reference = ( + "https://app.leg.wa.gov/RCW/default.aspx?cite=82.08.0206", + "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=61", + ) defined_for = StateCode.WA def formula(tax_unit, period, parameters): - # Filers must claim EITC and be in Washington to be eligible. - # TODO: Include ITIN children. - eligible = tax_unit("eitc", period) > 0 + # Baseline eligibility: filers who claim EITC + eitc = tax_unit("eitc", period) + eitc_eligible = eitc > 0 + + # ESSB 6346 Sec. 901: age expansion eligibility (effective 2029) + age_expansion_eligible = tax_unit( + "wa_working_families_tax_credit_age_expansion_eligible", period + ) + + eligible = eitc_eligible | age_expansion_eligible + # Parameters are based on EITC-eligible children. p = parameters( period diff --git a/policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit_age_expansion_eligible.py b/policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit_age_expansion_eligible.py new file mode 100644 index 00000000000..3b64958fdd5 --- /dev/null +++ b/policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit_age_expansion_eligible.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class wa_working_families_tax_credit_age_expansion_eligible(Variable): + value_type = bool + entity = TaxUnit + label = "Eligible for Washington Working Families Tax Credit via age expansion" + definition_period = YEAR + reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=61" + defined_for = StateCode.WA + + def formula(tax_unit, period, parameters): + # ESSB 6346 Sec. 901(2)(a)(ii)(D): individuals who do not meet the + # EITC age requirement but are at least age 18 (effective 2029). + p = parameters( + period + ).gov.states.wa.tax.income.credits.working_families_tax_credit.age_expansion + + expansion_in_effect = p.in_effect + age_head = tax_unit("age_head", period) + age_spouse = tax_unit("age_spouse", period) + filer_meets_min_age = (age_head >= p.min_age) | (age_spouse >= p.min_age) + earned_income = tax_unit("filer_adjusted_earnings", period) + has_earned_income = earned_income > 0 + + return expansion_in_effect & filer_meets_min_age & has_earned_income diff --git a/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.py b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.py new file mode 100644 index 00000000000..239e71eeb91 --- /dev/null +++ b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class wa_millionaires_tax(Variable): + value_type = float + entity = TaxUnit + label = "Washington millionaires tax" + unit = USD + definition_period = YEAR + reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=8" + defined_for = "wa_millionaires_tax_applies" + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.wa.tax.income.millionaires_tax + taxable_income = tax_unit("wa_millionaires_tax_taxable_income", period) + return taxable_income * p.rate diff --git a/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_applies.py b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_applies.py new file mode 100644 index 00000000000..b4876a44716 --- /dev/null +++ b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_applies.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class wa_millionaires_tax_applies(Variable): + value_type = bool + entity = TaxUnit + label = "Washington millionaires tax applies" + definition_period = YEAR + reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=8" + defined_for = StateCode.WA + + def formula(tax_unit, period, parameters): + return parameters(period).gov.states.wa.tax.income.millionaires_tax.in_effect diff --git a/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_base_income.py b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_base_income.py new file mode 100644 index 00000000000..86380eae623 --- /dev/null +++ b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_base_income.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class wa_millionaires_tax_base_income(Variable): + value_type = float + entity = TaxUnit + label = "Washington millionaires tax base income" + unit = USD + definition_period = YEAR + reference = ( + "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=7", + "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=11", + ) + defined_for = "wa_millionaires_tax_applies" + adds = ["adjusted_gross_income"] diff --git a/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_charitable_deduction.py b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_charitable_deduction.py new file mode 100644 index 00000000000..4987d82daf0 --- /dev/null +++ b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_charitable_deduction.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class wa_millionaires_tax_charitable_deduction(Variable): + value_type = float + entity = TaxUnit + label = "Washington millionaires tax charitable deduction" + unit = USD + definition_period = YEAR + reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=14" + defined_for = "wa_millionaires_tax_applies" + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.wa.tax.income.millionaires_tax + charitable = add( + tax_unit, + period, + ["charitable_cash_donations", "charitable_non_cash_donations"], + ) + return min_(charitable, p.deductions.charitable.cap) diff --git a/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_standard_deduction.py b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_standard_deduction.py new file mode 100644 index 00000000000..91ddcf04819 --- /dev/null +++ b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_standard_deduction.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class wa_millionaires_tax_standard_deduction(Variable): + value_type = float + entity = TaxUnit + label = "Washington millionaires tax standard deduction" + unit = USD + definition_period = YEAR + reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=13" + defined_for = "wa_millionaires_tax_applies" + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.wa.tax.income.millionaires_tax + return p.deductions.standard diff --git a/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_taxable_income.py b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_taxable_income.py new file mode 100644 index 00000000000..0af55e6618f --- /dev/null +++ b/policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_taxable_income.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class wa_millionaires_tax_taxable_income(Variable): + value_type = float + entity = TaxUnit + label = "Washington millionaires tax taxable income" + unit = USD + definition_period = YEAR + reference = ( + "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=7", + "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=14", + "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=15", + ) + defined_for = "wa_millionaires_tax_applies" + + def formula(tax_unit, period, parameters): + base_income = tax_unit("wa_millionaires_tax_base_income", period) + charitable_deduction = tax_unit( + "wa_millionaires_tax_charitable_deduction", period + ) + standard_deduction = tax_unit("wa_millionaires_tax_standard_deduction", period) + return max_(base_income - charitable_deduction - standard_deduction, 0) diff --git a/policyengine_us/variables/gov/states/wa/tax/income/wa_income_tax_before_refundable_credits.py b/policyengine_us/variables/gov/states/wa/tax/income/wa_income_tax_before_refundable_credits.py index dc5ddc2247c..6428f1aa831 100644 --- a/policyengine_us/variables/gov/states/wa/tax/income/wa_income_tax_before_refundable_credits.py +++ b/policyengine_us/variables/gov/states/wa/tax/income/wa_income_tax_before_refundable_credits.py @@ -8,4 +8,4 @@ class wa_income_tax_before_refundable_credits(Variable): unit = USD definition_period = YEAR defined_for = StateCode.WA - adds = ["wa_capital_gains_tax"] + adds = ["wa_capital_gains_tax", "wa_millionaires_tax"]