PolicyEngine / PolicyEngine/microcosm
Period-aware transformation needed for SOI EITC-by-AGI calibration targets
@MaxGhenis is already working on this.
Since Jun 18, 2026.
- Dominant language
- Python
- Stars
- 0
- Forks
- 4
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 94
Description
Problem
The 2024 Populace calibration appears to include IRS SOI TY2022 EITC-by-AGI/qualifying-child targets as hard 2024 calibration targets without re-expressing the source-period target surface for the 2024 target period.
One concrete bad target from populace-us-2024-incumbent-improved-996401a-20260618:
irs_soi.ty2022.table_2_5.eitc_by_agi_children.one_qualifying_child.under_1.eitc_total@2024- Source period:
2022 - Target period:
2024 - Target:
$62.88M - Final estimate:
$407.67M - Final relative error:
+548.3%
A stronger signal is the sibling one-child 50k_plus rows:
- TY2022 Ledger target for one-child
50k_plusEITC returns/amount is0 - 2024 model estimate is about
918.7Kreturns and$274.7M
This is consistent with nominal 2022 AGI bins and 2022-law/source distributions being evaluated against a 2024 PolicyEngine simulation, where EITC thresholds and filing behavior are period-sensitive.
Why this looks like a Populus target-compilation issue
Current code appears to carry period metadata and literal source constraints through to materialization, but not transform the target value or bucket thresholds:
compile_us_fiscal_target_registrychooses the latest eligible Ledger fact at or before the target period.- SOI references set
source_period,target_period,agi_lower_bound, andagi_upper_boundmetadata. target_spec_from_ledger_referenceuses the raw Ledger fact value asTargetSpec.value._agi_boundscopies AGI constraints directly from Ledger as float strings.- The fiscal materializer then applies those literal AGI bounds to the 2024 simulation.
Relevant code paths:
packages/populace-build/src/populace/build/us/fiscal_targets.py::_soi_reference_from_factpackages/populace-build/src/populace/build/us/fiscal_targets.py::_agi_boundspackages/populace-build/src/populace/build/ledger_targets.py::target_spec_from_ledger_referencetools/build_us_fiscal_refresh_release.py::_materialize_target_frame
The manifest also currently allows only identity value resolution from Ledger facts, so the diagnostics artifact's compiled_target remains the raw source fact value.
Expected behavior
For period-sensitive nominal bucket targets, Populus should not silently calibrate a 2024 model to an untransformed TY2022 target surface.
Possible acceptable fixes:
- Transform source-period targets to target-period semantics before calibration, including both value and nominal income-bin thresholds where appropriate.
- Evaluate these targets at the source period instead of the target period.
- Mark/source-period-specific EITC-by-AGI facts as diagnostics-only unless a declared transformation exists.
- Add a compile-time gate requiring explicit transformation metadata when
source_period != target_periodfor nominal income-bucketed targets.
Acceptance criteria
- SOI EITC-by-AGI/qualifying-child targets with
source_period != target_periodhave explicit transformation metadata, or are excluded/downgraded from hard calibration. - Diagnostics artifacts expose enough information to verify the transformation: source period, target period, original fact value, compiled target value, original bucket bounds, compiled bucket bounds, and transformation method.
- The one-child
50k_plusEITC rows are no longer hard-calibrated to a 2022 zero target in a 2024 build unless that is explicitly justified by transformation metadata. - Add tests covering dynamic SOI EITC target compilation across source and target periods.
Notes
This does not look like a dashboard formatting issue or a simple missing child-count filter. The EITC child-count filter is present in the fiscal materializer, and aggregate one-child EITC return counts are close overall. The largest miss appears concentrated in AGI-bin distribution, which points to period/bucket alignment.
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.
Assessment
This issue has not been assessed yet.