Skip to content

Three-pass --disable-salt to align PE federal SALT with TAXSIM-35#934

Merged
PavelMakarchuk merged 4 commits into
mainfrom
two-pass-disable-salt
May 28, 2026
Merged

Three-pass --disable-salt to align PE federal SALT with TAXSIM-35#934
PavelMakarchuk merged 4 commits into
mainfrom
two-pass-disable-salt

Conversation

@PavelMakarchuk
Copy link
Copy Markdown
Collaborator

Summary

Run PE in two Microsim passes when --disable-salt is set, so federal Schedule A keeps state income tax SALT (matching TAXSIM's single-pass methodology) while state-side computation remains SALT-disabled (existing intent).

Background

--disable-salt was added so PE-US state-tax computation could converge without iterating against federal SALT, matching TAXSIM-35's missing state↔federal SALT iteration. The single-pass implementation zeroed state_and_local_sales_or_income_tax globally, which also stripped state income tax from PE's federal Schedule A — producing a systematic federal mismatch against TAXSIM. In the 3K eCPS 2025 sample, ~90 records (more than half of post-otherprop realistic federal mismatches) traced to this.

Mechanism

  • Pass A — state-side: state_and_local_sales_or_income_tax = 0, producing state outputs that match TAXSIM's first-pass state tax
  • Pass B — federal-side: state_and_local_sales_or_income_tax explicitly set to Pass-A's per-record state_income_tax, so PE federal Schedule A uses a fixed SALT value (no iteration), mirroring TAXSIM exactly
  • Stitch: state-side columns (siitax, v32–v44, staxbc, etc.) from Pass A, everything else from Pass B

Impact on 3K eCPS 2025 (|AGI|<$500K, no S-Corp realistic subset)

Metric Pre Post
Federal exact 89.8% 91.1%
Federal within $100 93.1% 95.5%
Federal within $1K 97.9% 98.9%
State exact 79.1% 79.2% (no regression)

Headline 3K (with $15 tolerance): federal 72.9% → 74.2% (+38 records).

Runtime

  • 100-record run: 20s → 21s (~5% wall time, negligible)
  • 3K-record run: 77s → 74s wall time (essentially equal); user CPU +22% (40s → 49s)
  • Microsim setup dominates per-invocation cost; second pass is incremental, not a doubling

Test plan

  • 4 new three-pass tests in tests/test_three_pass_disable_salt.py (federal SALT uses Pass-A state tax; idempotent; no-flag pass unchanged)
  • Full suite 121/121 pass
  • CI passes

`--disable-salt` was added so PE-US state-tax computation could converge
without iterating against federal SALT, matching TAXSIM-35's missing
state↔federal SALT iteration. The single-pass implementation zeroed
`state_and_local_sales_or_income_tax` globally, which also stripped state
income tax from PE's federal Schedule A — producing a systematic federal
mismatch against TAXSIM (~90+ records in the 3K eCPS sample, median gap
$200-$2,400).

This change runs PE in two PE-Microsim invocations when the flag is set:

  Pass A — state-side: state_and_local_sales_or_income_tax = 0,
    producing state outputs that match TAXSIM's first-pass state tax.
  Pass B — federal-side: state_and_local_sales_or_income_tax explicitly
    set to Pass-A's per-record state_income_tax, so PE federal Schedule A
    uses a fixed SALT value (no iteration), mirroring TAXSIM exactly.

Final result stitches state-side columns (siitax, v32-v44, etc.) from
Pass A and everything else from Pass B.

3K eCPS 2025 sample (|AGI|<$500K, no S-Corp), pre/post:
- Federal exact match:    89.8% → 91.1%
- Federal within $100:    93.1% → 95.5%
- Federal within $1K:     97.9% → 98.9%
- State match: unchanged

Runtime: ~22% more CPU, ~5% more wall time on the 3K case (Microsim
setup dominates).

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

vercel Bot commented May 28, 2026

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

Project Deployment Actions Updated (UTC)
policyengine-taxsim Ready Ready Preview, Comment May 28, 2026 5:14am

Request Review

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`test_extract_does_not_iterate_states` enforces a ceiling on
`_calc_tax_unit()` calls to catch regressions where state vars
iterate per-state. With three-pass `--disable-salt` the runner
invokes PE twice, doubling the expected count from ~85 to ~170.
Raise the assertion ceiling from <100 to <200; per-state iteration
would still be 470+ calls, so the regression guard still bites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`test_benchmark_500_records` and `test_benchmark_cps_like` use
`disable_salt=True`, which now invokes PE twice. Wall-time roughly
doubles. Raise the ceilings from 60s/120s to 120s/240s respectively.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@PavelMakarchuk PavelMakarchuk merged commit 43768f9 into main May 28, 2026
12 checks passed
@PavelMakarchuk PavelMakarchuk deleted the two-pass-disable-salt branch May 28, 2026 05:45
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