Repository navigation
Fill CBO total AGI for 2015-2018 with IRS SOI actuals - #10114
Conversation
calibration.gov.cbo.income_by_source.adjusted_gross_income had a 2015 value of $9.03T, cited to a Tax Foundation page whose table is tax-year 2013 AGI excluding dependent filers, and no values for 2016-2018, so the series and its per-capita sibling (the default uprating index for dollar inputs) held that figure through 2018 and then jumped 31.7% into 2019. Replace 2015 and add 2016-2018 with IRS SOI Publication 1304 Table 1.1, all returns, adjusted gross income less deficit: $10.210T, $10.226T, $11.010T and $11.643T. CBO values from 2019 on are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CBO AGI total, which every dollar input without its own series follows per capita, must have a value for every year from its first to its last: a missing year holds the previous value, so the per-capita index drifts down with population and then jumps. The check fails on main (2016-2018 missing) and passes with the SOI fill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The node description now says the by-source series are CBO's, with SOI actuals for total AGI in 2015-2018. The changelog also covers inputs projected to a year within 2016-2018, which the old flat series grew up to 12% too little. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The CI run on this pull request was cancelled at 23:27Z on 2026-10-11 to free the organization's shared GitHub runners for an urgent fix in another repository. The US + core hub will re-run it automatically (cancelled jobs only; jobs that had passed are kept). Nothing in this pull request changed. Please don't push or reopen just to restart CI. |
PR Review: Fill CBO total AGI for 2015-2018 with IRS SOI actualsPR #10114 (author: MaxGhenis, head SummaryThe PR fixes the early years of
The data change itself is correct:
One blocking problem comes from timing:
Critical (must fix)1. Once merged with
Should address1. The changelog and the PR body's test-impact analysis predate #10106.
Suggestions
Verified correct
Axiom line assessmentValid
CI statusAll 26 checks pass (
Branch status
Verdict: REQUEST_CHANGES |
DTrim99
left a comment
There was a problem hiding this comment.
All four values match SOI Table 1.1 exactly, and the splice into CBO is smooth. One critical (details in the comment above): #10106, merged 10/12, deflates IRMAA two-year-lookback MAGI by this series, so merged with main the PR breaks three of its expectations (two_years_prior.yaml:33 and :91, senior_household_2015_2016_integration.yaml:56), and the medicare_irmaa_magi_two_years_prior docstring and index comments become false. Please merge main and update them. One should item: the changelog and PR body should state the IRMAA lookback effect (2019 factor 0.765 → 0.932, 2020 0.721 → 0.929).
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Main now has #10106, whose IRMAA two-year lookback deflates income by the per-capita CBO AGI series this branch fills for 2015-2018, so the branch must be tested against it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The IRMAA two-year lookback from #10106 deflates benefit-year income by the per-capita AGI index this branch fills for 2015-2018, so its 2016 cases move (500,000 -> 503,654.40, 100,000 -> 100,730.88, 10,000 -> 10,073.09) and the docstring's account of the 2016-2018 gap no longer holds. New 2018 and 2019 benefit-year cases pin the largest moves, where the deflator went from 1.014 to 0.890 and from 0.765 to 0.932. The changelog now states the lookback effect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Household cases show a default-uprated input crossing the SOI-to-CBO splice (2018 to 2019: x1.0218, was x1.3170) and staying inside the SOI years (2015 to 2018: x1.1149, was x0.9777). Property tests check that an input moves by the index ratio for any pair of years from 2015 to 2036, and that the index never moves more than 25% in a year, which a missing year would break (the 2016-2018 gap made 2018 to 2019 +31.7%). The guard docstring now names the IRMAA lookback as a reader of the series. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An independent review found that the comments on the old IRMAA and donation results said the index was held at its 2015 value. It was the total that was held, so the per-capita index fell with population, which is what the quoted numbers reflect. The module comment and changelog now say the index is SOI for 2015-2018 and that only inputs on the default series were affected, and the guard docstring separates the gap's share of the error (14%, 0.864) from the wrong 2015 level's. The Hypothesis file computed its expected factor from the same parameter core reads, so it passed on main as well, and its 25% bound does not detect a gap once the 2015 level is right. The guard and the hand-computed YAML cases cover what it claimed, so it is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Per-capita AGI fell from 2015 to 2016, so for a household entered for 2016 alone the lookback multiplies income by about 1.007. "Deflated" read as a reduction; the docstring now says the result is slightly more than that year's income, and why. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Picking this up for the US hub. I'm continuing an earlier session's work on this PR, which stopped before its hand-off; its five commits from Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Picking this up for the US hub. I'm continuing earlier sessions' work on this PR: the five commits from Generated by Claude Code |
|
Ready for hub review Head: This continues two earlier sessions on this brief. The first pushed Earlier commits: checked and kept
The review from DTrim99 (2026-10-13), item by item
Hand computationsThese use the PR's AGI totals and Per-capita index, main → this PR:
Expected values:
Source values
Code claims re-read here
Tests (local, one file per process)
Mutants (each in its own process; the file was restored after each)
#10128 guard check (scratch merge, not pushed)
Overlap with #10132 (not touched)
CIPush at 20:41Z. The Pull request run at Judgment calls
Proposed follow-upNone. impact: the hub will measure Generated by Claude Code |
|
Hub review in progress Superseded: the full review is posted below as a separate comment that starts Ready for hub review (verdict APPROVE at Generated by Claude Code |
|
Ready for hub review This is an independent review of the head above, which is unchanged since the hand-off. Main has moved four commits past the merged No P1 or P2 findings. The data are right and every hand value reproduces. The defect reproduces at current main. Every changed test passes, and each mutant is killed. The P3 items below are optional. FindingsP3-1. The guard can't see a missing first year or a wrong value
P3-2. "Within 0.04%" is a rounding of 0.041%
P3-3 (follow-up, the same on main). Part B and Part D IRMAA brackets for years before 2024 are backdated 2024 values
Checked and soundSources.
Hand values. I computed these in plain Python from the SOI totals above and
The defect reproduces at current main ( Main's outputs are exactly the body's "main gave" values. The new guard fails on main: Tests at the head, one file per process. Commands were
Each new or changed case asserts the hand-computed value itself, not a weaker bound. The cases span benefit years 2016, 2018 and 2019, and reads across 2015→2018 and 2018→2019, so both the SOI years and the SOI-to-CBO splice are pinned. Mutants. Each ran on a scratch edit, and I checked
Readers of
DTrim99's review (2026-10-13), item by item, at the head.
#10128 (head
#10132 (head
CI. The Pull request run 41714937303 at Scope. No file under Body and docs.
Effect at baseline.
Methodology. The PR splices SOI actuals onto CBO's projection for a calibration series. No statute, regulation or legal reading is involved, so The brief against the PR. The build brief asked for Hypothesis property tests for logic with outputs people rely on. The PR has none, and the body gives the reason: the change is data and the guard enumerates every year. I accept that. The brief also asked the build to check every SOI value against the table. The build couldn't reach irs.gov, and the hub's read now covers 2015-2019. What I couldn't check
Generated by Claude Code |
Round 1 of the hub review approved this PR, and these changes answer this review: main merged in; the three IRMAA expectations updated (medicare_irmaa_magi_two_years_prior.yaml Cases 2 and 7, senior_household_2015_2016_integration.yaml Case 2); the docstring and index comments updated. The changelog and PR body now state the lookback effect (2019 factor 0.765 → 0.932, 2020 factor 0.721 → 0.929).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
US + core hub merge audit, us#10114 at
🤖 Generated with Claude Code |
What changes
This PR sets
calibration.gov.cbo.income_by_source.adjusted_gross_income(total AGI) to IRS Statistics of Income actuals for 2015-2018. Its per-capita sibling,adjusted_gross_income_per_capita(total ÷calibration.gov.census.populations.total), uprates dollar inputs that have no series of their own and deflates income for Medicare IRMAA's two-year lookback.Each value takes the "All returns" row's "Adjusted gross income less deficit" amount and converts the table's thousands of dollars to dollars. Each parameter value cites its own tax year's workbook.
Why
Main's 2015 value comes from a Tax Foundation page whose Table 1 reports tax-year 2013 AGI on returns that exclude dependent filers. SOI reports 9,093,628,703 thousand for all returns in tax year 2013 (13in11si.xls) and 10,210,310,102 thousand for 2015. Main has no values for 2016-2018, so the parameter holds that 2015 value through 2018, and the per-capita index drifts down with population and then jumps 31.7% into 2019. The model therefore uprates a dollar input dated 2018 or earlier past the gap by the wrong factor. The gap and the wrong 2015 level each account for part of the jump: with the right 2015 total and the gap left in, the index would still rise 16.5% from 2018 to 2019.
SOI's tax-year 2019 total, 11,966,873,976 thousand (19in11si.xls), exceeds the series' CBO 2019 value of 11,962,000,000,000 by about 0.04%, so the series moves onto CBO's values nearly level.
Effect
Parameters
A dump of every leaf parameter after system init, at main (
abc67b98de) and at this branch, differs only in the AGI total and its per-capita sibling, at 2015-2018. Both series keep main's year-on-year ratios from 2019 on, and the map from variables to series doesn't change.Household inputs on the default series
policyengine-core multiplies an uprated input by index(target) ÷ index(source), using the latest earlier input, and holds the index at its first value before the index begins (
_uprating_index_valueinpolicyengine_core/simulations/simulation.py). On main, an input dated 2018 or earlier and read in 2019 or later exceeds this PR's result by index_new(source) ÷ index_old(source) − 1:Inside 2016-2018, main's factors fall short of this PR's by up to 12%. For example, main multiplies an input dated 2015 and read in 2018 by 0.978, and this PR multiplies it by 1.115.
Medicare IRMAA lookback
medicare_irmaa_magi_two_years_priorgives a household with inputs only for benefit year Y that year's MAGI times index(Y−2) ÷ index(Y), with the index held at its 2015 value before 2015:Dataset extension
extend_single_year_datasetgrows each year from the dataset's base year forward, so a dataset based in 2019 or later reads none of the changed values.impact: none on the default dataset from 2021 on. It holds 2024 records, so its inputs read the series from 2024 on, and the IRMAA lookback factors match main's from benefit year 2021. For household calculations, the PR changes inputs dated 2018 or earlier and lookback factors for benefit years 2016-2020. The default dataset holds no data from before 2024, so we report no aggregate for those years.
Tests
We computed expected values by hand from the SOI totals above and the population series, not from the model.
medicare_irmaa_magi_two_years_prior.yaml: Case 2 (500,000 → 503,654.40) and Case 7 (100,000 → 100,730.88) move. New Case 8 pins the 2018 benefit year (500,000 → 445,217.19; main gave 506,932.37). New Case 9 pins the 2019 benefit year (500,000 → 465,924.93; main gave 382,300.59).senior_household_2015_2016_integration.yaml: Case 2 moves (10,000 → 10,073.09).household/expense/charitable/charitable_cash_donations.yaml(new): the model multiplies a 2018 input read in 2019 by 1.0218 (main 1.3170) and a 2015 input read in 2018 by 1.1149 (main 0.9777).tests/core/test_uprating_series.py::test_default_series_has_a_value_for_every_year: the default series has a January 1 value for every year from its first to its last. It fails on main (2016-2018 missing).e0ba755386(https://github.com/PolicyEngine/policyengine-us/actions/runs/41984504030), concluded success: all 36 jobs passed.Invariants
test_every_per_capita_series_is_its_total_over_populationchecks this.This PR adds no Hypothesis test: it changes data and no logic, and invariant 1 ranges over a finite set of years, so the guard enumerates them. A simulation property test would compute its expected factor from the same parameter core reads, and it would pass on main too.
Overlap with open PRs
tests/core/test_uprating_series.py, and git merges them without conflict. Once both land, deletetest_default_series_has_a_value_for_every_year, which repeats Fill IRS SOI uprating series gaps with Publication 1304 actuals #10128's guard case for CBO AGI.test_series_has_a_january_value_for_every_yearto that file, covering this PR's series, and git merges those edits without conflict.medicare_irmaa_magi_two_years_prior.yamland this PR's index, so Case 7 expects 80,584.71.axiom: n/a: this PR corrects historical AGI calibration data and the uprating and income estimates built on it. In the Medicare IRMAA variable it changes only comments and documentation, and the revised test expectations follow the corrected index.
🤖 Generated with Claude Code