Repository navigation
Count each EITC child split once in the Table 2.5 uprating source total - #1227
Merged
Merged
Conversation
_eitc_source_decomposition_total_for_bounds summed every Table 2.5 by-children row inside the uprating group. For the all-AGI group that is each split's 28 AGI bins and its total row, so the source EITC was counted twice and the four all-AGI total rows compiled at half their value (factors 0.5209 amount, 0.4877 returns on the pinned feed). Count only each split's outermost contained rows, and refuse a split whose AGI rows cross. Adds example tests, Hypothesis properties over synthetic decompositions (conservation, child-split preservation, totals equal their bins under uniform growth) and a pinned-feed check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Doubling the eight Table 2.5 EITC child total rows moves the pinned-feed national_state registry from e1f9906bf0e0 to 3fad14f85468 (full: f5bd921d6b21 to c3aaea9c1e8c). Target counts are unchanged: 33,250 compiled, 6,102 national_state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 12, 2026
…#1235 review) Round 1 of the independent review found two majors. A group with no EITC in either year made the per-row uprating fall back to the all-returns total for its bins, and the plan's per-row index check then skipped the whole rake. And plain IPF capped at 10,000 sweeps refused feasible, ill-conditioned margins. - _eitc_rake_plan decides from structure: one all-AGI total row per split, leaf bins tiling AGI, and an AGI group for the totals and every bin. An empty group takes a zero factor; a group with active EITC but no source EITC is refused. - _rake_two_margins checks exactly whether a positive scaling exists (Menon/Brualdi) and refuses with a specific message if not. It then finds the IPF solution by damped Newton steps on the convex dual, pinning each block's largest column with a Jacobi-scaled solve, and finishes with exact IPF sweeps. Rows hold to rounding, columns to 1e-12. - The bin adjustment is relative to the recorded per-row group factor, so it stays consistent beside rounded published subtotals. - The per-row AGI metadata moves into _eitc_agi_uprating_metadata, unchanged for #1227's rows. - The plan uses an _EitcRow NamedTuple and the solver annotates its nested functions; the spine-blindness check had failed on lambda row: row[1:]. - New tests: the review's counterexamples, the empty and refused groups, the rounded-subtotal adjustment, a Hypothesis property against a scipy linprog feasibility oracle, and positive seeds spanning ten orders of magnitude. - Experiments: option (b) records the factor its new total implies; results regenerated; README separates pairs from runs, qualifies the level gap (TY2018 amount) and states the bin-level tradeoff. national_state 31bd18096d33 -> 1aafec44dbfa (values move in the last bits; the adjustment metadata changed); full ac32014f3325 -> ec807d77a746. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The overlap test now also covers two rows of one split with identical bounds, which the strict-containment rule must keep from nesting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
October 13, 2026 00:25
Contributor
Author
|
Merged at head Merge gates
Review
Effect
Open follow-ups
🤖 Generated with Claude Code |
Contributor
Author
|
Post-merge independent review at
Follow-up: #1274 commits the real TY2023 Table 2.5 and TY2024 filing-season rows as a fixture. It checks this fix in CI against IRS-published EITC. 🤖 Generated with Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
_uprate_cross_period_eitc_decompositionsscales the stale SOI Table 2.5 EITC-by-AGI-and-children rows (TY2023) to the TY2024 filing-season EITC by AGI. The factor is (active EITC in the row's AGI group) / (TY2023 EITC in that group, summed over child splits).Each child split's record set carries 28 AGI bins and an all-AGI total row that sums them.
_eitc_source_decomposition_total_for_boundsadded every row inside the group. For the all-AGI total rows, that group is (-inf, inf), so the sum took each split's bins and its total row. The source EITC was counted twice and the four splits' total rows shipped at half their value.Lane D of the CD concept sweep reported this (2026-09-27). It is reproduced here on the pinned feed
consumer_facts_us_51aa40f.jsonl(sha256 965a29ac…) with a release-equivalent compile:target_period=2024, the packaged CD crosswalk,age_targets=Trueandallow_unaged_dollar_targets=False;_select_target_surface.The fix
The source sum now groups contained rows by record set, one per child split. Per split it keeps only the outermost contained rows, those not inside another contained row of that split. A split whose kept rows overlap (crossing or duplicated AGI rows) raises
ValueErrorrather than guessing.Effect on national_state and full targets
All 232 Table 2.5 by-children rows are on national_state, so also on full. A whole-registry differential compiles the pinned feed with and without the fix in one process (
differential.json).uprating_factormetadata changes with them. No other target's value or metadata moves.test_pinned_feed_national_state_surface_restores_the_fences.Invariants
These hold for every decomposition whose bins tile AGI, whose total rows equal their bins, and whose active filing-season AGI bins coarsen the Table 2.5 bins.
Intended non-identity. With non-uniform growth, a split's total row and the sum of its bins differ by design: the total keeps the all-AGI child mix, while each bin keeps its own group's. On the pinned feed:
Reconciling the two levels (for example, raking the child × AGI matrix to both margins) is a methodology question, not part of this fix. It is proposed as a follow-up.
Tests
test_us_eitc_decomposition_uprating.py(new):compile_us_fiscal_target_registry: invariants 1-3, and invariant 4.test_pinned_feed_eitc_child_total_rows_count_each_split_oncepins the factors and checks both conservation identities on the pinned feed. Like the other pinned-feed tests it skips where the feed is absent, as in CI, and was run locally: 27 passed and none skipped across the new file,test_us_fiscal_targets.py -k 'eitc or pinned_feed'andtest_us_fiscal_refresh_builder.py -k eitc.lower=Noneso that a syntheticunder_1row can carry no lower AGI bound, as the feed's does.Review
Independent review: GPT-6.1 Sol (
subfleet run --task review --tier hard, job 20261012-102546-eitc-decomp-1227-review) gave APPROVE atf44d26eea. The reviewer checked the arithmetic against the raw feed and the artifacts, and probed the extracted helpers; its own test run stalled on imports, so the 27-test run is author evidence.Its two non-blocking notes:
_eitc_source_decomposition_totals. No current producer emits that shape: the feed scope has only the four split record sets per year. An existing synthetic test uses an all-children set alone, so a guard would need that test's fixture reshaped. It is left as a known limit of the producer contract.origin/main (977ac98) is merged in. The pinned-feed tests were re-run on the merged tree: 28 passed, none skipped, including the pinned-feed version pin 3fad14f85468. Main moved no US target.
axiom: n/a: microsim target-compilation fix (no policy encoding)
🤖 Generated with Claude Code