Repository navigation
Add 2015-2023 Medicare IRMAA brackets and 2015-2020 Part B premiums - #10112
Conversation
The Part B and Part D income-related monthly adjustment schedules started in 2024, so the backdating floor applied 2024 thresholds and amounts to benefit years 2015-2023, and the standard Part B premium applied its 2021 value to 2015-2020. Encode each year's schedule from the Federal Register Part B premium notices and CMS's Part D income-related adjustment releases: thresholds frozen through 2017, the MACRA brackets for 2018, the 85% tier from 2019 and CPI-U indexing from 2020, with the shorter married-filing-separately schedule (a single tier in 2018). Add YAML tests for every tier boundary in 2015-2023 and property tests for the statutory structure (ordering, joint and separate schedules, Part B adjustments relative to the standard premium, Part D tier proportions). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Brings the branch up to date with 513 commits on main. Main has since dropped the stale Illinois AABD entry from the person-adds ratchet (#10092), which was the only failing check on this branch, and merged the IRMAA lookback fallback (#10106), whose test comment this branch now makes stale. The merge had no conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each title now gives the page of the notice that prints the table it sources, not just the notice's first page, and the Part D files cite the same Part B tables for their thresholds, which 42 U.S.C. 1395w-113(a)(7)(A) takes from 1395r(i). The base premium file also cites the 2021-2023 notices, which state the standard premiums already in it. Every value cited was checked against the text of these pages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A reviewer can check each expected value against one page: the Federal Register table for Part B and the standard premium, and the CMS memo or fact sheet table for Part D. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lookback test's comment said years before 2024 are backdated from 2024, which stops being true once these brackets land, so its monotonicity and zero-below-threshold properties now draw from 2015-2026. They keep 25 examples each, so this adds no run time. Each schedule property also states the provision it checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Picking this up for the US hub. I continue an earlier session's work on this PR: that session stopped before it could hand off, and I will check each of its commits before building on it. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
|
Picking this up for the US hub. I continue an earlier session's work on this PR, checking each of its commits before building on them. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Main's #10106 cases 6 and 7 assert no IRMAA for a $100,000 MAGI in 2015 and 2016. They were written when 2015-2023 read the backdated 2024 schedule, whose first threshold is $103,001. With this branch's schedules, 2015 and 2016 use the $85,000 threshold that 42 U.S.C. 1395r(i)(6) holds at its 2010 level, so $100,000 lands in the 65 percent tier and both cases failed in CI. The cases test the lookback, not the tier, so lower the income to $80,000 to keep each name true: 2015 MAGI is 80,000 and 2016 MAGI deflates to 80,000 x 328,964 / 326,078 = 80,708.05, both below $85,000. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6KtJoHdqUJtpTYx4Z5
|
Ready for hub review Head: This continues an earlier session's work (it pushed Earlier session's commits
What the item asked1. The failing check: fixed
2. Every bracket and premium against the CMS notices, by script: blockedThe session's network policy denies govinfo.gov, federalregister.gov, cms.gov, ssa.gov, law.cornell.edu, uscode.house.gov and web.archive.org; only GitHub is reachable. I couldn't read any notice, memo, fact sheet or the statute, so I can't vouch for any value against its source. The PR body's 981-value comparison is the earlier session's, and I couldn't rerun it. What I could check is an independent structural script over the raw YAML (it doesn't use the model or the PR's tests). It checks 2015–2023, 210 checks:
All 210 pass. The amount checks:
For the hub: rerun the body's source comparison from a host that can reach govinfo.gov and cms.gov, or allow those hosts in the cloud environment's network settings (environment menu → Edit → Network access; https://code.claude.com/docs/en/cloud-environments#network-access). Tests run (one file per process)
CIThe Pull request run at this head, 41717469233, concluded success, with all 36 check runs passing. That includes "Baseline tests / Full Suite - Baseline (contrib-hhs)", the job that failed at MergeI merged main at Judgment calls
Overlapping PRs
Proposed follow-up issueModel the Part B hold-harmless premium for 2016–2017. impact: the hub will measure Generated by Claude Code |
|
Hub review in progress Reviewing head
Generated by Claude Code |
|
Ready for hub review Independent review, round 1. The head is the one the brief named. Nothing was pushed after Bottom line. The schedules are internally consistent. Every structural property I could derive holds. CI is green, the changed tests pass, and the body's main-vs-branch table reproduces. But no value in this PR has yet been checked against its Federal Register notice or CMS memo by a session that could read them: this session's network policy blocked every primary source, as it did for the author. The changes I ask for are small: a code comment this PR makes false, an overstated coverage claim in the body backed by a surviving mutant, and an undisclosed conflict with #10114. The source comparison still has to be run before landing. FindingsP2-1. The body says every tier boundary is covered, but no test pins the top MAGI of tiers 2 and up, and a mutant survives
Each case tests the first threshold itself (e.g. 85,000) and the lowest MAGI of each tier (X + 1). It never tests the highest MAGI of a tier above the first (X for "more than $X"). I parsed both files by script and listed every (year, status, threshold) the cases reach: Failure scenario. Suppose a "more than $107,000" threshold is stored as 107,000 instead of 107,001, consistently across the files. Then a MAGI of exactly $107,000 pays the 50 percent amount instead of the 35 percent one. Mutant M3 below does exactly this for 2017, tier 2, in Parts B and D (single, head of household, surviving spouse at 107,000; joint at 213,999). It survives every test: Replacement. In each year's single and joint case, add a person at X for each "more than $X" threshold above the first (e.g. 2017 single: 107,000, 160,000, 214,000; 2019: also 499,999 against the "at least $500,000" tier). Alternatively, change the body sentence to: "Each tier's lowest MAGI and the first threshold itself are covered; the highest MAGI of tiers 2 and up is not." P2-2. #10114 conflicts with this PR, and the body doesn't mention it
Under #10114, case 7's factor becomes 31,312.48 / 31,085.28 (#10114's own header values), not 27,704.54 / 27,461.49. So whichever PR lands second must use The other overlaps check out: #10103 conflicts in exactly the eight files the body names (re-run with P3-1. A main comment this PR makes false
# NOTE: gov.hhs.medicare.part_b.base_premium starts in 2021, so a
# person-paid Part B before 2021 reads the 2021 premium.After this PR, P3-2. The Part B property tolerance can't catch a dime-level transcription error; only the YAML cases do
For 2021, where every distance is 0, a $0.20 typo still passes. Mutant M4 shows this. The property file passes it, and only the YAML kills it: 2015 single 90,000 1782.0 0.0 | 1762.8 147.6 | 12×(104.90+42.00)=1762.80, 12×12.30=147.60 |
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 2015-2023 single and joint cases tested each tier's lowest MAGI (X + 1) but never X itself, so a "more than $X" bound stored as X survived every test. Add a person at each X above the first threshold, expecting the amount of the tier below, in Parts B and D. base_premium.yaml now starts in 2015, so the Medicaid comment saying it starts in 2021 is no longer true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: This round answers round 1's P2-1 and P3-1. It's built on Commits
Items1. Pick-up and merge. I posted the pick-up comment and merged main without conflicts. Afterwards I reran all eight files (see Tests). 2. Sources. No parameter value changed. I took every new expected amount from the monthly amount the case's own comments already list, so the new people use the same figures as the hub's checked tables. 3. P2-1: the highest MAGI of each tier above the first. In the 2015–2023 single and joint cases of both files, I added a person at X for each "more than $X" bound above the first, expecting the amount of the tier below. Each one has a comment line in the case's own style, e.g.
4. P3-1. I deleted the two-line MutantsEach mutant ran with one process per test file, at the new tests. After each, I restored the parameters with
Tests (one file per process, after the merge, on the head's content)
I installed CIPull request run 41856781101 at Judgment calls
Left for the hubThe PR body's Tests section (counts above), the Generated by Claude Code |
|
Hub review in progress Round 2 (delta) review of head
Generated by Claude Code |
|
Ready for hub review Independent review, round 2: a delta review from Bottom line. Round 1's P2-1 and P3-1 are fixed, and P2-2 and P3-2 are answered in the body. The 108 added people leave every existing MAGI, comment and value unchanged. Every tier top in 2015–2023 single and joint cases is now pinned in both files. M1, M2, M3, M6 and my own M7 all die, each at the person it targets. CI at the head is 36 of 36 FindingsP3-1. Deleting the Medicaid note creates a new conflict with #10634, which the body doesn't list
Failure scenario. Whoever merges second resolves the conflict by taking #10634's side. That keeps a note that is false once this PR lands. #10146 also conflicts in this file now (it deletes the same note itself, so taking either side drops it). #10146 already conflicts with main in Replacement. Add to the body's "Related" list:
P3-2 (follow-up, carried from round 1's P3-3; main does the same). The separate schedule applies to every separate filerUnchanged in this round. The round 2 checksThe 108 added peopleA script parsed every case in both files at
The 12 older Part D cases (2024–2026, in another form) are byte-identical. Each added person is a tier top, in a single or joint case, in the 35, 50 or 65 percent tier: for example, 2018 single 107,000 / 133,500 / 160,000 and 2023 joint 246,000 / 306,000 / 366,000. Coverage. For each 2015–2023 single and joint case, against each finite threshold t above zero in the case's own parameter file: Both t − 1 (the highest MAGI of the tier below) and t (the lowest MAGI of the tier) are present for all 82 thresholds in each file. That includes 499,999 and 749,999 from 2019. Those were already present at Tier tops by hand, two years in each file. Part B is the standard premium plus (p − 25) / 25 × the standard premium, rounded to the dime. Part D is the base beneficiary premium × (p − 25.5) / 25.5, rounded to the dime. Bases are the PR's: $104.90 and $148.50 for Part B, and $33.13 and $33.06 for Part D.
All twelve match. I couldn't read the printed tables (see below), so this confirms the arithmetic and the parameter values, not the notices. The deleted Medicaid comment (round 1's P3-1)Deleted at The body's new Tests sentencesEach one, checked by script against both files at the head:
The body's Related list now names #10114 and its case 7 value (round 1's P2-2). Overlap with #10114: case 7's value#10114 is still open and unmerged (head The rounded per-capita ratio gives 80,584.71 and the unrounded totals give 80,584.70. Both fall within the case's 0.01 margin. Case 6 stays at 80,000, because 2013 and 2015 both read the 2015 index value and the factor is exactly 1. Part D IRMAA stays 0, because 80,584.71 is not above $85,000. So the body's case 7 value is right. CIPull request run 41856781101 at Verify by running1. The defectRound 1 reproduced it at main, and this round changes no parameter or formula. The delta is tests and one comment, so I didn't rerun it. 2. The ruleThis round adds expectations only. The hand values above match the parameter files and the case comments. The formulas didn't change. 3. The tests, one file per process at the head
These match the hand-off's counts. The new people assert the claim itself: each sits exactly at X for "more than $X", and expects the lower tier's exact amount. 4. MutantsI ran each mutant on a scratch worktree at the head, one process per test file, and restored the files after each (
M3 and M7 pass the property file. So the new YAML people are the only guard against an off-by-one at a tier top, which is what P2-1 asked for. 5. ReadersThe delta changes no variable or parameter, so the readers are the ones round 1 listed. A grep at the head confirms them: 6. Docs and body
7. ScopeNothing under
Checked and sound
What I couldn't check
Generated by Claude Code |
Cases 6 and 7 keep the $80,000 MAGI below the 2015-2016 threshold, on the per-capita AGI deflator that main now uses. Case 7 expects 80,584.71. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
US + core hub merge audit, us#10112 at
🤖 Generated with Claude Code |
What and why
The Medicare IRMAA schedules (
gov.hhs.medicare.part_b.irmaa.*andgov.hhs.medicare.part_d.irmaa.*) had values only for 2024–2026, and the standard Part B premium (gov.hhs.medicare.part_b.base_premium) only from 2021. Onmain, every year from 2015 to 2023 reads the 2024 IRMAA schedule, and 2015–2020 read the 2021 standard premium of $148.50.This PR adds each year's schedule for 2015–2023 to all ten IRMAA files (Part B and Part D, each for single, joint, head of household, surviving spouse and separate filers) and the 2015–2020 standard Part B premium. It changes no 2024–2026 value.
Annual amounts for one Medicare enrollee, on
mainand on this branch. The branch values equal the published table amounts times 12:The schedule each year follows
42 U.S.C. 1395r(i) sets the Part B adjustments and thresholds:
As on main, a "more than $X" threshold takes the value X + 1, and an "at least $X" threshold takes X. A tier that did not exist yet has threshold
.infand repeats the amount of the tier below, so the schedule never falls. That covers the 85 percent tier before 2019 and the separate schedule's second tier in 2018.Sources, one per year
Part B. Thresholds, adjustments and standard premiums come from each year's Federal Register notice, "Medicare Part B Monthly Actuarial Rates, Premium Rate(s), and Annual Deductible". Each notice prints its tables three times; the links open the first printing. Each parameter file's reference titles now give these pages:
Part D. The Federal Register does not print the Part D adjustments. CMS publishes them in these memos and fact sheets, which also restate the thresholds. The Part D files cite them and, for the thresholds, the Part B tables above.
How we checked the values
We compared every threshold, adjustment and standard premium in the eleven files with the notices and CMS releases above, for each year from 2015 to 2026, and all 1,240 values match. We transcribed each table from the source text with a script (
pdftotext -layoutfor the PDFs) and applied the files' convention: X + 1 for "greater than $X" and X for "greater than or equal to $X". The.infplaceholder tiers have no printed row to compare. No later Federal Register document corrects any of these notices. The 2026 Trustees Report's Tables V.E3 and V.E4, which the IRMAA files also cite, list the same 2015–2023 adjustments.The provisions in the schedule section read as described in the 2024 edition of the U.S. Code (42 U.S.C. 1395r, 42 U.S.C. 1395w-113). Each reference's
#page=opens the page with its table or premium statement.A main test this branch makes stale
Main's #10106 added two lookback cases to
medicare_irmaa_magi_two_years_prior.yaml(cases 6 and 7) that assert no IRMAA for a single filer with a $100,000 MAGI in 2015 and 2016. At the time, those years read the backdated 2024 schedule, whose first tier starts at $103,001. Under this branch, 2015 and 2016 use the $85,000 threshold, so $100,000 falls in the 35 percent tier, and both cases failed CI. The cases test the lookback, not the tier, so they now use $80,000. The 2015 MAGI stays 80,000, and the lookback scales the 2016 MAGI to 80,000 × 328,964 / 326,078 = 80,708.05, so both stay below $85,000.Test plan
make format(ruff formatandruff checkon the changed Python files)changelog.d/(irmaa-historical-brackets.fixed.md)Tests
gross_medicare_part_b_premium.yamlhas 33 cases. Cases 6 and 7 ofmedicare_irmaa_magi_two_years_prior.yamlnow use a MAGI below the 2015–2016 threshold (see above).income_adjusted_part_d_premium_surcharge.yamlgains 33 cases andbase_part_b_premium.yamlsix. For 2015–2023 the cases reach the first threshold itself and each tier's lowest MAGI: all five filing statuses in 2016, 2019 and 2021, and single, joint and separate filers in the other years. The single and joint cases also reach each tier's highest MAGI. At each "more than $X" bound, a person whose MAGI equals $X pays the lower tier's amount. From 2019, a person $1 under the $500,000 bound ($750,000 joint) pays the 80 percent tier's amount. The cases include a MAGI of $2,000,000 before 2019, which must land in the 80 percent tier. Each case names its source table, with its page where the source has pages.test_irmaa_schedule_properties.pychecks the invariants below (560 cases), with one stated provision per property. The lookback test's monotonicity and zero-below-threshold Hypothesis properties now draw from 2015–2026, with the same number of examples.db993a8229(https://github.com/PolicyEngine/policyengine-us/actions/runs/42021620614), concluded success: all 36 jobs passed.Invariants
For every year from 2015 to 2035, both parts and every filing status:
+infbrackets, which come last;For the published years (2015–2026):
Not modeled
The hold-harmless provision. The 2016 notice says that with no cost-of-living adjustment "the majority of Part B enrollees can pay no increase in their monthly premium" (80 FR 70813). The 2017 notice says the $134.00 premium "will be paid by (or on behalf of) approximately 30 percent of beneficiaries" (81 FR 80067). The model charges every enrollee the standard premium, as before. Both notices say the provision doesn't cover beneficiaries who pay an income-related adjustment, so the model charges IRMAA payers the right amount.
Related
Fall back to the earliest input year's MAGI for Medicare IRMAA, and add a same-year income switch #10106 (merged). Its
test_irmaa_lookback_and_switch.pysaid years before 2024 take the 2024 values. This PR rewrites that comment and widensBRACKET_YEARS.Project Medicare premiums and IRMAA past the last announced year #10103 (open) overlaps without duplicating. It projects premiums and IRMAA after the last announced year. On top of this branch it conflicts in eight files:
amount:block undervalues:with upratingmetadata:(this branch adds 2015–2023 dates to the same blocks) and both add the 42 U.S.C. 1395r(i) reference;base_premium.yaml, where both insert references at the top of the list (Project Medicare premiums and IRMAA past the last announced year #10103 also adds uprating metadata);base_part_b_premium.yamlandincome_adjusted_part_d_premium_surcharge.yaml, where both append cases at the end.Whichever merges second keeps both sets of dates and cases and one statute reference.
Fill CBO total AGI for 2015-2018 with IRS SOI actuals #10114 (merged). It rewrote the deflator that cases 6 and 7 of
medicare_irmaa_magi_two_years_prior.yamlquote. This PR keeps its $80,000 MAGI on Fill CBO total AGI for 2015-2018 with IRS SOI actuals #10114's per-capita AGI, so case 7 expects 80,000 × 31,312.48 / 31,085.28 = 80,584.71, still below $85,000.Charge the Medicare Part B premium only to people who pay it #10634 (open) conflicts in
medicaid_optional_senior_or_disabled_countable_income.py, in comments only. This PR deletes the note thatbase_premiumstarts in 2021, and Charge the Medicare Part B premium only to people who pay it #10634 rewrites the comment above it. Whichever lands second keeps Charge the Medicare Part B premium only to people who pay it #10634's new comment and drops the note.Part A. Add 2015-2020 Medicare Part A premiums and 2015-2023 Part A deductibles #10117 (merged) added the matching 2015–2020 Part A premiums and 2015–2023 Part A deductibles.
impact: none from 2024 on. The PR adds values dated 2015 to 2023 and changes no 2024-2026 value, and
base_part_b_premium,gross_medicare_part_b_premiumandincome_adjusted_part_d_premium_surchargeread those parameters at their own period. For 2015-2023 the PR changes Part B premiums and Part D IRMAA in household calculations. The default dataset holds 2024 records and no earlier data, so we report no aggregate for those years.axiom: TheAxiomFoundation/rulespec-us#1677 queued
🤖 Generated with Claude Code