Skip to content

Model the Medicare Part D low-income subsidy as a CBO means-tested transfer - #10127

Draft
MaxGhenis wants to merge 12 commits into
cbo-medicare-net-of-premiumsfrom
medicare-part-d-lis
Draft

MaxGhenis wants to merge 12 commits into
cbo-medicare-net-of-premiumsfrom
medicare-part-d-lis

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

This PR builds on #10118, which builds on #10111 (#10107 merged on 2026-10-12). Once #10111 and #10118 merge, it retargets to main and merges it.

Summary

#10118 makes the default CBO household income count Medicare the way CBO does: net of premiums, and without the Part D low-income subsidy (LIS, "Extra Help"). CBO counts the LIS as a means-tested transfer instead. pe-us had no LIS variable, so after #10118, CBO income after transfers leaves out the LIS: about $18 billion in 2026, which #10118 takes out of Medicare at $255.86 per enrollee.

This PR models the LIS and counts it in two places:

  • gov.household.cbo_means_tested_transfers, CBO's means-tested transfers;
  • the household health benefit lists, gov.household.household_health_benefits and healthcare_benefit_value, beside medicaid_cost and msp_cost.

The model pieces:

  • part_d_lis_eligible covers Medicare enrollees in the 50 states and DC whom the law deems eligible or who pass the income and resource tests. Medicaid enrollees, SSI recipients and people eligible for a Medicare Savings Program count as deemed.
  • part_d_lis_enrolled pays only people in a Part D plan (medicare_part_d_enrolled, from Charge the Part D income-related premium only to Part D enrollees #10115). In a plan, Medicaid enrollees and SSI recipients get the subsidy automatically; other eligible people need takes_up_part_d_lis_if_eligible.
  • part_d_lis gives each enrollee the Medicare Trustees' average subsidy per LIS enrollee, CBO's measure: $1,254 in 2026.
  • Eight parameters under gov.hhs.medicare.part_d.low_income_subsidy, one calibration series (2013–2035), BLS's September 2026 CPI-U, a projection of the resource limits after 2026 in uprating_extensions.py, a programs.yaml entry, a take-up flag and a source-conflict candidate.

What changes:

  • household_net_income and household_benefits don't change. The health benefit lists reach them only when gov.simulation.include_health_benefits_in_net_income is on, and it's off by default.
  • healthcare_benefit_value, and so household_net_income_including_health_benefits, rise by the subsidy.
  • Neither list holds medicare_cost, whose spending per enrollee already includes all Part D spending, the LIS among it. So nothing counts twice.

In the 2026 microsimulation, 9.89 million people receive $12.40 billion. CBO income after transfers and taxes and healthcare_benefit_value each rise by that amount (see Impact).

Why an average, not a computed benefit

Most of the LIS is the cost-sharing subsidy. That depends on each enrollee's drug use, and pe-us has no Part D claims. The premium subsidy depends on the region's benchmark premium and the plan chosen. CBO values the LIS the same way for everyone:

  • Habib 2018, CBO Working Paper 2018-07, file page 46: "CBO removes LIS benefits from its total Medicare benefits and assigns them separately. ... A pool of eligible recipients is created by identifying Medicare recipients who also receive at least one means-tested transfer ... Recipients are chosen at random from that pool until the total LIS population is accounted for, and an average LIS benefit is assigned to each imputed recipient."
  • CBO, January 2026: "LIS benefits are assigned to some Medicare recipients who, CBO estimates, also receive other means-tested transfers." CBO allocates insurance at "the average resource cost, which is total spending divided by the number of recipients."

This PR keeps CBO's average but takes recipients from the law, not from CBO's pool. CBO draws recipients until their count matches the administrative total. The model pays every eligible person in a Part D plan who is on Medicaid or SSI or takes the subsidy up, so its count comes from the data (see Impact).

The Trustees publish the average directly: Table IV.B9's "Subsidy amount" per LIS enrollee. The series takes 2016–2035 from the 2026 report (file page 158), 2015 from the 2025 report and 2013–2014 from the 2023 report. Enrollment times the amount reproduces Table IV.B10's payments, for example 14.4 million × $1,254 = $18.1 billion in 2026.

Institutionalized enrollees. CBO removes institutionalized LIS recipients and their benefits (Habib 2018, file page 52). Its adjusted totals (file page 51) are:

Year CBO recipients CBO benefits CBO per recipient Trustees IV.B9 per enrollee
2015 10.7 million $22.6 billion $2,112 $2,112
2016 11.1 million $26.5 billion $2,387 $2,126

CBO's 2016 benefits come from its own baseline. Its recipient counts are 88–90% of the Trustees'. So the adjustment shows up mostly as fewer recipients, which the model's noninstitutional microdata already reflects.

Eligibility

Rule Source Code
Medicare enrollee, enrolled in a PDP or MA-PD 42 U.S.C. 1395w-114(a)(3)(A)(i); 42 CFR 423.773(a); 20 CFR 418.3101(b) defined_for = "medicare_enrolled"; part_d_lis_enrolled requires medicare_part_d_enrolled
Income below 150% of the poverty guideline for the family size (a)(3)(A)(ii); 423.773(a)(1); POMS HI 03020.055 part_d_lis_income_eligible
Family size: the person, a spouse living with them, and relatives who live with them and depend on them for at least half their support 42 CFR 423.772 part_d_lis_family_size: the marital unit plus the dependents on the couple's returns, on both returns when the spouses file separately
Income is SSI income, without in-kind support and maintenance, of the person and of a spouse living with them "regardless of whether the spouse is also an applicant"; all interest and dividends excluded; the $20, $65 and one-half exclusions apply once to the couple (a)(3)(C)(i); 423.772; 20 CFR 418.3310, 418.3325, 418.3350(d); POMS HI 03020.050 part_d_lis_countable_income: SSI's unearned sources less income/excluded_sources.yaml, then _apply_ssi_exclusions on the couple's totals
Rental income counts net, and expenses above the rent don't offset other income POMS SI 00830.505 each unearned source counts at no less than zero, for each person
Resources of the person and spouse ≤ the (E) standard: $10,000 / $20,000 in 2006, CPI-indexed; $16,590 / $33,120 in 2026 and $17,210 / $34,360 in 2027 (a)(3)(E); 423.773(b)(2)(iii), (d)(2); POMS HI 03030.025 limit/individual.yaml, limit/couple.yaml; extend_part_d_lis_resource_limits after 2026
Plus $1,500 per person for burial funds, unless the applicant says they won't use any for burial 20 CFR 418.3425(j); POMS HI 03030.020, .025 burial_exclusion.yaml
Countable resources: liquid resources and real estate other than the home; life insurance excluded (a)(3)(G); 423.772; 20 CFR 418.3405 sources.yaml (bank, stock and bond assets) and household_sources.yaml (household_other_real_estate_equity, for the household head's couple)
Deemed: full-benefit dual eligibles, SSI recipients, QMB/SLMB/QI (a)(3)(B)(v); 423.773(c)(1) part_d_lis_deemed_eligible
50 states and DC only (a)(3)(F); 20 CFR 418.3010(b)(11) ineligible_jurisdictions.yaml

Before 2024, income from 135% to 150% of the guideline, or resources between the lower (D) and the higher (E) limit, gave a partial subsidy. The Inflation Reduction Act (§ 11404) made all of it a full subsidy from 2024. The model uses the outer bound in every year, because CBO and this PR give every recipient the same average.

The LIS income test takes SSI's exclusions "without regard to the application of section 1396a(r)(2)" ((a)(3)(C)(i)). So part_d_lis_countable_income keeps SSI's $20 general exclusion even in Illinois and Mississippi, whose Medicare Savings Program income takes larger 1902(r)(2) exclusions.

Rental losses. SSI counts net rental income, and POMS SI 00830.505 says not to "use [excess expenses] to offset other income". part_d_lis_countable_income therefore counts each unearned source at no less than zero, for each spouse. pe-us's own SSI and Medicare Savings Program income sums the sources with their signs, so a rental loss there still offsets Social Security; a separate task covers those.

Real estate. 423.772 counts "real estate that is not the applicant's primary residence", and 20 CFR 418.3405(b) counts it whether or not it can be sold within 20 workdays. pe-us holds real estate equity by household, and a household amount doesn't say whose it is. So part_d_lis_resource_eligible counts household_other_real_estate_equity in full for the household head's couple (the oldest member's, when no one is head), once per household.

Rental property equity (household_rental_property_equity) stays out. 20 CFR 418.3425(c) and (d) exclude property essential to self-support: property used in a trade or business in full, and other income-producing property up to $6,000 of equity when it returns 6% a year (POMS SI 01130.500, SI 01130.501). The model can't tell which applies. The default dataset holds neither input, so in the microsimulation real estate changes nothing.

Part D plan. The statute's subsidy eligible individual "is enrolled in a prescription drug plan or MA–PD plan" ((a)(3)(A)(i)). CMS's rule reads "enrolled in, or seeking to enroll in a Part D plan" (423.773(a)), and SSA's rule tells people found eligible before they enroll that they "must enroll in one of these plans to actually receive a subsidy" (418.3101(b)). The model can't see who seeks to enroll, so part_d_lis_eligible holds the deemed, income and resource tests, and part_d_lis_enrolled adds the plan: only people with medicare_part_d_enrolled (from #10115) receive the subsidy.

Enrollment. CMS tells deemed people they don't need to apply (423.773(c)(2)). It enrolls subsidy-eligible people who don't choose a plan, and any of them can decline (42 CFR 423.34(d)(1), (e)). Qualifying covered retirees, whose employer retiree drug coverage qualifies for the retiree drug subsidy, are the exception: CMS enrolls only the full-benefit dual eligibles among them whose plan sponsor it approved for that subsidy, and only if they confirm that they want a plan (423.34(d)(3)). So:

  • part_d_lis_enrolled is automatic for medicaid_enrolled or ssi > 0 people in a Part D plan;
  • other eligible people in a plan need takes_up_part_d_lis_if_eligible, which defaults to True. pe-us models Medicare Savings Program eligibility, not enrollment, so MSP-deemed people go through the flag too;
  • microdata that set takes_up_medicare_part_d_if_eligible should set it True for Medicaid enrollees and SSI recipients other than those who decline and covered retirees who don't choose a plan. A person whose Part D input is False gets no subsidy. part_d_lis_enrolled's documentation states this contract.

Microcosm sets neither takes_up_medicare_part_d_if_eligible nor takes_up_part_d_lis_if_eligible (git grep on microcosm origin/main 3db65154b, 2026-11-07); its only mention of the first is a comment. Both default to True. In the microsimulation, therefore, every Medicare enrollee holds a Part D plan, and every eligible one receives the subsidy. microcosm#1206 proposes a Part D take-up input.

Values

Resource limits through 2026.

  • Individual: all 21 years, 2006–2026, match POMS HI 03030.025, which before 2024 lists two limits a year; the parameter takes the higher one. Each equals the statute's rule applied to the previous year's limit: × the September-to-September change in the not seasonally adjusted CPI-U (BLS CUUR0000SA0), never lowered, rounded to $10.
  • Couple, 2006–2014: SSA's amounts, which the same rule reproduces.
  • Couple, from 2015: the statute's rule, not SSA's amounts. For 2015, CMS's memo applies the factor 1.01658 (238.031 / 234.149) to 2014's $23,860, which gives $24,255.58 and rounds to $24,260. The memo prints $24,250, and POMS lists $24,250 for 2015 and 2016. SSA has raised its own published amount every year since. The parameter applies the statute's rule to the previous year's limit as the statute sets it. So it runs $10 above SSA's amounts in 2015 and 2016 and $20 above from 2017: $33,120 against SSA's $33,100 in 2026.
  • The ruling: source-conflict candidate us:part-d-lis-couple-resource-limit-2015 (source_conflicts/candidates.yaml), which follows the statute under the statute-first rule.
    • The memo's factor reproduces its other three 2015 amounts ($7,280, $10,930 and $12,140).
    • Every other limit SSA published from 2007 to 2026 equals the rule applied to the previous published limit. That covers individuals and couples, at the lower (full subsidy) and the higher level: 74 year-limit pairs, one mismatch (~/reviews/medicare-part-d-lis-2026-10/scripts/verify_published_chain.py, from POMS HI 03030.025's prior-year list and BLS's Septembers).
    • So $24,250 is the one amount the stated method doesn't give. The gap reaches only couples whose countable resources fall within $10 to $20 of the limit.
    • The rulespec-us register entry follows after merge (CONTRIBUTING.md, "Source conflicts", steps 2–4).

Resource limits after 2026. extend_part_d_lis_resource_limits (uprating_extensions.py) projects each later year:

  • the previous year's limit × the unrounded ratio of September of the year before to September two years before, never lowered, rounded to the nearest $10 with halves up;
  • get_september_cpi_u_values takes both Septembers from gov.bls.cpi.cpi_u_nsa_september when BLS has published both, and otherwise both from the model's CPI-U projection, never one of each;
  • the PR adds BLS's September 2026 value, 336.940 (API, retrieved 2026-11-08). For 2027 that gives $16,590 × 336.940 / 324.800 = $17,210.08, so $17,210, and $34,360 for couples. CMS hadn't published its CY 2027 memo as of 2026-11-08;
  • CMS's CY 2026 memo reports the 2026 increase as 3.01%, but its published $16,590 needs the unrounded ratio: $16,100 × 1.0301 = $16,584.61 would round to $16,580;
  • the limits hold from 2100, END_YEAR.

Medicaid home equity, as a side effect. get_cms_cpi_u_percentage_increase now reads its Septembers through the same helper. With September 2026 published, CMS's rounded percentage for the 2027 Medicaid long-term care home equity limits becomes 3.7% (336.940 / 324.800) instead of 3.1% from the projected series. The 2027 limit rises from $1,165,000 to $1,172,000.

The helper also reads only September instants now. pe-us backdates each parameter's first value to 2015-01-01, which the old code counted as a published 2015 September. No year the home equity projection fills used it.

Per recipient. IV.B9, 2013–2035:

Year LIS enrollees (IV.B9) Per recipient Per Medicare enrollee (#10118)
2013 11.5 million $2,023 $441.87
2014 11.8 million $2,052 $449.04
2015 12.1 million $2,112 $460.52
2020 13.1 million $2,507 $524.75
2024 14.5 million $2,833 $605.29
2025 14.2 million $1,226 $251.12
2026 14.4 million $1,254 $255.86
2030 15.8 million $1,833 $377.29
2035 16.7 million $2,076 $431.59
  • The amount falls from $2,833 in 2024 to $1,226 in 2025. The 2026 report says the Inflation Reduction Act redesigned the standard Part D benefit, "with the full effects of the benefit redesign implemented in 2025" (file page 119). Table IV.B9 gives no cause for the drop.
  • From 2036 the series grows with calibration.gov.hhs.medicare.per_capita_cost, like the per-enrollee series beside it.
  • Like Count Medicare net of premiums in CBO household income #10118's series, it starts in 2013. CBO means-tested transfers already fail before 2015 on the base, through Medicaid and SNAP parameters. So the CBO test file gets no 2013–2014 case, and programs.yaml gives 2015 as the first verified year.

Impact

2026, the default dataset (populace_us_2024.h5@populace-us-2024-spm-20260909: 57,240 households, 166,321 people), one full run per side through the shared heavy lock. Base: this branch's merge-base with #10118's branch, c9dfbc2 (#10118's head). PR: fe4af16 (the later commits, through the head 2c447a3, change only documentation and tests). Each run imported its own git archive snapshot.

Base This PR Change
CBO income before transfers and taxes $22,718.2 billion $22,718.2 billion 0
cbo_medicare_benefit $929.6 billion $929.6 billion 0
medicare_cost $928.1 billion $928.1 billion 0
CBO income after transfers and taxes $19,497.8 billion $19,510.2 billion +$12.40 billion
healthcare_benefit_value $967.2 billion $979.6 billion +$12.40 billion
household_net_income $17,162.3 billion $17,162.3 billion 0
part_d_lis $12.40 billion
part_d_lis_enrolled 9.89 million
  • The changes in CBO income after transfers and taxes and in healthcare_benefit_value equal total part_d_lis to within $220 and $112, float rounding on $12.4 billion.
  • 7.44 million of 124.56 million households gain, and none lose.
  • Every recipient gets $1,254, and no one outside part_d_lis_enrolled gets anything.

Recipients by path:

Path Recipients
Automatic: Medicaid enrollees 5.69 million
Automatic: SSI recipients without Medicaid 0.17 million
Medicare Savings Program eligible, neither Medicaid nor SSI 2.84 million
Income and resource tests only 1.19 million
Total 9.89 million

By quintile, ranked as CBO ranks: households by size-adjusted income before transfers and taxes, in quintiles of equal numbers of people. Households with negative income stay out of the lowest quintile; they gain $51 million.

Quintile Change Per household Share of income after transfers and taxes
Lowest +$3.85 billion $168 0.27%
Second +$4.78 billion $195 0.26%
Middle +$1.89 billion $75 0.07%
Fourth +$1.09 billion $44 0.03%
Highest +$0.74 billion $28 0.01%

What the review fixes moved. Against the previous head (e415392), record by record on the same dataset:

  • the rental-loss floor raises countable income for 4.63 million people (2.16 million of them Medicare enrollees), and 2,457 people lose the subsidy, $3.1 million;
  • the couple limit's statutory amount changes the resource test for 4 records, none of them Medicare enrollees;
  • separate filers' family size and real estate change nothing here: no record's family size moves, and the dataset has no real estate input.

Against the Trustees. The model reaches 69% of IV.B9's 14.4 million LIS enrollees and 68% of IV.B10's $18.1 billion. Two things account for much of the gap:

  • No Medicare enrollee in the dataset is under 65. All 24,147 Medicare-enrolled records are 65 or older: 58.5 million people. The 2026 Trustees Report counts 69.3 million enrollees in 2025, "62.2 million aged 65 and older, and 7.1 million disabled" (file page 13), and 70.7 million in 2026 (Table V.B3). pe-us reaches Medicare under 65 only through 24 months of SSDI (months_receiving_social_security_disability), and no Microcosm build sets that input (Medicare: add a Part B enrollment input and impute SSDI months so Part B rules reach the right people #10457, microcosm#876). So no disabled beneficiary under 65 can receive the subsidy here.
  • CBO drops institutionalized recipients. Its 2015–2016 counts came to 88–90% of the Trustees'. Applying that ratio to 2026 gives 12.7–12.9 million.

With #10118. #10118 takes $255.86 per Medicare enrollee out of cbo_medicare_benefit, which comes to $14.96 billion over the model's 58.5 million enrollees. This PR adds $12.40 billion back to the 9.89 million people it finds eligible.

Scripts and outputs: ~/reviews/medicare-part-d-lis-2026-10/impact/ (pair_inner.sh, compare.2026.fe4af16ec1.json, aggregates.2026.fe4af16ec1.json, r2_vs_r3.2026.json).

Invariants and tests

YAML: 68 cases across 9 files in tests/policy/baseline/gov/hhs/medicare/part_d/low_income_subsidy/. They include:

  • the exact boundaries: income at 150% of the guideline fails, and resources at the limit plus the burial exclusion pass while one dollar more fails, in 2026 and at the projected 2027 limits;
  • Alaska, Puerto Rico and DC;
  • the 2023 partial-subsidy range, and the 2013 and 2014 amounts;
  • a Medicaid enrollee who opted out of Part D, a Medicaid enrollee whose Part D input is False, and an eligible person outside Part D, none of whom gets the subsidy;
  • rental losses that don't offset Social Security or a spouse's income;
  • spouses who file separately, alone and with a child each;
  • non-home real estate, for the household head's couple only, for the older of two flagged heads and, without a head, for the oldest member's;
  • households computed from their inputs through MSP deeming and through the LIS's own tests.

Elsewhere:

  • cbo_household_income.yaml gains a case where the LIS is the only means-tested transfer, and its list test now includes part_d_lis (and msp, which does not count);
  • healthcare_benefit_value.yaml gains a case with the LIS;
  • household_health_benefits.yaml gains two: the flag on counts the LIS, and the flag off leaves it out.

Python, tests/core/test_part_d_lis.py: 90 tests. Locally the file takes 24 s, 12–13 s of it the model load, and peaks at 1.46 GB against 1.13 GB for a bare model load. It runs in CI's core groups, which peaked at 6.0–9.7 GiB on main's 2026-11-07 run (42409791828). extend_part_d_lis_resource_limits runs on every model build and takes 0.05 s of it. Builds take 7–9 s locally: three fresh builds at the base and three at the head, with no difference beyond their spread (~/reviews/medicare-part-d-lis-2026-10/ci-cost/load_cost.txt).

  1. Transcription: the per-recipient series equals IV.B9 for 2013–2035.
  2. Conservation: IV.B9 enrollment × amount reproduces IV.B10 within the cells' rounding.
  3. Differential: the same payments over V.B3 total enrollment equal Count Medicare net of premiums in CBO household income #10118's per-enrollee series, which comes from different cells, within 0.5%. V.B3 for 2013–2014 comes from the 2021 report.
  4. Indexing, 2007–2027: both limits equal the statute's rule from the 2006 amounts in every year, with no exception, applied to BLS Septembers typed into the test. The typed Septembers match cpi_u_nsa_september wherever the parameter has them.
  5. Projection, 2028–2100: each limit equals the rule applied to the Septembers get_september_cpi_u_values returns, and the 2035 limit exceeds 2027's.
  6. Rounding: adjust_part_d_lis_resource_limit_for_inflation rounds to the nearest $10 with halves up and never lowers a limit; the published 2026 limits need the unrounded ratio.
  7. Synthetic trees: in the extension, YAML values stand, published Septembers come first, a fall in the index keeps the limit, a missing September sends both Septembers to the fallback series, and the value holds after end_year. In get_september_cpi_u_values, an instant other than September 1 (such as the backdated 2015-01-01 entry) doesn't count as a published September.
  8. Bounds, 2013–2100: the amount stays positive and below Medicare spending per enrollee.
  9. Restated rules: a seeded sample of 300 households plus 10 boundary households (489 adults), each also run with more Social Security, more interest and more assets in one shared simulation. The test checks the model against rules it restates, not against the formulas:
    • countable income, with rental losses floored for each person, and family size;
    • the income and resource tests, with real estate for the head's couple;
    • eligibility, the Part D plan condition and enrollment in the subsidy;
    • the benefit, which is zero or the year's amount.
  10. Interest and dividends never change countable income, eligibility or the benefit.
  11. Monotonicity: more Social Security never makes someone income eligible, and more assets never make someone resource eligible.
  12. Spouses get the same countable income, family size and test results, including spouses who file separately.
  13. Differential against MSP: with no interest, dividends or rental income, part_d_lis_countable_income equals 12 × msp_countable_income, a separate implementation of the same SSI exclusions (single people and couples who both have Medicare). The sample has no Illinois or Mississippi households, whose MSP income takes the larger exclusions.

The sample reaches every branch, and a test fails if one goes unreached. In the base run:

  • 179 households are couples, 113 have dependents and 33 live in Puerto Rico; 37 adults have no Medicare;
  • Medicaid alone deems 35 adults eligible, SSI alone 62 and an MSP alone 56;
  • 196 pass both tests, 142 fail only the resource test and 97 only the income test;
  • 178 receive the subsidy; 45 eligible people have no Part D plan, 46 have a plan but don't take it up, and 27 get it automatically despite a False take-up flag;
  • 3 households sit exactly on a resource limit and 3 one dollar over; 4 sit exactly on the income limit;
  • 10 separate-filer households have one dependent, and splitting it changes the income test for 3. The rental floor changes the income test for 9 households, and real estate changes the resource test for 36.

Mutations: each mutant edits a fresh git archive of a commit, which then runs the LIS YAML folder and the Python file, plus the suites the edit can reach (the household health benefit YAML, the Medicaid home equity YAML and the uprating tests). A mutant counts as caught only when a test fails, not when collection breaks. ~/reviews/medicare-part-d-lis-2026-10/mutants/ holds the results (results.txt, results_r3b.txt).

  • 20 at 33cc03d, all caught:
    • the Part D plan condition dropped, a strict resource test, income at the limit passing, a 145% income limit;
    • interest counted, the rental floor dropped, the spouse's income or unearned income ignored;
    • separate filers on their own return, a joint return's dependents doubled;
    • one burial exclusion per couple, real estate dropped or counted for everyone, the household head ignored;
    • no indexing, a lowered limit, a rounded ratio, SSA's 2015 couple limit, September 2026 dropped;
    • the subsidy left out of healthcare_benefit_value.
  • 23 at 4ecac84, aimed at the round 3 review questions; 21 caught:
    • both Septembers always from the model's series, no hold after the end year, banker's rounding, the LIS extension run before the CPI-U extension, the home equity Septembers swapped;
    • the youngest member holding the real estate when no one is head, a spouse's resources ignored, the couple limit for single people, no burial exclusion;
    • a rental loss offsetting the person's or the spouse's other unearned income, dividends counted, the spouse left out of family size, the guideline for one;
    • territorial residents qualifying, MSP or SSI no longer deeming, automatic enrollment dropped, take-up defaulting to False;
    • the subsidy left out of CBO's means-tested transfers or the household health benefit list.
  • Two survived at 4ecac84; both fail at 2c447a3:
    • youngest_head: with two flagged heads, the younger one holds the real estate. No case had two heads; 2c447a3 adds one.
    • september_filter_dropped: an instant other than September 1 counts as a published September. On the real tree this changes nothing. The only such instant is the backdated 2015-01-01 entry, and the parameter's Septembers start in 2018, so no year gains a complete pair of Septembers through it. 2c447a3 adds a synthetic test of get_september_cpi_u_values.

With three people of the same age, the household amount goes to exactly one of them, and to a flagged head when there is one. That held for all 24 combinations of member order and head flags tried (scripts/tie_check.py).

Local runs at 4ecac84, one process at a time (local-runs/summary.4ecac84cc2.txt):

  • YAML: Medicare (279 cases in 5 batches), household income (69), the health benefit files (98), the EDAA reform (9) and Medicaid long-term care (62) all pass.
  • Python: the LIS file with the registry, aggregate-list, SPM-contract and Medicare-series tests (1,201 passed, 10 skipped), uprating (268), health (77) and code health (529 passed, 1 skipped) pass.
  • The code-health run's two failures, test_reform_folders_run_each_yaml_and_python_file_separately[True-contrib/crfb] and [True-reform], came from the local venv missing coverage. With uv.lock's 7.13.2 installed, all four of that test's cases pass.
  • At 2c447a3 the LIS YAML folder (68) and the Python file (90) pass.

Review

  • Round 2 (e415392), two independent reviews on Subfleet: one on the law, values and design, one on the formulas, tests and integration. Both asked for changes: 14 findings on the law side and 7 on the code side. ff54d4a, 33cc03d and fe4af16 address them:
    • the resource limits now index after 2026 (law 1, code 4);
    • non-home real estate counts (law 2);
    • spouses who file separately get one family size (law 3, code 2);
    • part_d_lis_enrolled documents the auto-enrollment contract (law 4);
    • the subsidy counts as a household health benefit (law 5);
    • part_d_lis says how its recipients differ from CBO's, and this body reports the impact (law 6);
    • the couple limit follows the statute, with a source-conflict candidate (law 7);
    • rental losses no longer offset other income (code 1);
    • the excluded sources come out of SSI's list instead of SSI's total (code 3);
    • more boundary cases and mutants for the Python file (code 5);
    • citations, descriptions, the registry entry and the changelog (law 8–13, code 6–7).
  • Round 3: two new reviews on the same two lenses wait on Subfleet for capacity. Each reviews the branch head when it starts (2c447a3 or later) and checks each round 2 finding against it.

Not modeled and follow-ups

  • Take-up. Microcosm seeds neither take-up flag (see Enrollment). microcosm#1206 proposes a Part D input, and a separate task covers the LIS flag, which should apply only to people with neither Medicaid nor SSI.
  • Medicare under 65. Medicare: add a Part B enrollment input and impute SSDI months so Part B rules reach the right people #10457 and microcosm#876 track the missing SSDI months.
  • Retirement accounts count as LIS resources (20 CFR 418.3405), but pe-us has no input for their balances.
  • Rental property equity stays out (see Real estate).
  • The Social Security cost-of-living increase: SSA leaves it out of income through the month after HHS publishes the new poverty guidelines (20 CFR 418.3340(f)); the model counts the year's benefits in full.
  • Carry-over of deemed status: people deemed eligible from July to December stay deemed through the next year (423.773(c)(2)(ii)); the model tests each year on its own.
  • Institutionalized enrollees. See above; the average stays.
  • The premium and cost-sharing subsidies, including the pre-2024 partial subsidy's sliding scale, have no per-person computation.
  • SSI and the Medicare Savings Programs net rental losses and leave out non-home real estate in their own income and resource tests. Separate tasks cover them.
  • Health benefits counted twice with the flag on. With gov.simulation.include_health_benefits_in_net_income on, household_net_income already holds household_health_benefits, and household_net_income_including_health_benefits adds healthcare_benefit_value on top, so every health benefit counts twice there and in marginal_tax_rate_including_health_benefits. That includes Medicaid, MSP and CHIP, and now part_d_lis. Net income including health benefits counts health coverage twice when health benefits are in net income #9581 (open) tracks it. This PR adds part_d_lis to both lists, so they stay identical, as Register the remaining five state premium programs in household_health_benefits #9514 made them.
  • The source-conflict register: after merge, us:part-d-lis-couple-resource-limit-2015 goes into rulespec-us's known-source-conflicts.yaml, and a follow-up PR here marks the deciding line.

axiom: TheAxiomFoundation/rulespec-us#1681 queued (42 U.S.C. 1395w-114(a)(3) and 42 CFR 423.772–773; the corpus has both, but rulespec-us's pin, us-rulespec-2026-10-29-ecfr-section-text, includes neither; 20 CFR 418 ingestion is TheAxiomFoundation/axiom-corpus#818)

Sources

Source URL Retrieved
42 U.S.C. 1395w-114 https://www.law.cornell.edu/uscode/text/42/1395w-114 2026-10-11
42 CFR 423.772, 423.773 (eCFR, 2026-10-01) https://www.ecfr.gov/current/title-42/chapter-IV/subchapter-B/part-423/subpart-P 2026-10-11
42 CFR 423.34 (eCFR, 2026-11-05) https://www.ecfr.gov/current/title-42/chapter-IV/subchapter-B/part-423/subpart-B/section-423.34 2026-11-08
20 CFR 418 subpart D (eCFR, 2026-10-01) https://www.ecfr.gov/current/title-20/chapter-III/part-418/subpart-D 2026-10-11
SSA interim final rule, 75 FR 81843 (effective 2011-01-01) https://www.federalregister.gov/documents/2010/12/29/2010-32848 2026-10-11
SSA POMS HI 03020.010, .030, .050, .055; HI 03030.020, .025 https://secure.ssa.gov/poms.nsf/lnx/0603030025 2026-10-11; HI 03030.025 again on 2026-11-08
SSA POMS SI 00830.505 (rental income) https://secure.ssa.gov/poms.nsf/lnx/0500830505 2026-11-08
SSA POMS SI 01130.500, .501 (property essential to self-support) https://secure.ssa.gov/poms.nsf/lnx/0501130500 2026-11-08
CMS, 2015 LIS income and resource standards (Attachment 4, file pages 5–6) https://www.cms.gov/files/document/2015-lis-income-and-resourcespdf 2026-11-08
CMS, CY 2026 LIS resource and cost-sharing limits, October 31, 2025 (file page 2) https://www.cms.gov/files/document/cy2026-lis-resource-limits-memo.pdf 2026-11-08
2026 Medicare Trustees Report (sha256 ffa56b91…8fa8) https://www.cms.gov/oact/tr/2026 2026-10-11
2025 Medicare Trustees Report (sha256 1b3de7a4…4d95) https://www.cms.gov/oact/tr/2025 2026-10-11
2023 Medicare Trustees Report (sha256 89daaf29…fa67) https://www.cms.gov/oact/tr/2023 2026-11-07
2021 Medicare Trustees Report (sha256 ef3d1fa7…fc8e) https://www.cms.gov/oact/tr/2021 2026-11-07
Habib, CBO WP 2018-07 https://www.cbo.gov/system/files/2018-07/54234-workingpaper.pdf 2026-10-11 (browser)
CBO, January 2026 health insurance sensitivity report https://www.cbo.gov/publication/61910 2026-10-11 (browser, via #10118's notes)
BLS CPI-U, CUUR0000SA0 https://api.bls.gov/publicAPI/v2/timeseries/data/ 2026-10-11; September 2026 on 2026-11-08

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 11, 2026 16:57
…ans-tested transfer

Adds statutory eligibility for the Part D low-income subsidy (Extra Help):
countable income below 150% of the poverty guideline for the family size,
countable resources within the CPI-indexed limit plus the burial funds
exclusion, and deemed eligibility for Medicaid enrollees, SSI recipients and
Medicare Savings Program enrollees. The subsidy is valued at the Medicare
Trustees' average payment per subsidy enrollee (Table IV.B9), as CBO assigns
it, and joins gov.household.cbo_means_tested_transfers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
YAML tests for every new variable, households computed from their inputs
(Medicare Savings Program deeming, the subsidy's own tests, the pre-2024
partial range, take-up), and the CBO means-tested list. Python invariants:
IV.B9 transcription, IV.B10 conservation, agreement with the per-enrollee
series cbo_medicare_benefit subtracts, the CPI rule behind the resource
limits, Hypothesis bounds, restated eligibility rules over a seeded sample
with income, interest and asset variants, and a differential test against
msp_countable_income.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…idy average

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits November 7, 2026 16:19
The subsidy pays part of a Part D plan's premium and cost sharing, so
42 U.S.C. 1395w-114(a)(3)(A)(i) defines a subsidy eligible individual
as one enrolled in a prescription drug plan or MA-PD plan, and 20 CFR
418.3101(b) says an applicant "must enroll in one of these plans to
actually receive a subsidy". medicare_part_d_enrolled reached main in
#10115 after this branch began, so part_d_lis_enrolled now requires it,
including for Medicaid enrollees and SSI recipients: Medicare enrolls
them in a plan automatically (42 CFR 423.34), but they can opt out of
Part D, for example for TRICARE for Life or VA drug coverage.

takes_up_medicare_part_d_if_eligible defaults to true and Microcosm does
not yet set it, so the microsimulation is unchanged; a household that
sets it to false now gets no subsidy. The seeded household sample in
test_part_d_lis.py now draws Part D enrollment and its restated rule
requires it; the YAML tests add an opt-out case for each path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#10118 extended calibration.gov.hhs.medicare.part_d_low_income_subsidy_
per_enrollee and the other Medicare per-enrollee series back to 2013,
the first year of per_capita_cost. The per-recipient average started in
2015, so part_d_lis raised ParameterNotFoundError for a 2013 or 2014
enrollee. The 2023 Trustees Report's Table IV.B9 (file page 158), the
newest that shows both years, gives $2,023 per subsidy enrollee in 2013
(11.5 million enrollees) and $2,052 in 2014 (11.8 million); its Table
IV.B10 gives $23.2 billion and $24.3 billion, which the products match
within rounding, and the 2021 report's Table V.B3 enrollment (52,504 and
54,115 thousand) turns them into #10118's per-enrollee values within
0.4%. The invariant tests now cover both years.

Before 2015, cbo_household_means_tested_transfers still raises
ParameterNotFoundError through Medicaid and SNAP parameters, as it does
without this change.

The 2026 report's reference now lists both cited pages (119 and 158),
and the Habib reference both of its pages (51 and 52), per the
repository's reference rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

part_d_lis gives each recipient the Trustees' average subsidy per LIS enrollee, which includes nursing home residents. CBO removes institutionalized LIS recipients and their benefits from its totals, using the Master Beneficiary Summary File (Working Paper 2018-07, file page 52). #10126 scales the other Medicare values to enrollees outside nursing homes with a ratio from MedPAC's fee-for-service Part A and B spending, which doesn't cover the LIS. Matching CBO here would take an LIS average per recipient outside institutions.

MaxGhenis and others added 3 commits November 8, 2026 01:05
- Index the resource limits after 2026 by the unrounded September CPI-U
  ratio (42 U.S.C. 1395w-114(a)(3)(E)(i)), and add September 2026's CPI-U.
- Follow the statute's chain for the couple limit from 2015, entered as a
  source-conflict candidate against CMS's 2015 memo.
- Count non-home real estate for the household head's couple, floor each
  income source at zero, count both returns' dependents for spouses who
  file separately, and document the auto-enrollment data contract.
- Fix the per-recipient and jurisdiction citations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add part_d_lis next to msp_cost in household_health_benefits and
  healthcare_benefit_value, which count only when
  include_health_benefits_in_net_income is on.
- YAML cases for the indexed 2027 limits, the statutory couple limit,
  non-home real estate and its attribution, rental losses, separate
  filers' family size and the Part D input of Medicaid enrollees.
- Python tests: the CPI rule through 2027 with no published exception,
  projected years and a synthetic tree for the extension, exhaustive
  loops for the bounds, and a sample with separate filers, rental
  losses, real estate and households on each limit, plus a reach check.
- Move the registry entry to the HHS block and fix its notes.
- Read only September instants as published CPI-U values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits November 8, 2026 01:59
16,590 x 336.940 / 324.800 is 17,210.08 and 33,120 x 336.940 / 324.800
is 34,357.92. The rounded limits and the tests' inputs don't change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CMS enrolls a qualifying covered retiree only if they are a full-benefit
dual eligible whose plan sponsor it approved for the retiree drug subsidy
and they confirm that they want a plan; it enrolls no other covered
retiree. The docstring had limited the exception to retirees whose
employer gets the subsidy. Documentation and a test comment only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A household with two flagged heads gives its real estate to the older
one, and a non-September instant in the September CPI-U node is not a
published September. Both rules had no test; the round 3 mutants that
reversed them survived.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant