Skip to content

Emit PE one-time rebates in srebate and add --net-of-rebates comparison scoring#1070

Merged
PavelMakarchuk merged 2 commits into
mainfrom
add-srebate-net-of-rebates
Jul 6, 2026
Merged

Emit PE one-time rebates in srebate and add --net-of-rebates comparison scoring#1070
PavelMakarchuk merged 2 commits into
mainfrom
add-srebate-net-of-rebates

Conversation

@PavelMakarchuk

Copy link
Copy Markdown
Collaborator

Summary

TAXSIM books one-time state rebates in payout-year siitax (reporting them in its srebate output column); PolicyEngine books them to the liability year. The same rebate therefore breaks the comparison twice — once in each year, opposite signs (#1068; convention question #716). This PR makes the emulator emit its own srebate and adds a --net-of-rebates option to compare that scores state tax as siitax + srebate on both sides — removing the timing convention from match scoring without changing either engine's behavior.

Design: srebate is a computed difference, not a variable sum

PE's srebate = state_income_tax(one-time rebates zeroed, lazy twin sim) − state_income_tax(actual) — exactly the amount rebates moved siitax.

Why not sum the rebate variables? We tried — it failed validation (2022 state match −2.75 pts): several PE rebate variables compute amounts that never reach siitax (mt_income_tax_rebate $1,250, sc_2022_rebate $800 — not wired into state tax; GA amounts liability-capped away), creating 312 phantom mismatches. The difference-based design is immune by construction.

Validation (8,000-record eCPS, scored at 0.1%-of-AGI tolerance)

Year State match (base) State match (net-of-rebates) Δ Federal
2021 75.50% 87.08% +11.58 90.29% — identical
2022 79.30% 83.30% +4.00 89.53% — identical

Sanity: ME 2021 srebate = $850.00 (relief payment), VA 2021 = $250.00 — to the penny, matching the mirror analysis in #1068.

Details

  • Default behavior unchanged: --net-of-rebates is opt-in; the srebate column is additive output (idtl 2/5). Composable with --rel-tolerance.
  • The twin sim is built lazily (only when srebate is extracted) from the same dataset; rebate variables are zeroed via set_input before any calculation (formula variables are silently recomputed otherwise — same lesson as Zero PE-imputed transfers via set_input (fixes MA Senior Circuit Breaker, #1031) #1049).
  • 16 one-time rebate variables covered (AZ/CO/CT/DE/GA/HI/ID×2/IL/IN/MA/ME/MT/NM×3/RI/SC/VA); recurring annual rebates deliberately excluded.
  • Tests: tests/test_net_of_rebates.py (6 tests — comparator both-directions, non-blanket-pass guard, ME $850 e2e). Full suite passes.

Refs #1068, #716, #1059.

🤖 Generated with Claude Code

TAXSIM books one-time state rebates in payout-year siitax (reported in its
srebate column); PE books them to the liability year. The same rebate
therefore breaks the match twice — once in each year, opposite signs
(#1068, convention #716).

Emit PE's srebate as a computed difference: state_income_tax with the 16
one-time rebate variables forced to zero (lazy twin sim, set_input before
any calculation) minus actual state_income_tax. This is exactly the amount
rebates moved siitax — immune to variables that exist but are not wired
into state tax or are liability-capped (a variable-sum approach broke 312
records in 2022 via such phantoms). Add --net-of-rebates to compare,
scoring state tax as siitax + srebate on both sides; composable with
--rel-tolerance, federal untouched.

eCPS validation (8k records/yr, at 0.1%-AGI tolerance):
  2021 state 75.50% -> 87.08% (+11.58), federal unchanged 90.29%
  2022 state 79.30% -> 83.30% (+4.00), federal unchanged 89.53%

Sanity: ME 2021 srebate = 850.00 (relief payment), VA 2021 = 250.00.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
policyengine-taxsim Ready Ready Preview, Comment Jul 6, 2026 9:10pm

Request Review

_extract_vectorized_results gained rebate_free_sim_factory; the timed_extract
test wrapper had a fixed 3-arg signature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PavelMakarchuk PavelMakarchuk merged commit 3c9eb68 into main Jul 6, 2026
12 checks passed
@PavelMakarchuk PavelMakarchuk deleted the add-srebate-net-of-rebates branch July 6, 2026 21:23
PavelMakarchuk added a commit that referenced this pull request Jul 7, 2026
…mode (#1072)

Regenerate the full-population comparison (111,347 records x 2021-2025) on
current main, picking up the July fixes: transfer zeroing (#1049),
pass-through QBID routing (#1051), transfers mapping (#1052), MD county-tax
parity (#1066), and the srebate column (#1070).

Summaries now carry net-of-rebates state metrics (stateMatchPctRelNet /
statePctRelNet): the relative-tolerance match with one-time state rebates
netted out of siitax on both sides, removing the TAXSIM payout-year vs
PolicyEngine liability-year timing convention (#1068). The dashboard gains a
third tolerance mode surfacing it; federal metrics are unchanged by rebates.
Full-data downloads point at the full-ecps-comparison-2026.07.07 release
(flags: --assume-w2-wages; --disable-salt dropped - inert on the eCPS and
overstates federal tax for 2025 itemizers, see #1058).

Headline (1% of gross income): state 87.5/88.5/92.3/96.1/96.2 -> net of
rebates 92.0/91.4/93.3/96.2/95.9; federal 98.1/97.7/97.6/98.7/98.7.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant