PolicyEngine / PolicyEngine/calibration-diagnostics
Expand JCT target coverage: JCX-45-25 vintage + RCC-relevant lines (CTC/EITC/CDCC/ALD/OBBBA)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 4
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 13
Description
Context
We just finished a scoring validation pass on the 9 refundable-credit-conversion repeal toggles (CTC, EITC, CDCC, standard deduction, itemized, ALD, OBBBA bundle, §199A QBI, head-of-household) against JCT JCX-45-25 and JCX-22-25R. We pulled the populace-us release on Hugging Face (populace-us-2024-f0d2ef6-09292aa0d5db-20260617T032307Z) hoping the target surface could anchor the validation, and ran into two issues worth raising here.
What the target surface covers today
| Family | n targets | Vintage | Lines |
|---|---|---|---|
jct |
5 | JCX-48-24 (CY2024) | SALT, mortgage interest, charitable, medical, §199A QBI |
irs_soi |
4,748 | TY2020/2022 | Income components, EITC/CTC/ACTC/QBI deduction lines, filing-status slices |
cbo |
5 | Feb 2026 | AGI projections by source |
state_income_tax, ssa, cms_*, tanf, snap |
339 | various | not RCC-relevant |
Issue 1 — JCT family uses JCX-48-24, not JCX-45-25
The latest JCT tax-expenditure document is JCX-45-25 (Estimates of Federal Tax Expenditures for Fiscal Years 2025-2029, Dec 2025). The repo's jct family still anchors on the earlier JCX-48-24 at CY2024. The two disagree on every line (different fiscal-year window, post-OBBBA mortgage interest is $53.0B in JCX-45-25 vs $24.8B in JCX-48-24, etc.), and downstream consumers validating against the newer vintage end up double-checking which JCT cell they're matching against.
Proposal: load JCX-45-25 alongside JCX-48-24 (or replace it). FY2026 and FY2027 are the cells we need most for OBBBA-era scoring.
Issue 2 — Five-line jct family is too narrow for tax-expenditure validation
Today the JCT family covers SALT, mortgage interest, charitable, medical, and §199A. For RCC validation we hit gaps on:
| Toggle | Why no benchmark |
|---|---|
| CTC | no CTC/ACTC line in jct family |
| EITC | no EITC line in jct family |
| CDCC | no §21 / §129 line |
| Standard deduction | JCT excludes from tax-expenditure framing |
| ALD (above-the-line) | no traditional IRA, HSA, student loan, SE-health, SE-pension, educator |
| OBBBA bundle | no tip exclusion, overtime exclusion, senior bonus, SALT cap raise |
Proposal: add JCT tax-expenditure lines for at least the refundable credits (CTC/ACTC, EITC, CDCC) and above-the-line deductions JCT does score (traditional IRA, SE-pension, SE-health, HSA, SLID, educator). For OBBBA, the natural source is JCX-22-25R (Estimated Revenue Effects of the OBBBA) — that's the document we used in PR #48.
Issue 3 — Residuals on the 5 JCT lines we do have are eye-catching
name |
target | final_estimate | relative_error |
|---|---|---|---|
jct...salt_deduction.revenue_loss |
$21.7B | $5.9B | -72.7% |
jct...medical_expense_deduction.revenue_loss |
$11.4B | $0.6B | -94.8% |
jct...charitable_deduction.revenue_loss |
$60.4B | $32.5B | -46.1% |
jct...deductible_mortgage_interest.revenue_loss |
$24.8B | $11.4B | -54.1% |
jct...qualified_business_income_deduction.revenue_loss |
$63.1B | $11.8B | -81.2% |
(Aggregate fit is 94.65% within 10%, so these tax-expenditure lines are sitting in the long tail.) Interestingly the toggle revenue impact in PE-US comes out reasonably close to JCX-45-25 on these (e.g. QBI -19%), suggesting microsim formulas are compensating for the under-represented base. Worth a separate look at whether these targets are getting enough calibration pressure.
What this would enable
With JCX-45-25 + CTC/EITC/CDCC/ALD/OBBBA lines loaded, the surface becomes a one-stop validation source for the RCC project (and any subsequent reform-modeling work scoring against JCT). Today we hand-transcribe ~25 JCT cells per validation run; tomorrow we could join PE-US output against a single JSON.
Cross-reference
- PolicyEngine/refundable-credit-conversion#48 — the validation effort that surfaced these gaps
scripts/scoring_validation/comparison.csv(in that PR) — columnpopulace_calibration_residualnow reports the 5 existing JCT residuals plus SOI residuals for CTC/EITC/QBIscripts/scoring_validation/pull_calibration_residuals.py— pulls the residuals from this surface
Happy to write up the JCX-45-25 table parsing if it helps.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with scripts/scoring_validation/pull_calibration_residuals.py and scripts/scoring_validation/comparison.csv, then review the existing jct target surface against PR #48 and the JCX documents named here. Add JCX-45-25 coverage and the proposed CTC/ACTC, EITC, CDCC, above-the-line, and OBBBA lines, preserving or intentionally replacing JCX-48-24. Done means the targets are available in one JSON surface and residual comparisons no longer require hand-transcription.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data, testing-qa
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100