Skip to content

Fix WA WFTC phase-out rate and expansion effective year (#9373) - #9391

Open
DTrim99 wants to merge 4 commits into
PolicyEngine:mainfrom
DTrim99:fix/wa-wftc-phaseout-effective-year
Open

Fix WA WFTC phase-out rate and expansion effective year (#9373)#9391
DTrim99 wants to merge 4 commits into
PolicyEngine:mainfrom
DTrim99:fix/wa-wftc-phaseout-effective-year

Conversation

@DTrim99

@DTrim99 DTrim99 commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes the model bugs verified in #9373 (Ziming's WA WFTC verification). Draft pending CI (this repo can't run the model locally) and coordination on partner contract tests — see below.

Changes

  • A1 — phase-out rate (correctness bug). The reduction rate is maximum amount / phase-out band per WAC 458-20-285(10)(d) — the published per-dollar rates of $0.12 / $0.12 / $0.18 / $0.24 for 0–3 children equal max/band on the 2022 base amounts (600/5000 = 0.12, 900/5000 = 0.18, 1200/5000 = 0.24). The prior code used (maximum − minimum) / band (= 0.11/0.17/0.23), a shallower slope that overpaid inside the phase-out band (up to ~$46/household). The $50 statutory minimum (RCW 82.08.0206(3)(c)) still floors any positive reduced amount.
  • A3 — expansion effective year. ESSB 6346 Sec. 1205(1): the expansion "takes effect January 1, 2028, for applications submitted beginning in calendar year 2029." The model flipped the age expansion, maximum-qualifying-income expansion, and assistance-unit-size cap at 2029-01-01; moved to 2028-01-01 (tax year 2028).
  • A4 — strict ceiling. WAC 458-20-285(10)(e): income "equal to or more than" the maximum qualifying income is ineligible → <= changed to <. (Moot for the credit amount once A1 zeroes it at the ceiling, but corrects the eligibility flag.)

Baseline tests updated for the new rate and effective year (Cases 4/5/6b/16/17, the 2029 need-standard case, and the age-expansion boundary cases moved to 2027 with a new positive 2028 first-in-effect case).

Relationship to #9371 (Anthony's uprating-nesting PR)

Follow-ups (not in this PR)

  • B5(ii) — the uprating index should be the Seattle CPI-W (RCW 82.08.0206), not the federal chained-CPI gov.irs.uprating. Larger change (custom index + averaging convention); tracked separately.
  • B6 — extend the cash-assistance need standard to 2026-07-01 (WSR 26-10-028). Forward maintenance; no output effect before 2028.

Notes

  • Partner contract tests will fail (partners/.../wa/working_families_tax_credit.yaml, tax_credits_composition.yaml, signatures/wa.yaml) because A1 changes WA WFTC outputs. Not rewritten here — flagged for partner coordination per the repo's partner-test policy.
  • Phase-out expected values are hand-computed to the dollar (a couple carry a wider absolute_error_margin); CI will pin the exact cents.

Closes #9373 (pending B5(ii)/B6 follow-ups noted above).

…#9373)

A1: phase-out rate is maximum amount / phase-out band per WAC 458-20-285(10)(d)
(0.12/0.12/0.18/0.24 for 0-3 children on the 2022 base amounts), not
(maximum - minimum) / band; the old slope under-taxed the phase-out and
overpaid inside the band. The $50 statutory minimum (RCW 82.08.0206(3)(c))
still floors any positive reduced amount.

A4: the maximum qualifying income ceiling is strict (WAC 458-20-285(10)(e):
income "equal to or more than" the threshold is ineligible).

A3: ESSB 6346 Sec. 1205(1) makes the expansion (age, maximum qualifying income,
assistance-unit-size cap) effective January 1, 2028 for applications submitted
beginning in calendar year 2029 -- i.e. tax year 2028, not 2029.

Updates baseline tests for the new rate and effective year. Does not touch
amount.yaml uprating/rounding (B5(i), handled by PolicyEngine#9371). B5(ii) Seattle CPI-W
index and B6 need-standard maintenance are tracked as follow-ups.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o3CatUFsN4y6TpBHY6Vgf
@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (e21799b) to head (a460e4e).
⚠️ Report is 97 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9391   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            3         3           
  Lines           33       106   +73     
  Branches         0         1    +1     
=========================================
+ Hits            33       106   +73     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

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

☔ View full report in Codecov by Harness.
📢 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 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator Author

Extra primary-source corroboration for A1 (the max/band phase-out rate), from a live TAXSIM record (PolicyEngine/policyengine-taxsim#1166 — WA 2023 MFJ, 3 qualifying children, AGI $61,289 inside the 3-child phase-out band).

I pulled WAC 458-20-285(10)(D) verbatim (apps.leg.wa.gov):

...your maximum refund will be decreased, but not below $50, as follows (the below figures reflect the 2022 tax year adjustments to the original statutory amounts):
(a) [no children]... reduce the amount of refund received by $0.12
(b) [one child]... reduce the amount of refund by $0.12
(c) [two children]... reduce the amount of refund by $0.18
(d) [three or more]... reduce the amount of refund by $0.24
The department will adjust the WFTC refund reduction amounts on an annual basis beginning in 2023 to align the WFTC program with the federal EITC program.

Two takeaways that back this PR:

  1. The published rates are exactly max / band on the 2022 base amounts (300/2500 = 0.12, 600/5000 = 0.12, 900/5000 = 0.18, 1200/5000 = 0.24) — confirming max/band, not the pre-PR (max − min)/band (which would give 0.11/0.17/0.23).
  2. The rule explicitly says the reduction amounts are adjusted annually beginning 2023, so they are not frozen at the 2022 $0.24. With the 2023 uprated 3-child max ($1,255) over the fixed $5,000 band, the 2023 rate is 1,255/5,000 = 0.251, which is what this PR computes — and it makes the credit reach exactly $0 at the ceiling, per "align with the federal EITC."

For the #1166 record this lands at ≈$529 (vs the pre-PR $558.70 from the old (max−50)/band ≈ 0.241). The application-instruction PDFs don't publish the rate at all (as the parameter comment notes), so WAC 458-20-285(10)(D) is the operative source.

@DTrim99

DTrim99 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator Author

@hua7450 heads-up — this PR will affect API partner contract values, so we need to coordinate before it merges.

The A1 phase-out-rate correction (to max ÷ band per WAC 458-20-285(10)(d)) changes two analytics_coverage WA WFTC edge cases in tests/policy/baseline/partners/analytics_coverage/edge_cases/state/wa/working_families_tax_credit.yaml:

Case (2026) Current pinned Post-fix Reason
wa_wftc_childless_mid_phase_out 230.21 211.00 steeper correct rate (0.12 vs 0.11) reduces more inside the band
wa_wftc_1_child_min_amount_near_ceiling 50.42 50.00 now floored at the $50 statutory minimum (RCW 82.08.0206(3)(c))

These are corrections (the old model overpaid in the phase-out band), not regressions — consistent with your #9373 verification. But because they're partner-facing values, per our contract-test policy I'm holding the update to that partner file until the API partner is notified and it's acknowledged. Flagging you as the team contact; could you confirm the partner (analytics_coverage) is looped in? Once acknowledged I'll update the two expected values to match.

The A1 phase-out-rate fix (max/band per WAC 458-20-285(10)(d)) changes two
analytics_coverage WA WFTC edge cases:
- wa_wftc_childless_mid_phase_out (2026): 230.21 -> 211.00
- wa_wftc_1_child_min_amount_near_ceiling (2026): 50.42 -> 50.00 (now floored at
  the $50 statutory minimum, RCW 82.08.0206(3)(c))

These are corrections (the prior model overpaid inside the phase-out band), not
regressions. Partner (analytics_coverage) notification is handled via the weekly
partner update; flagged to @hua7450 who provides it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCwrSsGY7vPCpKYGfV1xRr
@DTrim99

DTrim99 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator Author

Update: re-pinned the two WA WFTC partner contract values to the corrected amounts (commit above):

  • wa_wftc_childless_mid_phase_out (2026): 230.21 → 211.00
  • wa_wftc_1_child_min_amount_near_ceiling (2026): 50.42 → 50.00 (now at the $50 statutory floor)

@hua7450 — since partner notification goes out through your weekly partner update, please include this WA WFTC change in the next one. No separate partner sign-off needed here, and @anth-volk can disregard the earlier partner-gate ask on #9371 — the weekly update covers it.

Note for merge sequencing: #9371 also re-pins this same file (uprating rounding → e.g. childless mid-phase-out 231.69). Whichever of #9371/#9391 merges second will need a quick re-pin to the combined value (rounding + corrected rate), and that combined number is what should appear in the weekly partner update.

…-work

# Conflicts:
#	policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml
#	policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/state/wa/working_families_tax_credit.yaml
@DTrim99
DTrim99 marked this pull request as ready for review September 4, 2026 18:43
@DTrim99
DTrim99 requested a review from hua7450 September 4, 2026 18:43
@hua7450

hua7450 commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Program Review

Source Documents

Branch Status

The branch is 3 ahead / 1 behind main; the one missing commit (04a961a) is a version bump only, so a rebase is optional and staleness did not affect any finding. PR #9371's nearest-$5 rounding is at the merge base (a2ae335) and therefore already in the PR head, which is why the tests' 365 / 345 / 675 maxima reproduce. CI is fully green, including Household API Partners — the PR head re-pinned the partner contract values, so the PR body's "partner tests will fail" note is stale.

Critical (Must Fix)

  1. [C1] age_expansion/min_age.yaml was not moved to 2028 — tax year 2028 has an in-effect expansion with a minimum age of 0: The PR moved age_expansion/in_effect, maximum_qualifying_income/in_effect and max_assistance_unit_size from 2029-01-01 to 2028-01-01 but left min_age at 2029-01-01: 18 behind its 2000-01-01: 0 back-stop. In TY2028 filer_meets_min_age = (age_head >= 0) | (age_spouse >= 0) is unconditionally true (age_spouse is 0 for single filers) and no other gate on the expansion path is age-dependent, so every WA filer with earnings below the ceiling qualifies — executed against the snapshot, a single 17-year-old (or 10- or 16-year-old) with $8,000 wages receives $360 in 2028 and correctly $0 in 2029. The new 2028 test uses an 18-year-old and passes under either dating, so it cannot detect this. — policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/min_age.yaml:5; consumer policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit_age_expansion_eligible.py:37 — PDF Sec. 901(2)(a)(ii)(D) "at least age 18" p.60; Sec. 1205 p.109. Fix: 2028-01-01: 18 (all four Sec. 901 provisions share the single Sec. 1205 date); add a period: 2028, age-17 negative test mirroring policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:530 asserting wa_working_families_tax_credit_age_expansion_eligible: false and wa_working_families_tax_credit: 0; mention the re-dating in the changelog fragment. (Flagged by regulatory C1, references C3, code CRITICAL, tests C1, pdf-statute MISMATCH 1, pdf-amounts M1; CONFIRMED by codepath-1 execution and mismatch-1 A at 600 DPI.)
  2. [C2] The 2028-01-01 date is cited to Sec. 1205(1), which says January 1, 2029: The value is correct (see Investigated and cleared) but its cited authority now contradicts it. Sec. 1205(1) reads "Section 901 of this act takes effect January 1, 2029"; the 2028 date comes from Sec. 1205(2), "Refunds may not be provided under section 901 of this act for any period before January 1, 2028." The PR changed the value without updating the reference titles, added test comments attributing "takes effect January 1, 2028" to Sec. 1205(1), and the PR body's quoted sentence ("takes effect January 1, 2028, for applications submitted beginning in calendar year 2029") is not in the enrolled bill — it is a Senate Bill Report (APS/HA) staff sentence; the Final Bill Report says 2029. max_assistance_unit_size.yaml carries no Sec. 1205 reference at all, so its 2028 dating is untraceable from the file. — policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/in_effect.yaml:13; policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/maximum_qualifying_income/in_effect.yaml:14; policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/maximum_qualifying_income/max_assistance_unit_size.yaml:4,11-12; policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:575-576,600-601 — PDF p.109. Fix: retitle to ESSB 6346, Sec. 1205(2) - No refunds under Sec. 901 for any period before January 1, 2028 (Sec. 1205(1): Sec. 901 takes effect January 1, 2029) with the same #page=109 in both in_effect.yaml files and add it to max_assistance_unit_size.yaml; reword the two test comments to the Sec. 1205(1)-(2) mechanics; correct the PR body attribution. Optionally add the codified RCW note "Effective date—When refunds provided—2026 c 238 s 1205" and the DOR fiscal note (OFM package 77653, first expanded payments booked in FY2029). (Flagged by references C1/S4, regulatory S1, pdf-statute INTERPRETIVE NOTE 2, pages side note; CONFIRMED by codepath-4 and mismatch-1 B.)
  3. [C3] max_assistance_unit_size cap and need-standard sizes 2-5 have zero test coverage: The only need-standard case is a single-person unit at 2029, so min_(size, p.max_assistance_unit_size) and the cash_assistance_need_standard[2..5] lookups are never executed by any test in any year — including the cap parameter this PR re-dated. — policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit_maximum_qualifying_income.py:41-46; policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:633-665 (sole need-standard case) — PDF Sec. 901(2)(e)(ii) "not to exceed five" p.60. Fix: add a size-in-range case (e.g. period: 2028, joint, no children → 6,044 × 12 = 72,528) and a size-6 case (joint + 4 children → capped to 5 → 11,481 × 12 = 137,772), each asserting wa_working_families_tax_credit_maximum_qualifying_income. (tests C2.)

Should Address

  1. [A1] Two #page=59 links point at the wrong page for Sec. 901(2)(e) / (2)(e)(ii): File p.59 carries only the PART IX heading, Sec. 901(1) and the start of (2)(a); the "Maximum qualifying income" definition and the "not to exceed five" cap are on file p.60 (the printed page number was used instead of the file page). The lines are pre-existing but sit in files this PR edits; the same error is in two sibling files. — policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/maximum_qualifying_income/in_effect.yaml:13; policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/maximum_qualifying_income/max_assistance_unit_size.yaml:12; also policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/maximum_qualifying_income/cash_assistance_need_standard.yaml:14 and policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit_maximum_qualifying_income.py:13 — PDF p.60. Fix: #page=59#page=60 in all four. (pages verifier WRONG ×2; references C2.)
  2. [A2] The new rate comment overstates WAC 458-20-285 and mis-cites its structure; the strict-ceiling authority is mis-cited as "(10)(e)": The comment says "WAC 458-20-285(10)(d) reduces the credit by (maximum amount / phase-out band)"; the WAC is organized as Answers 10A-10K, and Answer 10D only publishes DOR's 2022 per-dollar figures ($0.12 / $0.12 / $0.18 / $0.24, "adjusted ... annually beginning in 2023") without stating a formula. The formula itself is right — DOR's ETA 3240 publishes per-year rates equal to max / band in all 16 TY2022-2025 cells — so cite that. The "equal to or more than" language the PR body attributes to WAC (10)(e) lives in WAC 458-20-285(4) / Answer 4C (10E is the worked example and tables). The WAC appears only in a comment, not in the variable's reference tuple. — policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py:141-148 (comment), :15-22 (reference); test comments policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:210,662,817, policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/state/wa/working_families_tax_credit.yaml:130-134,197-199; changelog.d/fix-wa-wftc-phaseout-effective-year.fixed.md:1WAC 458-20-285; ETA 3240.2026 p.3. Fix: reword to "RCW 82.08.0206(3)(f) directs DOR to re-set the rate annually; DOR's published per-dollar rates (WAC 458-20-285(10) Answer 10D for 2022; ETA 3240 for 2022-2025) equal maximum amount / phase-out band in every year, so the reduced amount reaches $0 at the ceiling and the (3)(c) $50 floor catches the last band"; cite Answer 4C and the DOR instructions (#page=1, #page=4) for <; add the WAC and ETA 3240 URLs to reference. (references C4/S1/S2 downgraded to a citation nit per codepath-3 and ext-1; regulatory S2.)
  3. [A3] Stale 2029 / old-formula wording in the tests this PR edits: partner test name wa_wftc_age_18_before_2029_expansion and comment "not in effect until 2029" (expansion is now 2028); partner header comment "phases from the maximum down to $50 over the last $2,500 / $5,000" describes the removed (max − 50) / band rate — it now phases to $0 with a $50 floor; 50.00 trailing zeros where sibling cases use 50; baseline names "Case 7 / 7b ... under 2029 age expansion" read as if 2029 were the effective year. — policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/state/wa/working_families_tax_credit.yaml:7-8,200,266,309; policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:216,232. Fix: rename to ..._before_2028_expansion, update the comments, write 50. (code SHOULD/SUGGESTION, tests SUGGESTION 1, pdf-amounts test notes.)
  4. [A4] Error margins widened without need; a margin of 1 masks the Fix ignored uprating rounding rules in state tax parameters #9371 rounding dependency: The 2029 need-standard case pins 261.63 (reproducible to the cent: 365 − 0.146 × 708 = 261.632) with absolute_error_margin: 1; with an unrounded max (366.7) the result would be 262.85, inside the margin, so the test cannot tell whether the nearest-$5 rounding it cites is active. Cases 5 and 6b were loosened 0.01 → 0.1 although the hand values (320.026, 977.584) are within 0.01 of the pins. Every widened margin is still smaller than its case's old-rate delta, so none hides the rate change itself. — policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:88,161,635. Fix: 0.01 on all three (pin 320.03 if preferred). (tests S4, code SUGGESTION.)
  5. [A5] Missing in-band coverage for the changed formula: (a) no 2-child in-band non-floor case — the 0.188-class rate is tested only at the floor (Case 17 → 50, which any rate ≥ 0.1782 satisfies); (b) the state-only path (MFS / ITIN), where the < was also changed, is tested only at full-credit incomes; (c) no case sits at phase_out_start (full max), one dollar into the band, or at a reduced amount just above 50. — policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml (whole file). Fix: 2023 MFJ 2 children at 56,478 → 564.00 (old rate would give 584); 2024 MFS 1 child at 46,584 → 320.03 and one at/above the non-joint ceiling 49,084.21 → 0; 2023 MFJ 1 child at 48,120 → 625, 48,121 → 624.875, 52,700 → 52.50, 52,740 → 50. (tests S1, S2, S5.)
  6. [A6] maximum_qualifying_income/in_effect flip tested on one side only: the age-expansion toggle is tested at 2027 (false) and 2028 (true), but the maximum-qualifying-income expansion is asserted only at 2029; a regression making in_effect always-true would pass every current test. — policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/maximum_qualifying_income/in_effect.yaml:5; policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:633-665. Fix: period: 2028 single filer → wa_working_families_tax_credit_maximum_qualifying_income: 45_792 (credit at 44,000 → 360 − 0.144 × 708 = 258.05), and period: 2027 same filer → federal ceiling only (~20,011). (tests S3; codepath-2 table.)
  7. [A9] (downgraded from C4) The strict ceiling (<=<) has no distinguishing test: No case places income exactly at wa_working_families_tax_credit_maximum_qualifying_income — partner cases straddle 51,593.38 (51,590 / 51,600) and Case 4 was moved further from the ceiling (49,084 → 49,000) — so a revert to <= would pass every test. Code-path verification shows the operator is load-bearing: under the new rate max − band × (max / band) leaves a 1e-13 float residue for TY2026 2-child and TY2027 0-child units, which the old <= turned into a spurious $50 exactly at the ceiling. — policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py:88,112; policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:50-84 (Case 4) — WAC 458-20-285(4) / Answer 4C (HTML); DOR instructions "AGI must be less than" p.1. Fix: add at-ceiling cases asserting 0 — 2023 MFJ 1 child at 53,120 (Case 16 already asserts that ceiling; 53,119 → 50), 2026 MFJ 2 children at 65,898.84 (residue year), 2029 single at 45,792 (45,791 → 50) — and restore the 49,084 → 50 / 49,085 → 0 pair in the baseline file. (tests C3/S6; codepath-2 §4b. Downgraded from Critical: missing boundary test on an already-tested variable, no wrong output.)

Pre-existing (out of PR scope)

  1. [A7] PRE-EXISTING — The reduced refund is not rounded to the nearest dollar: RCW 82.08.0206(3)(b) / Sec. 901(3)(b) "will be reduced, rounded to the nearest dollar"; WAC Answer 10E Example 3 "$590.64, which will be rounded to $591"; ETA 3240 "All reductions are rounded to the nearest dollar". The model returns cents, and the PR re-pinned five cent-level values (320.02, 977.58, 384.01, 261.63, 212.48) on the very lines it rewrote, so fixing here avoids a second re-pin. Effect ≤ $0.50 per household; no test shows an outcome flip. Not in the PR body's follow-up list. — policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py:153-159 — PDF p.61. Fix: where(phased_out_amount > 0, max_(p.min_amount, round_(phased_out_amount)), 0) — gate on the unrounded value so a result in (0, 0.5) still floors to $50 per (3)(c) — and re-pin to 320 / 978 / 384 / 262 / 212; or file a follow-up and state the simplification in the comment block. (regulatory S3, pdf-statute MISSING 2; codepath-5 P2 CONFIRMED; mismatch-2 P2 CONFIRMED at 600 DPI.)
  2. [A8] PRE-EXISTING — Phase-out is measured on max_(earnings, agi), but the statute defines "income" as earned income: RCW 82.08.0206(2)(b) / Sec. 901(2)(b) "'Income' means earned income as defined by Title 26 U.S.C. Sec. 32"; (3)(b) reduces "per additional dollar of income" — "federal phase-out / maximum qualifying income" is only the anchor of the band. WAC §4 and Answer 10C, Example 3, and the DOR legislative report all compute the reduction on earned income. The max_ is correct for the AGI-based ceiling test but over-reduces households with AGI above earned income inside the band (Case 6b: law $1,330, model $977.58). The comment attributes the greater-of rule to (3)(b), and the PR re-pinned Case 6b on that reading. Not in the PR body's follow-up list. — policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py:81,149-153; policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml:159-212 — PDF p.60, p.61. Fix: follow-up to use excess = max_(0, earnings - phase_out_start) (keep higher_income for the ceiling) and re-pin Case 6b to 1,330; in this PR, soften the comment and the Case 6b rationale so they do not assert statutory authority for max(earned income, AGI). (regulatory G3, references G1, pdf-statute MISSING 3; codepath-5 P3 CONFIRMED; mismatch-2 P3 CONFIRMED.)

Suggestions

  1. [S1] Age-expansion helper still uses <= on the same ceiling; make the $50 floor residue-proof: wa_working_families_tax_credit_age_expansion_eligible.py keeps <= while the main variable now uses <. Verification shows the <= is the statutory reading of Sec. 901(2)(a)(ii)(C) "equal to or less than" for 2028+ and yields no wrong output except through float residue: in TY2028 a 1-child or 3-child unit at exactly the ceiling receives $50 while 0- and 2-child units receive $0. — policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit_age_expansion_eligible.py:62; policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py:155-158 — PDF p.60. Either align the helper to < for consistency or add a one-line comment citing (C), and guard the floor (e.g. round_(phased_out_amount, 2) before the > 0 test, or compute the reduction as max_amount * excess / band, exact when excess == band). (code SHOULD, regulatory S4, pdf-statute MISMATCH 2 — downgraded per codepath-2.)
  2. [S2] Collapse the two identical income-eligibility expressions and drop a dead floor: baseline_income_eligible and state_only_income_eligible are byte-identical after this PR; a single income_eligible prevents them drifting again. reduction = max_(0, excess * phase_out_rate) is a dead floor since excess is already max_(0, ...). — policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py:87-89,111-113,154. (code SUGGESTION.)
  3. [S3] Reference hygiene on the three re-dated parameters: pair the session-law links with the now-codified RCW text (the RCW 82.08.0206 page shows the 2026 c 238 s 901 version with the Sec. 1205 note; no anchors, so put the subsection in the title); name the subsection in the age-expansion title ("Sec. 901(2)(a)(ii)(D) - Age expansion (at least age 18)"); add #page=62 alongside #page=61 in the variable reference, since the (3)(c) floor and (3)(f) rate rule are on p.62; give max_assistance_unit_size.yaml a 2000-01-01 base entry (its single 2028-01-01: 5 phantoms backward — harmless because gated by in_effect). — policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/age_expansion/in_effect.yaml:11; policyengine_us/variables/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.py:17; policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/maximum_qualifying_income/max_assistance_unit_size.yaml:4 — PDF p.62. (references S3/S5/G2; mismatch-1 side note.)
  4. [S4] Changelog fragment wording: "its statutory effective tax year 2028" would be more precise as "the first tax year it covers (2028; ESSB 6346 Sec. 1205(2))"; add the min-age re-dating once C1 is fixed. — changelog.d/fix-wa-wftc-phaseout-effective-year.fixed.md:1. (regulatory G4.)
  5. [S5] Additional test ideas: a 2028 amount case via the expansion path (childless 20-year-old, 10,000 → 360) so the first in-effect year checks the credit, not just the boolean; a negative-earnings guard (self-employment loss → 0) and an AGI-below-earnings case; an integration.yaml / household_net_income check; the "SSN child + ITIN child" comment says "partially phased out at $20K" but 995 is the full 2-child maximum. — policyengine_us/tests/policy/baseline/gov/states/wa/tax/income/credits/wa_working_families_tax_credit.yaml. (tests SUGGESTION 1-4.)

Pre-existing (out of PR scope)

  1. [S6] PRE-EXISTING (B5(ii)) — amount.yaml uprates with gov.irs.uprating (national Chained CPI-U, Sep-Aug) but RCW 82.08.0206(3)(d)-(e) prescribes the Seattle-area CPI-W 12-month average published by November 15, rounded to $5: affects only TY2026+ projections (345 / 675 / 1,020 / 1,360 for 2026; 365 for 2029) that the new tests rely on; 2022-2025 are hard-coded DOR values that match every source. No Seattle CPI-W series exists in the repo. DOR also indexes the $50 minimum under the same rule (it stays $50 through TY2024), which belongs in the same follow-up as a design note. — policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/amount.yaml:35-40 (and :50-55, :65-70, :80-85) — PDF p.62. Acknowledged follow-up B5(ii); hard-code the TY2026 amounts when DOR publishes them (ETA 3240.2027, ~Jan 2027). (regulatory G1, pdf-statute PRE-EXISTING 1; codepath-5 P1/P5; mismatch-2 P1 CONFIRMED.)
  2. [S7] PRE-EXISTING (B6) — cash_assistance_need_standard.yaml stops at 2025-07-01: WSR 26-10-028 (effective July 1, 2026) sets sizes 1-5 at 3,942 / 6,276 / 7,678 / 9,907 / 11,846; the model carries the 2025-07-01 row into 2028+, understating the size-1 ceiling (45,792 vs 47,304), so the 2029 need-standard test's 45,792 will need updating with B6. Worth a comment on which month's standard the tax-year read uses (January 1 → the prior July's standard). — policyengine_us/parameters/gov/states/wa/tax/income/credits/working_families_tax_credit/maximum_qualifying_income/cash_assistance_need_standard.yaml:20-34 — PDF WSR 26-10-028 p.1, p.2. (pdf-amounts R1/F5, regulatory G2.)
  3. [S8] PRE-EXISTING (Fix ignored uprating rounding rules in state tax parameters #9371 follow-up) — partner composition test pins the unrounded 674.96: the model now returns 675 after nearest-$5 rounding; the test passes only because absolute_error_margin: 0.1 > 0.04. — policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/state/wa/tax_credits_composition.yaml:65-70. Re-pin to 675 / 675 / -675 and fix the "660 x 1.02266" comment while partner contracts are being touched. (code, tests SUGGESTION 1, regulatory G5.)

Investigated and cleared

  • Phase-out rate max / band vs (max − 50) / band — REJECTED as a mismatch; confirmed correct. DOR's ETA 3240 publishes per-year per-dollar rates that equal max / band in 16 of 16 TY2022-2025 cells (e.g. TY2024 1 child $0.128 = 640 / 5,000; TY2025 3+ children $0.266 = 1,330 / 5,000); (max − 50) / band matches none. RCW (3)(f) delegates the rate to DOR, which states that max / band plus the (3)(c) floor is how "the minimum credit [is] received at the maximum qualifying income level". All PR test expectations reproduce under max / band and would fail under the removed formula. (codepath-3; ext-1.)
  • Ceiling < vs <= — REJECTED. No reachable household/year exists where < yields a wrong dollar output: pre-2028 law is strict (WAC 458-20-285(4) / Answer 4C; DOR instructions "must be less than"), and < removes a latent $50 mis-payment exactly at the ceiling in TY2026 (2 children) / TY2027 (0 children) that the old <= produced via float residue; for 2028+ the inclusive Sec. 901(2)(a)(ii)(C) reading is already realised by the helper's <=. Residual kept as S1. (codepath-2.)
  • 2028-01-01 effective-date value — REJECTED as a value error (the citation defect is C2). Sec. 1205(1)'s January 1, 2029 is the operative date during the TY2028 application season; Sec. 1205(2) makes TY2028 the first refundable period; the bill's own convention is "tax year 2028 with taxes due in 2029"; the DOR fiscal note books the first expanded WFTC payments ($226M) in FY2029, i.e. February-June 2029 on tax-year-2028 applications. (codepath-4; pdf-statute INTERPRETIVE NOTE 2.)
  • min_amount.yaml not indexed (P5) — REJECTED as a defect. $50 is the published minimum for every year TY2022-2024 (ETA 3240, DOR legislative report, WAC 10B); DOR indexes year-over-year from the rounded prior amount, so $50 stays $50 unless a single year's Seattle CPI-W growth reaches 5%. Recorded as a B5(ii) design note under S6. (codepath-5 P5.)
  • Derived federal EITC ceiling vs DOR-published thresholds (P4, $0.02-$3.14) — FALSE POSITIVE as a WA defect. calculate_eitc_max_agi_limit = start + max / rate is the same unrounded endpoint the federal eitc and eitc_agi_limit use; the gap changes an output by at most the $50 minimum inside a ≤ $3.14 AGI sliver. Any fix belongs in gov.irs.credits.eitc as an IRS completed-phase-out parameter. (codepath-5 P4; mismatch-2 P4.)

PDF Audit Summary

Category Count
Confirmed correct 48 (14 statute/rule + 34 amounts; plus 16/16 DOR ETA 3240 rate cells)
Mismatches (code-path confirmed + visually verified) 2 (C1 min_age date; C2 Sec. 1205(1) citation)
Mismatches rejected (code-path cleared) 5 (rate formula; < ceiling; 2028 value; min_amount indexing; EITC ceiling drift)
Unmodeled items 1 (183-day residency / sales-or-use-tax-paid requirement, RCW 82.08.0206(2)(a)(i)(B)-(C), (2)(g) — by design)
Pre-existing issues 4 (P1 uprating index B5(ii); P2 nearest-dollar rounding; P3 earned-income phase-out base; B6 need standard 2026-07-01)

Validation Summary

Check Result
Regulatory Accuracy 2 issues (C1 min_age date, C2 Sec. 1205 citation) + 2 pre-existing (A7, A8)
Reference Quality 4 issues (C2 wrong subsection; A1 two wrong #page; A2 WAC mis-description and missing WAC/ETA references; S3 hygiene)
Code Patterns 1 critical (C1 toggle-date alignment) / 3 suggestions (S1, S2, S4)
Formatting (params & vars) 2 nits (50.00 trailing zeros in A3; missing base entry in S3)
Test Coverage 2 critical gaps (C1 2028 negative test, C3 cap/sizes 2-5) + 5 should (A3-A6, A9 at-ceiling)
PDF Value Audit 2 mismatches / 48 confirmed
CI Status Passing

Review Severity: REQUEST_CHANGES

Next Steps

To auto-fix issues: run the fix-pr workflow for this PR.

@hua7450 hua7450 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Requesting changes per the full review posted above (#9391 (comment)). Blocking items: C1 age_expansion/min_age.yaml still flips to 18 at 2029-01-01 while the expansion toggles now flip at 2028-01-01 (TY2028 admits any age); C2 the 2028 date is cited to Sec. 1205(1), which says January 1, 2029 — the authority is Sec. 1205(2); C3 the assistance-unit-size cap and need-standard sizes 2-5 have zero test coverage. The phase-out rate change (max / band) and the 2028 tax-year modelling are confirmed correct against DOR ETA 3240 and the enrolled bill.

…ding, test coverage

Applies all items from the 2026-09-05 review: re-dates the age-expansion
minimum age to 2028, corrects ESSB 6346 Sec. 1205(2) citations and page
references, adds RCW 82.08.0206(3)(b) nearest-dollar rounding with the
$50 floor gated on the unrounded amount, restores 0.01 error margins,
adds boundary/in-band/at-ceiling/integration test cases, and updates the
partner contract pins for the rounded values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
@DTrim99

DTrim99 commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator Author

Fixes applied from @hua7450's review

Thanks for the thorough review. All 18 in-scope items are addressed in the latest commit.

Critical

  • C1 — Re-dated the age-expansion minimum age from 2029-01-01 to 2028-01-01: 18 (TY2028 was admitting any age); added a 2028 age-17 negative test asserting age_expansion_eligible: false and credit 0.
  • C2 — Re-cited the 2028 effective date to ESSB 6346 Sec. 1205(2) ("no refunds before Jan 1 2028"), not Sec. 1205(1); added the reference to max_assistance_unit_size.yaml and fixed the baseline-test cite comments.
  • C3 — Added need-standard size coverage: 2028 joint no-children → max_qualifying_income 72,528; joint + 4 kids capped at 5 → 137,772.

Should

  • A1 — Fixed #page=59#page=60 across all 4 listed files (3 YAML + 1 .py reference).
  • A2 — Reworded the WAC comment (Answer 10D publishes 2022 rates; formula authority is ETA 3240 + RCW (3)(f); strict-ceiling cite is WAC (4)/Answer 4C, not "(10)(e)"); added the WAC + ETA 3240 URLs to the reference tuple.
  • A3 — Renamed wa_wftc_age_18_before_2029_expansion..._2028_..., fixed stale 2029/old-formula comments, and normalized 50.0050 in the partner file.
  • A4 — Restored absolute_error_margin: 0.01 on Cases 5, 6b, and the need-standard 2029 case (margin 1 was masking Fix ignored uprating rounding rules in state tax parameters #9371 rounding).
  • A5 — Added in-band cases across 2023/2024 MFJ/MFS filers at the reviewer-listed income points (recomputed under the new rounding).
  • A6 — Tested the maximum_qualifying_income in_effect flip on both sides (2028 vs 2027 federal ceiling).
  • A7 — Fixed in-PR per your option A (see rounding note below).
  • A8 — Softened the phase-out-base comment and Case 6b rationale so they no longer claim statutory authority for max(earnings, AGI) (flagged as a modeling choice / follow-up).
  • A9 — Added at-ceiling cases asserting 0, plus the strict-< distinguishing pair (49,084 → 50 / 49,085 → 0).

Suggestions

  • S1 — Added the Sec. 901(2)(a)(ii)(C) comment on the age-expansion helper (kept <= semantics) and made the $50 floor residue-proof.
  • S2 — Collapsed the duplicate income-eligible expressions into one and dropped the dead max_(0, ...) floor.
  • S3 — Reference hygiene: codified RCW cites, subsection in the age-expansion title, #page=62 for (3)(c)/(3)(f), and a 2000-01-01 base entry in max_assistance_unit_size.yaml.
  • S4 — Reworded the changelog fragment to "first tax year it covers (2028; ESSB 6346 Sec. 1205(2))" and noted the min-age re-dating.
  • S5 — Added the 2028 expansion-path amount case (childless 20yo, 10,000 → 360), negative-earnings → 0, AGI-below-earnings, and a household_net_income integration case; fixed the "partially phased out at $20K" comment.
  • S8 — Re-pinned 674.96675/675/-675 in tax_credits_composition.yaml and fixed the "660 x 1.02266" comment.

A7 — rounding (option A)

Implemented nearest-dollar rounding per RCW 82.08.0206(3)(b) using numpy round_ (half-to-even), with the $50 floor gated on the unrounded phased-out amount. Three of the reviewer's figures were pre-rounding and were recomputed under the new rounding rule and the actual parameter values:

  • ceiling 49,084 → 49,084.21 (true frozen-EITC indexed ceiling; strict < flip verified);
  • JOINT childless federal ceiling is 27,421.18, not ~20,011 (that was the single-filer figure);
  • 52.50 → 52 under half-to-even.

Partner files

The three partner-contract edits — A3 rename, S8 675 re-pin, and A7 212 re-pin (212.48212) — were made under the approved partner gate. Partner notification will ride the next weekly partner update.

Deferred (reviewer-acknowledged follow-ups)

  • S6 — Seattle CPI-W uprating (hard-code TY2026 when ETA 3240.2027 publishes).
  • S7 — WSR 26-10-028 2026-07-01 need-standard rows.

Tests

  • Baseline wa_working_families_tax_credit.yaml: 48/48 pass.
  • Partner working_families_tax_credit.yaml + tax_credits_composition.yaml: 9/9 pass.
  • Full WA credits dir: 49/49 pass.
  • Validator audit: CLEAN, 18/18.

@DTrim99
DTrim99 requested a review from hua7450 September 11, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants