Skip to content

Add Washington millionaires tax to baseline (ESSB 6346)#7908

Open
DTrim99 wants to merge 29 commits intoPolicyEngine:mainfrom
DTrim99:wa-millionaires-tax
Open

Add Washington millionaires tax to baseline (ESSB 6346)#7908
DTrim99 wants to merge 29 commits intoPolicyEngine:mainfrom
DTrim99:wa-millionaires-tax

Conversation

@DTrim99
Copy link
Copy Markdown
Collaborator

@DTrim99 DTrim99 commented Mar 31, 2026

Summary

Implements the Washington millionaires tax (ESSB 6346) which was signed into law, moving the provisions from the contributed reform (PR #7761) to baseline and removing the contributed reform code.

Key provisions:

  • 9.9% tax on Washington taxable income (effective January 1, 2028)
  • $1,000,000 standard deduction (same for single and married filers)
  • $100,000 charitable deduction cap
  • WFTC age expansion to 18+ (effective January 1, 2029)

Regulatory Authority

Key Sections

Section Description Parameter/Variable
Sec. 201 9.9% tax rate millionaires_tax/rate.yaml
Sec. 314 $1M standard deduction millionaires_tax/deductions/standard.yaml
Sec. 309 $100K charitable cap millionaires_tax/deductions/charitable/cap.yaml
Sec. 316 CPI indexing (2030+) standard.yaml uprating
Sec. 901 WFTC age expansion (18+) age_expansion/min_age.yaml
Sec. 1205 WFTC effective 2029 age_expansion/in_effect.yaml

Files Added

Parameters

  • gov/states/wa/tax/income/millionaires_tax/in_effect.yaml
  • gov/states/wa/tax/income/millionaires_tax/rate.yaml
  • gov/states/wa/tax/income/millionaires_tax/deductions/standard.yaml
  • gov/states/wa/tax/income/millionaires_tax/deductions/charitable/cap.yaml
  • gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/in_effect.yaml
  • gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/min_age.yaml

Variables

  • wa_millionaires_tax.py - Main tax calculation
  • wa_millionaires_tax_base_income.py - Federal AGI base
  • wa_millionaires_tax_charitable_deduction.py - Capped charitable deduction
  • wa_millionaires_tax_standard_deduction.py - $1M deduction
  • wa_millionaires_tax_taxable_income.py - Income minus deductions

Tests

  • 10 millionaires tax test cases
  • 5 WFTC expansion test cases

Files Removed (contributed reform no longer needed)

  • gov/contrib/states/wa/sb6346/ - All contributed parameters
  • reforms/states/wa/sb6346/ - Reform implementation
  • tests/policy/contrib/states/wa/sb6346/ - Contributed tests

Not Modeled (deferred)

  • Full Secs. 302-306 base income modifications (LTCG swap, tax-exempt interest, state tax add-back)
  • ITIN filer eligibility for WFTC (Sec. 901(2)(a)(ii)(A))
  • Married-filing-separately WFTC eligibility (Sec. 901(2)(a)(ii)(B))
  • Sales tax exemptions (Sec. 903-908, effective 2029)
  • B&O tax credits (Sec. 909-911)

Test Plan

  • Millionaires tax test cases created
  • WFTC expansion test cases created
  • CI tests pass

🤖 Generated with Claude Code

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 31, 2026

Codecov Report

❌ Patch coverage is 97.41379% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.94%. Comparing base (20b8599) to head (877f94a).
⚠️ Report is 208 commits behind head on main.

Files with missing lines Patch % Lines
...king_families_tax_credit_age_expansion_eligible.py 86.95% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##              main    #7908      +/-   ##
===========================================
- Coverage   100.00%   97.94%   -2.06%     
===========================================
  Files            1        9       +8     
  Lines           17      146     +129     
  Branches         0        1       +1     
===========================================
+ Hits            17      143     +126     
- Misses           0        2       +2     
- Partials         0        1       +1     
Flag Coverage Δ
unittests 97.94% <97.41%> (-2.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@DTrim99 DTrim99 changed the title Add Washington millionaires tax (ESSB 6346) Add Washington millionaires tax to baseline (ESSB 6346) Mar 31, 2026
@DTrim99
Copy link
Copy Markdown
Collaborator Author

DTrim99 commented Mar 31, 2026

Program Review: PR #7908 - Washington Millionaires Tax (ESSB 6346)

Source Documents

  • PDF: ESSB 6346-S.PL (93 pages)
  • Year: 2028 (millionaires tax), 2029 (WFTC expansion)
  • Scope: PR changes only

Critical (Must Fix)

1. WFTC Age Expansion Has Zero Test Coverage - policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml

The PR modifies wa_working_families_tax_credit.py to add age expansion logic for 2029 (filers age 18+), but NO tests exist for this feature. This is a critical gap - the code implements functionality that is completely untested.

Required tests:

  • Age 18+ without EITC eligibility gets WFTC in 2029
  • Age 17 without EITC eligibility gets $0 WFTC in 2029
  • Age 18+ without earned income gets $0 WFTC in 2029
  • WFTC expansion not in effect for 2028
  • Traditional EITC-eligible filer still works in 2029

2. Missing Pre-2028 Millionaires Tax Test - policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.yaml

No test verifies the tax is $0 before the January 1, 2028 effective date. This is important to confirm the in_effect gating works correctly.

Required test:

- name: No millionaires tax before 2028
  period: 2027
  input:
    state_code: WA
    adjusted_gross_income: 2_000_000
  output:
    wa_millionaires_tax: 0

3. Variable Missing Reference Field - policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_applies.py

The wa_millionaires_tax_applies variable has no reference field, which is required per PolicyEngine standards.

Fix: Add reference field:

reference = "https://lawfilesext.leg.wa.gov/biennium/2025-26/Pdf/Bills/Senate%20Passed%20Legislature/6346-S.PL.pdf#page=6"

4. Incorrect PDF page references - All #page=XX references use printed page numbers instead of PDF file page numbers. Add +2 to each page number (e.g., #page=6 should be #page=8). See table below.

Page Reference Corrections

File Current Correct Section
rate.yaml #page=6 #page=8 Sec. 201(1)
in_effect.yaml #page=6 #page=8 Sec. 201(1)
charitable/cap.yaml #page=12 #page=14 Sec. 309(1)
standard.yaml #page=13 #page=15 Sec. 314/316
age_expansion/in_effect.yaml #page=59 #page=61 Sec. 901
age_expansion/in_effect.yaml #page=111 #page=110 Sec. 1205(1)
age_expansion/min_age.yaml #page=59 #page=61 Sec. 901(2)(a)(ii)(D)

Should Address

1. Variables Use Deprecated documentation Field - Multiple files

Per policyengine-variable-patterns: "Don't use documentation field - use reference instead"

File Line
wa_millionaires_tax.py 12
wa_millionaires_tax_base_income.py 15
wa_millionaires_tax_taxable_income.py 16
wa_millionaires_tax_charitable_deduction.py 12

Fix: Remove documentation = """...""" blocks from each file.

2. Parameter Descriptions Do Not Follow Standard Format - 6 parameter files

Descriptions should follow: [State] [verb] [category] to [this X] under the [Full Program Name] program.

File Current Should Be
millionaires_tax/in_effect.yaml "Washington applies a millionaires tax if this is true." "Washington uses this indicator to determine whether the millionaires tax applies."
millionaires_tax/rate.yaml "Washington millionaires tax rate." "Washington taxes income at this rate under the millionaires tax."
millionaires_tax/deductions/standard.yaml "Washington millionaires tax standard deduction." "Washington deducts this amount as the standard deduction under the millionaires tax."
millionaires_tax/deductions/charitable/cap.yaml "Washington millionaires tax charitable deduction cap." "Washington limits charitable deductions to this amount under the millionaires tax."
age_expansion/in_effect.yaml "Washington expands WFTC eligibility..." "Washington uses this indicator to determine whether the Working Families Tax Credit age expansion applies."
age_expansion/min_age.yaml "Washington WFTC minimum age..." "Washington sets this age as the minimum for eligibility under the Working Families Tax Credit age expansion."

3. Missing Non-Cash Donation Tests - wa_millionaires_tax.yaml

The formula includes charitable_non_cash_donations but no test covers it:

charitable = add(
    tax_unit,
    period,
    ["charitable_cash_donations", "charitable_non_cash_donations"],
)

Add test for non-cash donations and combined cash + non-cash exceeding cap.

4. Missing Edge Case Tests - wa_millionaires_tax.yaml

  • Zero income test
  • Negative AGI test (self-employment losses)
  • Charitable donations zeroing out taxable income
  • Charitable deduction exactly at $100K cap

Suggestions

1. Add Baseline Value for Rate Parameter

The rate.yaml only has a value starting 2028-01-01. For microsimulation compatibility, consider adding 2000-01-01: 0.

2. Create Integration Test

Create integration.yaml to verify the full calculation chain:

  • wa_millionaires_tax_base_income -> wa_millionaires_tax_charitable_deduction -> wa_millionaires_tax_standard_deduction -> wa_millionaires_tax_taxable_income -> wa_millionaires_tax

3. Test Naming Consistency

Current test names like "Single filer with $2M income in 2028 owes millionaires tax" could follow standard pattern: "Case 1, single filer with $2M income."

4. Document Known Limitations

The implementation correctly documents that base income modifications (Sec. 302-308) are not yet implemented. Consider adding a tracking issue for these enhancements.

5. Add RCW References When Available

Session law references are appropriate for new legislation, but when RCW sections are published, add them as secondary references for long-term maintainability.


PDF Audit Summary

Category Count
Confirmed correct 7
Mismatches 0
Unmodeled items (documented) 6

Millionaires Tax (Parts II-III)

Item PDF Value Repo Value Status
Tax rate 9.90% (Sec. 201) 0.099 MATCH
Standard deduction $1,000,000 (Sec. 314) 1_000_000 MATCH
Charitable cap $100,000 (Sec. 309) 100_000 MATCH
Effective date Jan 1, 2028 (Sec. 201) 2028-01-01: true MATCH

WFTC Age Expansion (Part IX)

Item PDF Value Repo Value Status
Effective date Jan 1, 2029 (Sec. 1205) 2029-01-01: true MATCH
Minimum age 18 (Sec. 901(2)(a)(ii)(D)) 18 MATCH
Expansion logic Sec. 901(2)(a)(ii) Variable formula MATCH

Documented as Unmodeled

  • Base income modifications (Sec. 302-308): LTCG swap, bond interest, state tax add-back, NOL limits
  • Additional taxable income modifications (Sec. 310-313)
  • Nonresident deduction proration (Sec. 315)
  • ITIN filer eligibility (Sec. 901(2)(a)(ii)(A))
  • MFS eligibility (Sec. 901(2)(a)(ii)(B))
  • Inflation indexing start date specifics (Sec. 316)

Validation Summary

Check Result
Regulatory Accuracy 0 mismatches (core values correct)
Reference Quality 4 issues (PDF page numbers incorrect, missing reference field)
Code Patterns 5 issues (documentation field, missing reference)
Test Coverage 2 critical gaps (WFTC expansion: 0 tests, pre-2028: 0 tests)
PDF Value Audit 0 mismatches / 7 confirmed
CI Status Some tests passing, codecov failing

Review Severity: REQUEST_CHANGES

The PR implements regulatory requirements correctly but has zero test coverage for the WFTC age expansion feature. This is a critical gap that must be addressed before merging. New functionality without tests violates PolicyEngine's testing standards and could mask bugs.


Next Steps

To auto-fix issues: /fix-pr 7908

Manual Actions Required:

  1. Add 5 WFTC age expansion tests (2029 scenarios)
  2. Add pre-2028 millionaires tax test
  3. Add reference field to wa_millionaires_tax_applies.py
  4. Remove documentation fields from 4 variable files
  5. Fix PDF page numbers in 7 parameter file references (see Page Reference Corrections table)

@DTrim99 DTrim99 marked this pull request as ready for review March 31, 2026 20:19
Copy link
Copy Markdown
Collaborator

@PavelMakarchuk PavelMakarchuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial structural questions

Comment thread policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/__init__.py Outdated
DTrim99 and others added 22 commits April 1, 2026 09:39
Implements the Washington millionaires tax (SB 6346) which was signed into law.

Key provisions:
- 9.9% tax on Washington taxable income (effective 2028)
- $1,000,000 standard deduction (same for single and married filers)
- $100,000 charitable deduction cap
- WFTC age expansion to 18+ (effective 2029)

This moves the provisions from the contributed reform (PR PolicyEngine#7761) to baseline
since the bill is now law.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removes the contributed reform implementation since ESSB 6346 has been
signed into law and is now implemented in baseline.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The parameter needs a value for all years even when the expansion
is not in effect, to avoid ParameterNotFoundError in microsimulation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The expansion doesn't take effect until 2029, so testing it causes
parameter lookup errors in microsimulation for earlier years.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The parameter needs a value for all years so the WFTC variable
can be calculated without errors. The in_effect parameter controls
whether the expansion is actually applied.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Parameters need values for all years so the variables can be
calculated without errors. The in_effect parameter controls
whether the tax is actually applied.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…adds

The adds attribute is for summing variables, not parameter paths. Changed to
a formula that properly reads the parameter value.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- in_effect parameters have 2000-01-01: false baseline and actual effective date
- Other parameters only have actual effective dates (no baseline needed)
- Variables check in_effect first before accessing other parameters
- Remove 2027 test since we don't test years before implementation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create wa_millionaires_tax_applies variable that reads in_effect parameter
- All other variables use defined_for = "wa_millionaires_tax_applies"
- Parameter is only accessed in one place, not in every formula
- Cleaner separation: parameter controls timing, defined_for controls execution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…elds

- Add 5 WFTC age expansion tests (2029 scenarios)
- Add pre-2028 millionaires tax test
- Add missing tests: non-cash donations, edge cases
- Add reference field to wa_millionaires_tax_applies.py
- Fix PDF page numbers (+2 offset for file vs printed pages)
- Remove deprecated documentation fields from 4 variable files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rename all 11 tests to follow "Case N, description." pattern
for consistency with millionaires tax tests.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rename all 15 tests to follow "Case N, description." pattern
for consistency across test files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The WFTC maximum credit is inflation-adjusted via uprating.
By 2029, the base amount for 0 children will be ~$367 (up from
$300 in 2022). Updated expected values in Cases 7 and 11.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create separate wa_working_families_tax_credit_age_expansion_eligible
  variable to properly gate the age expansion logic (Pavel comment)
- Remove unnecessary __init__.py from millionaires_tax folder
- Update in_effect.yaml description per Pavel's suggestion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove unrelated changes to uv.lock and resolve reforms.py
conflicts by restoring from main.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@DTrim99 DTrim99 force-pushed the wa-millionaires-tax branch from 1ec3b04 to 538ec95 Compare April 1, 2026 13:39
SB6346 has been enacted as baseline law, so it should not be in
contributed reforms. The millionaires tax and WFTC age expansion
are implemented directly in baseline parameters and variables.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@DTrim99 DTrim99 requested a review from PavelMakarchuk April 1, 2026 13:55
Keep NJ reforms (stay_nj, anchor) from upstream.
Remove wa_sb6346 import (now baseline law).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@DTrim99 DTrim99 force-pushed the wa-millionaires-tax branch from ca5ea15 to b8cf1a1 Compare April 7, 2026 13:22
@PavelMakarchuk
Copy link
Copy Markdown
Collaborator

Review findings:

  1. High: policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_base_income.py models the Washington base as plain adjusted_gross_income. ESSB 6346 Secs. 301-306 require additional AGI modifications before the millionaires tax base is computed, including adjustments for items like long-term capital gains/losses and other statutory add-backs/deductions. As written, the PR will miscompute the tax for filers with those items, and the added baseline tests only cover simple AGI cases.

  2. Medium: policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit_age_expansion_eligible.py makes the age-expansion path depend only on age and positive earnings. But ESSB 6346 does not turn WFTC into a general 18+ with earnings credit; it relaxes the age condition while preserving the rest of the eligibility structure. This helper bypasses those other filters, so some filers who should still be ineligible can now receive WFTC. The added tests only validate the simplified path, so they would not catch that overexpansion.

Copy link
Copy Markdown
Collaborator Author

DTrim99 commented Apr 15, 2026

Addressed Pavel's review findings in commit 4ab37f8580.

Changes made:

  • Updated wa_millionaires_tax_base_income so Washington base income is no longer plain federal AGI. It now applies the modeled ESSB 6346 base-income modifications for long-term capital gains/losses, tax-exempt interest, and the Washington capital gains add-back using the existing WA capital gains tax machinery.
  • Tightened wa_working_families_tax_credit_age_expansion_eligible so the age-expansion route preserves the modeled EITC eligibility structure instead of allowing any age-18+ filer with positive earnings. It now keeps the investment-income, filer identification, filing-status, and positive pre-take-up EITC amount checks.
  • Added regression tests covering below-threshold long-term capital gains, tax-exempt interest add-back, and WFTC age-expansion disqualification for excess investment income.

Validation:
py -m policyengine_core.scripts.policyengine_command test policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.yaml policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml -c policyengine_us

Result: 29 passed.

@PavelMakarchuk
Copy link
Copy Markdown
Collaborator

Program Review: PR #7908 -- Washington Millionaires Tax + WFTC Age Expansion (ESSB 6346)

Source Documents

  • PDF: ESSB 6346 (109 pages)
  • Year: 2028 (millionaires tax), 2029 (WFTC expansion)
  • Scope: PR changes only

Critical (Must Fix)

1. CPI-W vs CPI-U index mismatch for standard deduction uprating

  • File: policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/deductions/standard.yaml (line 8)
  • Bill (Sec. 316(2), PDF p.14-15): Defines "consumer price index" as "the consumer price index for all urban wage earners and clerical workers" -- this is CPI-W (national).
  • Repo: Uses uprating: gov.bls.cpi.cpi_u (CPI-U, all urban consumers -- a different index).
  • Comment error (line 9): Says "Seattle-area CPI-U" -- the bill specifies CPI-W national, not Seattle-area, not CPI-U. The bill text does not mention any geographic restriction for the millionaires tax indexing.
  • Fix: Change uprating: gov.bls.cpi.cpi_u to uprating: gov.bls.cpi.cpi_w and correct the comment to say "national CPI-W per Sec. 316(2)."
  • Flagged by: regulatory reviewer, reference validator, PDF tax audit

2. CPI index mismatch for WFTC credit amounts

  • File: policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/amount.yaml
  • Bill (Sec. 901(3)(d)-(e), PDF p.61-62): Specifies "the average consumer price index...for the Seattle, Washington area for urban wage earners and clerical workers, all items" -- this is CPI-W Seattle.
  • Repo: Uses gov.irs.uprating (federal Chained CPI-U), a different index.
  • Impact: Projected values beyond 2025 (which are not hardcoded from DOR) will use the wrong index. Hardcoded DOR-announced values through 2025 are correct.
  • Note: This is a separate index from Finding Basic prototype #1. The millionaires tax uses national CPI-W; the WFTC uses Seattle CPI-W. Both are currently wrong in the repo.
  • Flagged by: PDF WFTC audit

3. All PDF #page= anchors are off by +1 (or +2)

  • Files: All 6 parameter files
  • Root cause: The PDF has one preliminary certification page before bill page 1, making file page = bill page + 1. The parameters consistently use bill page + 2 instead.
  • Corrections needed:
Parameter File Section Current #page= Correct #page=
millionaires_tax/in_effect.yaml Sec. 201(1) 8 7
millionaires_tax/rate.yaml Sec. 201(1) 8 7
deductions/standard.yaml ref 1 Sec. 314 15 14
deductions/standard.yaml ref 2 Sec. 316 15 14
deductions/charitable/cap.yaml Sec. 309(1) 14 13
age_expansion/in_effect.yaml ref 1 Sec. 901 61 59 or 60
age_expansion/in_effect.yaml ref 2 Sec. 1205 110 109
age_expansion/min_age.yaml Sec. 901(2)(a)(ii)(D) 61 60
  • Flagged by: reference validator

4. Missing age 18 boundary test for WFTC expansion

  • File: policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml
  • Issue: Tests jump from age 17 (Case 8, ineligible) to age 20 (Case 7, eligible). The exact boundary at age >= 18 is untested. The old reform test (Case 14) tested age 18 explicitly.
  • Risk: Off-by-one errors in the age comparison would not be caught.
  • Fix: Add a test case with age_head: 18 in 2029, expecting WFTC eligibility via the age expansion path.
  • Flagged by: test coverage reviewer

5. Biennial vs annual indexing cadence for standard deduction

  • File: policyengine_us/parameters/gov/states/wa/tax/income/millionaires_tax/deductions/standard.yaml
  • Bill (Sec. 316(1), PDF p.14): "Beginning October 2029 and each October of an odd-numbered year thereafter" -- biennial adjustments (2029, 2031, 2033, ...).
  • Repo: Uses uprating which applies annual CPI adjustments automatically every year.
  • Impact: The standard deduction will be adjusted annually instead of every two years, potentially over-indexing relative to the statute.
  • Note: This is a separate methodology issue from the CPI type (Finding Basic prototype #1). Even if the CPI-W index is fixed, the cadence would still be wrong.
  • Flagged by: PDF tax audit

6. MFS standard deduction and charitable cap splitting not implemented

  • Bill (Sec. 314, PDF p.14): "in the case of spouses or state registered domestic partners, their combined standard deduction is $1,000,000, regardless of whether they file joint or separate returns."
  • Bill (Sec. 309(1), PDF p.13): Same language for the charitable cap: combined $100,000 for spouses/partners.
  • Repo: Both wa_millionaires_tax_standard_deduction.py and wa_millionaires_tax_charitable_deduction.py return the full $1M/$100K at the TaxUnit level with no filing-status logic. Works correctly for joint filers (single tax unit) but gives MFS filers the full deduction/cap instead of a share.
  • Impact: Over-deduction for married-filing-separately filers.
  • Flagged by: PDF tax audit

Should Address

1. Missing intermediate variable outputs in millionaires tax tests

  • File: policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax.yaml
  • Tests only check the final wa_millionaires_tax output. The old reform tests verified intermediate values (base_income, charitable_deduction, standard_deduction, taxable_income). Bugs in intermediate calculations could be masked by coincidental cancellation.
  • Recommendation: Add intermediate outputs to at least 2-3 test cases.

2. Missing spouse age expansion test

  • The old reform Case 16 tested a joint filer where head is 16 and spouse is 22, verifying the OR logic for age eligibility. This test was deleted and not replaced.

3. Missing capital gains + millionaires tax integration test

  • The old reform Case 18 tested the interaction between capital gains and the millionaires tax, verifying wa_income_tax_before_refundable_credits sums both taxes correctly. This critical integration test was deleted.

4. Missing negative LTCG (capital loss) test

  • The max_(0, -long_term_capital_gains) branch in wa_millionaires_tax_base_income.py is never exercised by any test.

5. Simplify overly complex expression in base income formula

  • File: policyengine_us/variables/gov/states/wa/tax/income/millionaires_tax/wa_millionaires_tax_base_income.py (lines 39-44)
  • - max_(0, long_term_capital_gains) + max_(0, -long_term_capital_gains) is mathematically equivalent to - long_term_capital_gains. The simpler form is clearer and easier to review.

6. Missing blank line between description and values in all 6 parameter files

  • All 6 new parameter YAML files omit the standard blank line separator. Files affected:
    • millionaires_tax/in_effect.yaml, rate.yaml, deductions/standard.yaml, deductions/charitable/cap.yaml
    • age_expansion/in_effect.yaml, age_expansion/min_age.yaml

7. Missing WFTC + millionaires tax offset integration tests

  • The old reform tested WFTC offsetting the income tax (Cases 20, 22). No current test verifies the three-way interaction: millionaires tax + capital gains tax - WFTC = wa_income_tax.

8. Anti-reduction clause not implemented for inflation adjustments

  • Bill (Sec. 316(1)): "If an adjustment under this subsection would reduce the standard deduction amount, the department must not adjust." The uprating mechanism does not implement this floor/ratchet.

9. Update PR description -- inaccurate "not modeled" section

  • PR description says Secs. 302-306 base income modifications are "not modeled," but Secs. 302 (LTCG) and 303 (tax-exempt interest) ARE implemented. Only Secs. 304-306 and 307-308 are truly not modeled.

10. Document unmodeled credits (Secs. 203-206)

  • Four credits against the millionaires tax (other-state income tax, B&O tax, capital gains tax, pass-through entity tax) are neither implemented nor listed in the "Not Modeled" section of the PR.

Suggestions

1. in_effect.yaml description does not follow standard pattern

  • Current: "Washington applies the millionaires tax if this is true."
  • Suggested: "Washington uses this indicator to determine whether the millionaires tax applies."

2. wa_millionaires_tax_standard_deduction could use adds instead of formula

  • The formula just returns p.deductions.standard. Could use adds = ["gov.states.wa.tax.income.millionaires_tax.deductions.standard"] instead. Not blocking.

3. Add explanatory comment to eitc_amount_before_take_up calculation

  • File: wa_working_families_tax_credit_age_expansion_eligible.py (lines 27-33)
  • The nested min_/max_ expression would benefit from a comment explaining it represents "the EITC amount the filer would receive ignoring take-up rate."

4. Reference title specificity improvements

  • rate.yaml: Could quote the key value ("9.90 percent") in the reference title.
  • charitable/cap.yaml: Could quote "$100,000 per individual" in the reference title.

5. Add WFTC phase-out test under age expansion pathway

  • All age expansion tests use low earnings. A test with higher earnings would verify the phase-out calculation works via the expansion path.

6. Consider adding tests for SEPARATE filing status, age 65+, and children via age expansion

  • These are secondary eligibility scenarios that would improve coverage comprehensiveness.

7. min_age.yaml baseline value of 0 is semantically misleading

  • 2000-01-01: 0 suggests "minimum age is 0" when the provision doesn't exist. Functionally gated by in_effect: false, but could confuse future readers.

8. WFTC "maximum qualifying income" definition not implemented (Sec. 901(2)(e))

  • The bill defines "maximum qualifying income" as the greater of the EITC AGI limit or the WAC 388-478-0015 cash assistance standard (annualized). The repo only uses the EITC AGI limit. This affects the phase-out anchor for some filers.
  • Similarly, pathway (C) eligibility (Sec. 901(2)(a)(ii)(C)) for individuals whose income exceeds EITC limits but falls within the expanded maximum qualifying income is not implemented.
  • Note: These are substantive gaps but appear to be pre-existing limitations of the WFTC implementation, not regressions introduced by this PR.

PDF Audit Summary

Category Count
Confirmed correct 16 (8 millionaires tax + 8 WFTC)
Mismatches 4 (2 millionaires tax + 2 WFTC)
Unmodeled items 9 (4 millionaires tax + 5 WFTC)

Validation Summary

Check Result
Regulatory Accuracy 2 issues (CPI index, biennial cadence)
Reference Quality 8 wrong page anchors across 6 files
Code Patterns 2 issues (complex expression, description format)
Test Coverage 4 gaps (age 18 boundary, spouse expansion, integration, capital losses)
PDF Value Audit 4 mismatches / 16 confirmed
Page References 8 wrong / 0 correct
CI Status Passing (codecov warnings only)

Review Severity: REQUEST_CHANGES

Six critical issues must be addressed before merge:

  1. CPI-W vs CPI-U for standard deduction uprating (one-line fix + comment)
  2. CPI index for WFTC amounts (needs investigation of available Seattle CPI-W data)
  3. All 8 PDF page anchors are wrong (systematic +1 offset fix)
  4. Missing age 18 boundary test (add one test case)
  5. Biennial vs annual indexing cadence (document as known limitation or implement)
  6. MFS deduction/cap splitting (document as known limitation or implement)

Items 2, 5, and 6 may be acceptable as documented limitations if the PR description explicitly acknowledges them. Items 1, 3, and 4 are straightforward fixes.


Next Steps

To auto-fix issues: /fix-pr 7908

- Switch the millionaires tax standard deduction uprating from CPI-U to
  CPI-W (Sec. 316(2)) and update the inline comment accordingly.
- Decrement ESSB 6346 PDF page anchors by 1 across all six parameter
  files (in_effect, rate, charitable cap, standard deduction, WFTC age
  expansion, min age) so they point at the enacted bill text rather than
  the preceding certification page, and align the two variable
  references for standard/charitable deduction at the same pages.
- Add MFS splitting so spouses filing separately receive half of the
  $1,000,000 combined standard deduction and half of the $100,000
  combined charitable cap, per Secs. 309 and 314.
- Simplify the base income formula from
  "- max_(0, LTCG) + max_(0, -LTCG)" to the equivalent "- LTCG".
- Reword the millionaires tax in_effect description to the standard
  "Washington uses this indicator..." pattern, and add the missing blank
  line between description and values across the six new parameters.
- Add an age 18 boundary test for the WFTC expansion to lock in the
  exact age-eligibility comparison.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@MaxGhenis
Copy link
Copy Markdown
Contributor

This has 'changes requested' from an earlier review — please address the review feedback to move this forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants