From c5ab5b5d70166c4cf483b7e8ab890779529b4069 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 11 Oct 2026 15:50:17 -0400 Subject: [PATCH 1/7] Count Medicare net of premiums in CBO household income CBO's standard household income counts Medicare at the government's average cost per enrollee, net of premiums paid by enrollees, and counts the Part D low-income subsidy separately as a means-tested transfer (CBO, January 2026, publication 61910; Distribution of Household Income in 2021, Appendix A; Habib 2018, Appendix B). The default list used medicare_gross_cost, which is gross of premiums and includes the subsidy. Add cbo_medicare_benefit: Medicare spending per enrollee less per-enrollee Part A, B and D premium income and the Part D low-income subsidy per Medicare enrollee, from the 2026 Medicare Trustees Report. Every enrollee gets the same value, as CBO assigns the average. Fix the medicare_gross_cost docstring, which said gross matched CBO. Co-Authored-By: Claude Opus 5.5 --- .../cbo-medicare-net-of-premiums.fixed.md | 1 + ...art_d_low_income_subsidy_per_enrollee.yaml | 54 +++++++++++++++++ .../premium_income_per_enrollee/part_a.yaml | 47 +++++++++++++++ .../premium_income_per_enrollee/part_b.yaml | 60 +++++++++++++++++++ .../premium_income_per_enrollee/part_d.yaml | 57 ++++++++++++++++++ .../cbo_social_insurance_benefits.yaml | 15 ++++- .../household/cbo_household_income.yaml | 13 ++-- .../medicare/costs/cbo_medicare_benefit.py | 36 +++++++++++ .../hhs/medicare/costs/medicare_gross_cost.py | 13 +++- ...cbo_household_social_insurance_benefits.py | 4 +- 10 files changed, 290 insertions(+), 10 deletions(-) create mode 100644 changelog.d/cbo-medicare-net-of-premiums.fixed.md create mode 100644 policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml create mode 100644 policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml create mode 100644 policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml create mode 100644 policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml create mode 100644 policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py diff --git a/changelog.d/cbo-medicare-net-of-premiums.fixed.md b/changelog.d/cbo-medicare-net-of-premiums.fixed.md new file mode 100644 index 00000000000..31b17d9bb0c --- /dev/null +++ b/changelog.d/cbo-medicare-net-of-premiums.fixed.md @@ -0,0 +1 @@ +The default CBO household income now counts Medicare as CBO does, at the average cost per enrollee net of premiums and excluding the Part D low-income subsidy, through a new `cbo_medicare_benefit` variable instead of gross Medicare spending. diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml new file mode 100644 index 00000000000..6e84c8d8cac --- /dev/null +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml @@ -0,0 +1,54 @@ +description: The Medicare Trustees report and project these Part D low-income subsidy payments per Medicare enrollee. +metadata: + unit: currency-USD + period: year + label: Medicare Part D low-income subsidy per enrollee + # From 2036, each value is the 2035 value times the growth in Medicare + # spending per enrollee, so the subsidy keeps its 2035 share of spending. + uprating: calibration.gov.hhs.medicare.per_capita_cost + reference: + # Each value is Table IV.B10's "Low-income subsidy" payments ($ billions, + # incurred basis) over Table V.B3's total enrollment (file page 196, + # thousands), people with Part A and/or Part B coverage, so it is per + # Medicare enrollee, not per subsidy recipient. 2016 to 2035 come from the + # 2026 report's Table IV.B10 (file page 159); 2015, which that table no + # longer shows, from the 2025 report's (file page 159). The two reports + # agree on 2016 to 2023. 2026 Medicare Trustees Report, transmitted + # 2026-06-09, retrieved 2026-10-11, sha256 + # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8; 2025 + # report sha256 + # 1b3de7a4faeee5ad42059e10740603182b716a5fa7b53b30d360b45b9e474d95. + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10 + href: https://www.cms.gov/oact/tr/2026#page=159 + - title: 2025 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10 + href: https://www.cms.gov/oact/tr/2025#page=159 + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 + href: https://www.cms.gov/oact/tr/2026#page=196 +values: + # Historical. + 2015-01-01: 460.52 + 2016-01-01: 462.57 + 2017-01-01: 465.21 + 2018-01-01: 474.84 + 2019-01-01: 482.65 + 2020-01-01: 524.75 + 2021-01-01: 547.05 + 2022-01-01: 604.61 + 2023-01-01: 663.6 + 2024-01-01: 605.29 + # 2025 is the first year of the full Inflation Reduction Act benefit + # redesign (file page 119). The subsidy per low-income enrollee fell from + # $2,833 to $1,226 while the direct subsidy per enrollee rose from $383 to + # $1,869 (Table IV.B9, file page 158). + 2025-01-01: 251.12 + # Trustees' intermediate estimates. + 2026-01-01: 255.86 + 2027-01-01: 283.45 + 2028-01-01: 298.54 + 2029-01-01: 324.78 + 2030-01-01: 377.29 + 2031-01-01: 396.02 + 2032-01-01: 404.71 + 2033-01-01: 409.83 + 2034-01-01: 417.15 + 2035-01-01: 431.59 diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml new file mode 100644 index 00000000000..5049d213595 --- /dev/null +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml @@ -0,0 +1,47 @@ +description: The Medicare Trustees report and project this Part A premium income per Medicare enrollee, which counts premiums paid by or on behalf of people without premium-free Part A who enroll voluntarily. +metadata: + unit: currency-USD + period: year + label: Medicare Part A premium income per enrollee + # From 2036, each value is the 2035 value times the growth in Medicare + # spending per enrollee, so premiums keep their 2035 share of spending. + uprating: calibration.gov.hhs.medicare.per_capita_cost + reference: + # Each value is Table III.B4's "Premiums from voluntary enrollees" (file + # page 64, $ billions, cash basis) over Table V.B3's total enrollment + # (file page 196, thousands), which footnote 2 defines as the "Number of + # beneficiaries with HI and/or SMI coverage". The Part A premium is paid + # "by or on behalf of" these enrollees (glossary, file page 257), so state + # Medicaid buy-in payments are included. 2026 Medicare Trustees Report, + # transmitted 2026-06-09, retrieved 2026-10-11, sha256 + # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table III.B4 + href: https://www.cms.gov/oact/tr/2026#page=64 + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 + href: https://www.cms.gov/oact/tr/2026#page=196 + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, glossary, Part A premium + href: https://www.cms.gov/oact/tr/2026#page=257 +values: + # Historical. + 2015-01-01: 57.57 + 2016-01-01: 57.82 + 2017-01-01: 59.64 + 2018-01-01: 59.98 + 2019-01-01: 63.38 + 2020-01-01: 63.61 + 2021-01-01: 65.65 + 2022-01-01: 69.05 + 2023-01-01: 70.56 + 2024-01-01: 70.52 + 2025-01-01: 82.26 + # Trustees' intermediate estimates. + 2026-01-01: 97.54 + 2027-01-01: 102.32 + 2028-01-01: 106.72 + 2029-01-01: 112.68 + 2030-01-01: 117.5 + 2031-01-01: 125.13 + 2032-01-01: 131.5 + 2033-01-01: 140.4 + 2034-01-01: 149.07 + 2035-01-01: 156.27 diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml new file mode 100644 index 00000000000..e70f8535fae --- /dev/null +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml @@ -0,0 +1,60 @@ +description: The Medicare Trustees report and project this Part B premium income per Medicare enrollee, which counts premiums paid by or on behalf of enrollees, including income-related premiums and premiums that state Medicaid programs pay. +metadata: + unit: currency-USD + period: year + label: Medicare Part B premium income per enrollee + # From 2036, each value is the 2035 value times the growth in Medicare + # spending per enrollee, so premiums keep their 2035 share of spending. + uprating: calibration.gov.hhs.medicare.per_capita_cost + reference: + # Each value is premium income over Table V.B3's total enrollment (file + # page 196, thousands), people with Part A and/or Part B coverage. + # - 2015 to 2026: Table III.C7 (file page 102), "Premium income", $ + # millions, incurred basis. + # - 2027 to 2035: Table III.C4 (file page 96), "Premium income", $ + # billions, cash basis. Footnote 7 credits premiums withheld from the + # benefits due January 3, 2027 on December 31, 2026; their amount is + # III.C4's 2026 cash value less III.C7's 2026 incurred value (174.8 - + # 173.228 = 1.572), which is added back to 2027. Cash and incurred + # premium income agree in every year from 2017 to 2025 except 2020 and + # 2021, the other footnote 7 years. + # Premium income is "premium payments by (or on behalf of) enrollees" + # (file page 88). It includes income-related premiums: in 2019 the + # standard premium, $135.50 a month, times 56.019 million Part B enrollees + # plus Table V.E3's $8.4 billion of income-related premiums (file page + # 208) is $99.5 billion, against $99.4 billion of premium income. + # 2026 Medicare Trustees Report, transmitted 2026-06-09, retrieved + # 2026-10-11, sha256 + # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table III.C7 + href: https://www.cms.gov/oact/tr/2026#page=102 + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table III.C4 + href: https://www.cms.gov/oact/tr/2026#page=96 + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 + href: https://www.cms.gov/oact/tr/2026#page=196 + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Part B premium income + href: https://www.cms.gov/oact/tr/2026#page=88 +values: + # Historical. + 2015-01-01: 1_214.54 + 2016-01-01: 1_296.34 + 2017-01-01: 1_389.19 + 2018-01-01: 1_554.68 + 2019-01-01: 1_615.55 + 2020-01-01: 1_729.23 + 2021-01-01: 1_772.6 + 2022-01-01: 2_009.35 + 2023-01-01: 1_969.28 + 2024-01-01: 2_054.43 + 2025-01-01: 2_169.44 + # Trustees' intermediate estimates. + 2026-01-01: 2_448.69 + 2027-01-01: 2_549.32 + 2028-01-01: 2_755.79 + 2029-01-01: 2_946.87 + 2030-01-01: 3_178.93 + 2031-01-01: 3_409.4 + 2032-01-01: 3_662.85 + 2033-01-01: 3_985.68 + 2034-01-01: 4_334.37 + 2035-01-01: 4_652 diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml new file mode 100644 index 00000000000..1c8af7fff7f --- /dev/null +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml @@ -0,0 +1,57 @@ +description: The Medicare Trustees report and project this Part D premium income per Medicare enrollee, which counts premiums withheld from benefits, paid to the federal government or paid directly to plans, including income-related premiums. +metadata: + unit: currency-USD + period: year + label: Medicare Part D premium income per enrollee + # From 2036, each value is the 2035 value times the growth in Medicare + # spending per enrollee, so premiums keep their 2035 share of spending. + uprating: calibration.gov.hhs.medicare.per_capita_cost + reference: + # Each value is Table III.D3's "Premium income" (file page 116, $ + # billions, cash basis) over Table V.B3's total enrollment (file page 196, + # thousands), people with Part A and/or Part B coverage. Footnote 1: + # "Premiums include both amounts withheld from Social Security benefits or + # other Federal payments, direct payments to the Federal government, and + # those paid directly to Part D plans." Footnote 6 (file page 117) credits + # one January's withheld premiums on December 31 of the year before: about + # $0.2 billion in 2015, $0.1 billion in 2020 and an estimated $0.2 billion + # in 2026, which are moved to 2016, 2021 and 2027. Premium income includes + # income-related premiums, which are deposited into the Part D account + # (footnote 73, file page 151). So each value equals the Part D enrollment + # share times calibration.gov.hhs.medicare.part_d.premiums_per_enrollee, + # plus Table V.E4's aggregate income-related premiums (file page 218) per + # Medicare enrollee. 2026 Medicare Trustees Report, transmitted + # 2026-06-09, retrieved 2026-10-11, sha256 + # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table III.D3 + href: https://www.cms.gov/oact/tr/2026#page=116 + - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 + href: https://www.cms.gov/oact/tr/2026#page=196 +values: + # Historical. + 2015-01-01: 224.86 + 2016-01-01: 245.3 + 2017-01-01: 264.13 + 2018-01-01: 264.91 + 2019-01-01: 255.14 + 2020-01-01: 249.65 + 2021-01-01: 267.27 + 2022-01-01: 270.08 + 2023-01-01: 274.75 + 2024-01-01: 282.08 + # 2025 premiums fell with the voluntary Part D premium demonstration for + # stand-alone prescription drug plans (file page 109). + 2025-01-01: 215.04 + # Trustees' intermediate estimates. The 2030 jump is the Inflation + # Reduction Act's reset of the base beneficiary premium percentage + # (file page 154). + 2026-01-01: 281.3 + 2027-01-01: 356.74 + 2028-01-01: 389.05 + 2029-01-01: 404.32 + 2030-01-01: 674.95 + 2031-01-01: 708.2 + 2032-01-01: 720.06 + 2033-01-01: 752.61 + 2034-01-01: 776.68 + 2035-01-01: 809.85 diff --git a/policyengine_us/parameters/gov/household/cbo_social_insurance_benefits.yaml b/policyengine_us/parameters/gov/household/cbo_social_insurance_benefits.yaml index ac597fb7156..550ea17a0f1 100644 --- a/policyengine_us/parameters/gov/household/cbo_social_insurance_benefits.yaml +++ b/policyengine_us/parameters/gov/household/cbo_social_insurance_benefits.yaml @@ -2,7 +2,7 @@ description: Social insurance benefits included in CBO household income. values: 0000-01-01: - social_security - - medicare_gross_cost + - cbo_medicare_benefit - unemployment_compensation - workers_compensation @@ -10,3 +10,16 @@ metadata: unit: list period: year label: CBO social insurance benefits + reference: + # "Social insurance benefits consist of benefits provided through Social + # Security (Old Age, Survivors, and Disability Insurance); Medicare + # (measured as the average cost to the government of providing those + # benefits, net of offsetting receipts); regular unemployment insurance + # ...; and workers' compensation." (Appendix A, note 3.) + - title: Congressional Budget Office, The Distribution of Household Income in 2021, Appendix A + href: https://www.cbo.gov/system/files/2024-09/60341-income.pdf#page=27 + # "The measure of Medicare benefits in The Distribution of Household + # Income includes the federal government's average cost per enrollee of + # providing Medicare, net of premiums paid by enrollees." + - title: Congressional Budget Office, Sensitivity of the Distribution of Household Income to the Treatment of Health Insurance From 1979 to 2021 + href: https://www.cbo.gov/publication/61910 diff --git a/policyengine_us/tests/policy/baseline/household/income/household/cbo_household_income.yaml b/policyengine_us/tests/policy/baseline/household/income/household/cbo_household_income.yaml index 07d9f4f1d8e..d52fdf17f34 100644 --- a/policyengine_us/tests/policy/baseline/household/income/household/cbo_household_income.yaml +++ b/policyengine_us/tests/policy/baseline/household/income/household/cbo_household_income.yaml @@ -14,6 +14,7 @@ - name: CBO before-tax income adds social insurance and alias matches period: 2025 + absolute_error_margin: 0.01 input: employment_income: 40_000 employer_sponsored_insurance_premiums: 6_000 @@ -35,10 +36,14 @@ cbo_household_market_income: 49_102 # CMS Medicare spending per enrollee, 2025. medicare_gross_cost: 17_751 - # $12,000 + $17,751 + $2,000 + $1,000. - cbo_household_social_insurance_benefits: 32_751 - cbo_household_income_before_transfers_and_taxes: 81_853 - cbo_household_income: 81_853 + # $17,751 less 2025 premium income per Medicare enrollee ($82.26 Part A, + # $2,169.44 Part B, $215.04 Part D) and the $251.12 Part D low-income + # subsidy per Medicare enrollee. + cbo_medicare_benefit: 15_033.14 + # $12,000 + $15,033.14 + $2,000 + $1,000. + cbo_household_social_insurance_benefits: 30_033.14 + cbo_household_income_before_transfers_and_taxes: 79_135.14 + cbo_household_income: 79_135.14 - name: CBO means-tested transfers include only the listed programs period: 2026 diff --git a/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py b/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py new file mode 100644 index 00000000000..1a4e1d96df5 --- /dev/null +++ b/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py @@ -0,0 +1,36 @@ +from policyengine_us.model_api import * + + +class cbo_medicare_benefit(Variable): + value_type = float + entity = Person + label = "CBO Medicare benefit" + documentation = ( + "Medicare benefit as the Congressional Budget Office counts it in " + "household income: the government's average cost per enrollee of " + "providing Medicare Parts A, B and D, net of premiums paid by or on " + "behalf of enrollees. CBO assigns the same average to every " + "enrollee and counts the Part D low-income subsidy separately as a " + "means-tested transfer, so this subtracts per-enrollee averages of " + "premium income and of the low-income subsidy from Medicare " + "spending per enrollee, rather than the person's own premiums." + ) + unit = USD + definition_period = YEAR + reference = ( + "https://www.cbo.gov/publication/61910", + "https://www.cbo.gov/system/files/2024-09/60341-income.pdf#page=27", + "https://www.cbo.gov/system/files/2018-07/54234-workingpaper.pdf#page=46", + ) + defined_for = "medicare_enrolled" + + def formula(person, period, parameters): + p = parameters(period).calibration.gov.hhs.medicare + premiums = p.premium_income_per_enrollee + total_premiums = premiums.part_a + premiums.part_b + premiums.part_d + net = ( + p.per_capita_cost + - total_premiums + - p.part_d_low_income_subsidy_per_enrollee + ) + return max_(net, 0) diff --git a/policyengine_us/variables/gov/hhs/medicare/costs/medicare_gross_cost.py b/policyengine_us/variables/gov/hhs/medicare/costs/medicare_gross_cost.py index 48533e92fb4..1baeeaf188a 100644 --- a/policyengine_us/variables/gov/hhs/medicare/costs/medicare_gross_cost.py +++ b/policyengine_us/variables/gov/hhs/medicare/costs/medicare_gross_cost.py @@ -7,12 +7,19 @@ class medicare_gross_cost(Variable): label = "Gross Medicare cost" documentation = ( "Annual Medicare spending on behalf of the beneficiary before " - "subtracting beneficiary premiums. This matches the gross Medicare " - "benefit concept used in the CBO household-income framework." + "subtracting beneficiary premiums: CMS Medicare spending per " + "enrollee, which covers Parts A through D, including the Part D " + "low-income subsidy. CBO's standard household income counts " + "Medicare net of premiums instead (cbo_medicare_benefit); CBO adds " + "the premiums back only in an expanded sensitivity measure, which " + "it calls gross Medicare spending." ) unit = USD definition_period = YEAR - reference = "https://www.cms.gov/about-cms/what-we-do/medicare" + reference = ( + "https://www.cms.gov/about-cms/what-we-do/medicare", + "https://www.cbo.gov/publication/61910", + ) defined_for = "medicare_enrolled" def formula(person, period, parameters): diff --git a/policyengine_us/variables/household/income/household/cbo_household_social_insurance_benefits.py b/policyengine_us/variables/household/income/household/cbo_household_social_insurance_benefits.py index b39c09e5db5..82ecc087d38 100644 --- a/policyengine_us/variables/household/income/household/cbo_household_social_insurance_benefits.py +++ b/policyengine_us/variables/household/income/household/cbo_household_social_insurance_benefits.py @@ -7,8 +7,8 @@ class cbo_household_social_insurance_benefits(Variable): label = "CBO household social insurance benefits" documentation = ( "Social insurance benefits included in CBO household income: Social " - "Security, gross Medicare benefits, unemployment insurance, and " - "workers' compensation." + "Security, Medicare benefits net of enrollee premiums, unemployment " + "insurance, and workers' compensation." ) definition_period = YEAR unit = USD From 3d8bb6d64327a418f56ea674d1690206ad1d20cf Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 11 Oct 2026 16:15:40 -0400 Subject: [PATCH 2/7] Test cbo_medicare_benefit and its Trustees series YAML: the 2025, 2015 and 2035 values, and five people with different premiums (Part A premium, income-related premiums, under 65, not enrolled) who all get the same average. Python, parameters only: transcription and conservation against the Trustees cells, the Part D series against #10111's share x premium plus income-related premiums, Part B premium income including income-related premiums, bounds through 2200, the post-2035 extension keeping each series' share of spending, and January reads. Co-Authored-By: Claude Opus 5.5 --- .../premium_income_per_enrollee/part_b.yaml | 7 +- .../core/test_cbo_medicare_benefit_series.py | 220 ++++++++++++++++++ .../medicare/costs/cbo_medicare_benefit.yaml | 111 +++++++++ 3 files changed, 335 insertions(+), 3 deletions(-) create mode 100644 policyengine_us/tests/core/test_cbo_medicare_benefit_series.py create mode 100644 policyengine_us/tests/policy/baseline/gov/hhs/medicare/costs/cbo_medicare_benefit.yaml diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml index e70f8535fae..53b67c103aa 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml @@ -20,9 +20,10 @@ metadata: # 2021, the other footnote 7 years. # Premium income is "premium payments by (or on behalf of) enrollees" # (file page 88). It includes income-related premiums: in 2019 the - # standard premium, $135.50 a month, times 56.019 million Part B enrollees - # plus Table V.E3's $8.4 billion of income-related premiums (file page - # 208) is $99.5 billion, against $99.4 billion of premium income. + # standard premium, $135.50 a month (Table III.C2, file page 89), times + # 56.019 million Part B enrollees plus Table V.E3's $8.4 billion of + # income-related premiums (file page 215) is $99.5 billion, against $99.4 + # billion of premium income. # 2026 Medicare Trustees Report, transmitted 2026-06-09, retrieved # 2026-10-11, sha256 # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. diff --git a/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py b/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py new file mode 100644 index 00000000000..c3da92714a1 --- /dev/null +++ b/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py @@ -0,0 +1,220 @@ +"""The per-enrollee series that ``cbo_medicare_benefit`` subtracts. + +CBO counts Medicare in household income at the government's average cost +per enrollee, net of premiums paid by enrollees, and counts the Part D +low-income subsidy separately. ``cbo_medicare_benefit`` takes CMS Medicare +spending per enrollee (``calibration.gov.hhs.medicare.per_capita_cost``) and +subtracts four series under ``calibration.gov.hhs.medicare``, each an +aggregate from the 2026 Medicare Trustees Report over Table V.B3's total +enrollment (people with Part A and/or Part B): + +- ``premium_income_per_enrollee.part_a``: Table III.B4 premiums from + voluntary enrollees. +- ``premium_income_per_enrollee.part_b``: Table III.C7 incurred premium + income through 2026, then Table III.C4 cash premium income, with the + December 31, 2026 credit moved back to 2027. +- ``premium_income_per_enrollee.part_d``: Table III.D3 premium income with + footnote 6's December 31 credits moved back a year. +- ``part_d_low_income_subsidy_per_enrollee``: Table IV.B10 low-income + subsidy (the 2025 report for 2015). + +These tests read parameters only; the YAML tests cover the variable. + +Invariants: + +1. Transcription: every value equals its formula applied to the Trustees' + published cells, rounded as stored. +2. Conservation: each series times total enrollment returns its published + aggregate, within the cells' rounding. +3. Differential: the Part D series equals the Part D enrollment share times + ``part_d.premiums_per_enrollee`` (which excludes income-related premiums, + per Part D enrollee) plus Table V.E4's income-related premiums per + Medicare enrollee: two derivations from different cells agree. +4. Part B premium income includes income-related premiums: in 2019 the + standard premium times Part B enrollment plus Table V.E3's aggregate + income-related premiums reproduces it within 0.5 percent, while the + standard premium alone falls more than 5 percent short. +5. Bounds: every series is positive, and net Medicare spending per enrollee + stays between 0 and gross spending, in every year from 2015 to 2200. +6. Extension: from 2036 to 2100 each series grows with Medicare spending + per enrollee, so each keeps its 2035 share of spending; later years hold + the 2100 value. +7. Calendar years: every date in a year reads the January 1 value. +""" + +import pytest +from hypothesis import given +from hypothesis import strategies as st +from policyengine_core.parameters.operations.get_parameter import get_parameter + +from policyengine_us.system import system + +MEDICARE = "calibration.gov.hhs.medicare" +SERIES = { + "part_a": f"{MEDICARE}.premium_income_per_enrollee.part_a", + "part_b": f"{MEDICARE}.premium_income_per_enrollee.part_b", + "part_d": f"{MEDICARE}.premium_income_per_enrollee.part_d", + "lis": f"{MEDICARE}.part_d_low_income_subsidy_per_enrollee", +} +SPENDING = f"{MEDICARE}.per_capita_cost" +FIRST_YEAR, LAST_PROJECTED_YEAR, END_YEAR = 2015, 2035, 2100 +YEARS = range(FIRST_YEAR, LAST_PROJECTED_YEAR + 1) + + +def _cells(*values): + return dict(zip(YEARS, values)) + + +# 2026 Medicare Trustees Report (sha256 ffa56b91...8fa8), file pages. +# Table V.B3 (page 196), total enrollment, thousands. +TOTAL_ENROLLMENT = _cells( + *(55_589, 57_073, 58_683, 60_020, 61_535, 62_887, 63_980, 65_166), + *(66_606, 68_066, 69_289, 70_743, 72_322, 74_026, 75_436, 76_598), + *(77_521, 78_327, 79_058, 79_827, 80_632), +) +# Table III.B4 (page 64), premiums from voluntary enrollees, $ billions. +PART_A_PREMIUMS = _cells( + *(3.2, 3.3, 3.5, 3.6, 3.9, 4.0, 4.2, 4.5, 4.7, 4.8, 5.7), + *(6.9, 7.4, 7.9, 8.5, 9.0, 9.7, 10.3, 11.1, 11.9, 12.6), +) +# Table III.C7 (page 102), premium income, incurred basis, $ millions. +PART_B_INCURRED = dict( + zip( + range(2015, 2027), + ( + *(67_515, 73_986, 81_522, 93_312, 99_413, 108_746, 113_411), + *(130_941, 131_166, 139_837, 150_318, 173_228), + ), + ) +) +# Table III.C4 (page 96), premium income, cash basis, $ billions. +PART_B_CASH = _cells( + *(69.4, 72.1, 81.5, 93.3, 99.4, 111.2, 111.0, 130.9, 131.2, 139.8, 150.3), + *(174.8, 182.8, 204.0, 222.3, 243.5, 264.3, 286.9, 315.1, 346.0, 375.1), +) +# Table III.D3 (page 116), premium income, cash basis, $ billions, and +# footnote 6's December 31 credits (page 117). +PART_D_CASH = _cells( + *(12.7, 13.8, 15.5, 15.9, 15.7, 15.8, 17.0, 17.6, 18.3, 19.2, 14.9), + *(20.1, 25.6, 28.8, 30.5, 51.7, 54.9, 56.4, 59.5, 62.0, 65.3), +) +PART_D_DECEMBER_31_CREDIT = {2015: 0.2, 2020: 0.1, 2026: 0.2} +# Table IV.B10 (page 159), low-income subsidy, $ billions; 2015 from the +# 2025 report's Table IV.B10 (page 159). +LOW_INCOME_SUBSIDY = _cells( + *(25.6, 26.4, 27.3, 28.5, 29.7, 33.0, 35.0, 39.4, 44.2, 41.2, 17.4), + *(18.1, 20.5, 22.1, 24.5, 28.9, 30.7, 31.7, 32.4, 33.3, 34.8), +) +# Table V.E4 (page 218), Part D income-related premiums, $ billions. +PART_D_IRMAA = _cells( + *(0.9, 1.0, 1.2, 1.4, 1.6, 1.8, 1.8, 1.7, 2.2, 2.2, 2.4, 3.1, 3.5), + *(4.0, 4.6, 10.8, 11.9, 12.6, 13.7, 14.7, 15.9), +) +# 2019: Table III.C2 (page 89) standard monthly premium, Table V.B3 Part B +# enrollment (thousands), Table V.E3 (page 215) income-related premiums +# ($ billions). +STANDARD_PART_B_PREMIUM_2019 = 135.50 +PART_B_ENROLLMENT_2019 = 56_019 +PART_B_IRMAA_2019 = 8.4 + + +def _part_b_billions(year): + if year in PART_B_INCURRED: + return PART_B_INCURRED[year] / 1e3 + # III.C4 footnote 7: January 2027 withholdings credited December 31, 2026. + december_31_credit = PART_B_CASH[2026] - PART_B_INCURRED[2026] / 1e3 + return PART_B_CASH[year] + (december_31_credit if year == 2027 else 0) + + +def _part_d_billions(year): + return ( + PART_D_CASH[year] + - PART_D_DECEMBER_31_CREDIT.get(year, 0) + + PART_D_DECEMBER_31_CREDIT.get(year - 1, 0) + ) + + +AGGREGATES = { + "part_a": PART_A_PREMIUMS.get, + "part_b": _part_b_billions, + "part_d": _part_d_billions, + "lis": LOW_INCOME_SUBSIDY.get, +} + + +def _read(name, date): + return get_parameter(system.parameters, name)(date) + + +def _value(series, year): + return _read(SERIES[series], f"{year}-01-01") + + +def _spending(year): + return _read(SPENDING, f"{year}-01-01") + + +def _per_enrollee(billions, year): + return billions * 1e9 / (TOTAL_ENROLLMENT[year] * 1e3) + + +@pytest.mark.parametrize("series", SERIES) +@pytest.mark.parametrize("year", YEARS) +def test_series_is_the_trustees_aggregate_per_medicare_enrollee(series, year): + expected = _per_enrollee(AGGREGATES[series](year), year) + assert _value(series, year) == round(expected, 2) + + +@pytest.mark.parametrize("series", SERIES) +@pytest.mark.parametrize("year", YEARS) +def test_series_times_enrollment_returns_the_aggregate(series, year): + rebuilt = _value(series, year) * TOTAL_ENROLLMENT[year] * 1e3 / 1e9 + # Stored to the cent; enrollment of at most 81 million moves the + # aggregate by at most $0.0005 billion. + assert rebuilt == pytest.approx(AGGREGATES[series](year), abs=1e-3) + + +@pytest.mark.parametrize("year", YEARS) +def test_part_d_series_matches_share_times_premium_plus_irmaa(year): + share = _read(f"{MEDICARE}.part_d.enrollment_share", f"{year}-01-01") + premium = _read(f"{MEDICARE}.part_d.premiums_per_enrollee", f"{year}-01-01") + irmaa = _per_enrollee(PART_D_IRMAA[year], year) + # The share is stored to four decimals and the premium to the cent, so + # the product can be off by up to about $0.05. + assert share * premium + irmaa == pytest.approx(_value("part_d", year), abs=0.1) + + +def test_part_b_premium_income_includes_income_related_premiums(): + standard = STANDARD_PART_B_PREMIUM_2019 * 12 * PART_B_ENROLLMENT_2019 * 1e3 / 1e9 + published = _part_b_billions(2019) + assert standard + PART_B_IRMAA_2019 == pytest.approx(published, rel=0.005) + assert standard < published * 0.95 + + +@given(st.integers(FIRST_YEAR, END_YEAR + 100)) +def test_series_are_positive_and_net_spending_is_between_zero_and_gross(year): + deductions = sum(_value(series, year) for series in SERIES) + assert all(_value(series, year) > 0 for series in SERIES) + assert 0 < _spending(year) - deductions < _spending(year) + + +@pytest.mark.parametrize("series", SERIES) +def test_extension_keeps_the_2035_share_of_spending(series): + share_2035 = _value(series, LAST_PROJECTED_YEAR) / _spending(LAST_PROJECTED_YEAR) + for year in range(LAST_PROJECTED_YEAR + 1, END_YEAR + 1): + assert _value(series, year) / _spending(year) == pytest.approx( + share_2035, rel=1e-9 + ) + + +@given(st.integers(END_YEAR, END_YEAR + 100)) +def test_series_hold_the_2100_values_afterwards(year): + for series in SERIES: + assert _value(series, year) == _value(series, END_YEAR) + + +@given(st.integers(FIRST_YEAR, END_YEAR), st.integers(1, 12), st.integers(1, 28)) +def test_every_date_in_a_year_reads_the_january_value(year, month, day): + date = f"{year}-{month:02d}-{day:02d}" + for series in SERIES: + assert _read(SERIES[series], date) == _value(series, year) diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicare/costs/cbo_medicare_benefit.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicare/costs/cbo_medicare_benefit.yaml new file mode 100644 index 00000000000..f3e1652a12b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicare/costs/cbo_medicare_benefit.yaml @@ -0,0 +1,111 @@ +# cbo_medicare_benefit = Medicare spending per enrollee - premium income per +# Medicare enrollee (Parts A, B and D) - Part D low-income subsidy per +# Medicare enrollee, the same for every enrollee. +# 2025: $17,751 - $82.26 - $2,169.44 - $215.04 - $251.12 = $15,033.14. + +- name: Case 1, enrolled person gets the average net of premiums and the low-income subsidy. + period: 2025 + absolute_error_margin: 0.01 + input: + age: 70 + is_medicare_eligible: true + medicare_enrolled: true + output: + medicare_gross_cost: 17_751 + cbo_medicare_benefit: 15_033.14 + +# CBO assigns the average to every enrollee, so the person with 20 quarters +# of coverage (a $6,216 Part A premium in 2025) and the person paying the +# income-related premiums get the same value as the others, though each one's +# medicare_cost differs. +- name: Case 2, every enrollee gets the same value whatever premiums they pay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + premium_free_part_a: + age: 70 + is_medicare_eligible: true + medicare_enrolled: true + medicare_quarters_of_coverage: 40 + pays_part_a_premium: + age: 70 + is_medicare_eligible: true + medicare_enrolled: true + medicare_quarters_of_coverage: 20 + pays_irmaa: + age: 70 + is_medicare_eligible: true + medicare_enrolled: true + medicare_quarters_of_coverage: 40 + disabled_under_65: + age: 50 + is_medicare_eligible: true + medicare_enrolled: true + medicare_quarters_of_coverage: 40 + not_enrolled: + age: 70 + is_medicare_eligible: true + medicare_enrolled: false + tax_units: + tax_unit: + members: [premium_free_part_a] + adjusted_gross_income: + 2023: 30_000 + tax_unit_2: + members: [pays_part_a_premium] + adjusted_gross_income: + 2023: 30_000 + tax_unit_3: + members: [pays_irmaa] + # IRMAA uses income from two years before. + adjusted_gross_income: + 2023: 1_000_000 + tax_unit_4: + members: [disabled_under_65] + tax_unit_5: + members: [not_enrolled] + households: + household: + members: + [ + premium_free_part_a, + pays_part_a_premium, + pays_irmaa, + disabled_under_65, + not_enrolled, + ] + output: + cbo_medicare_benefit: [15_033.14, 15_033.14, 15_033.14, 15_033.14, 0] + +- name: Case 3, first year of the series. + period: 2015 + absolute_error_margin: 0.01 + input: + age: 70 + is_medicare_eligible: true + medicare_enrolled: true + output: + # $11,929 - $57.57 - $1,214.54 - $224.86 - $460.52. + cbo_medicare_benefit: 9_971.51 + +- name: Case 4, last Trustees projection year. + period: 2035 + absolute_error_margin: 0.01 + input: + age: 70 + is_medicare_eligible: true + medicare_enrolled: true + output: + # $31,764.35 (the 2034 CMS value grown at the 2031-2032 rate) - $156.27 + # - $4,652 - $809.85 - $431.59. + cbo_medicare_benefit: 25_714.64 + +- name: Case 5, not enrolled. + period: 2025 + input: + age: 70 + is_medicare_eligible: true + medicare_enrolled: false + output: + cbo_medicare_benefit: 0 From b553a6782f22daebb162291e1e1ce07ee8e2faec Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 23:06:15 +0000 Subject: [PATCH 3/7] Merge duplicate references to one entry per source document CLAUDE.md asks for one reference entry per document with the page list in the title. The four Trustees calibration series listed the 2026 report two to four times with hrefs that differed only by #page=; each now has one entry naming every table and PDF page its comments cite (and the LIS series keeps a separate entry for the 2025 report). The CBO social-insurance list now cites Appendix D (PDF page 39) of the 2021 report alongside note 3, and the 2026 report's PDF page, and cbo_medicare_benefit notes the extra PDF pages of its 2021 and 2018 CBO references. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LwQq6HHj8EHZr9hwABoKJk --- .../part_d_low_income_subsidy_per_enrollee.yaml | 8 +++----- .../medicare/premium_income_per_enrollee/part_a.yaml | 6 +----- .../medicare/premium_income_per_enrollee/part_b.yaml | 8 +------- .../medicare/premium_income_per_enrollee/part_d.yaml | 6 ++---- .../gov/household/cbo_social_insurance_benefits.yaml | 12 +++++++++--- .../gov/hhs/medicare/costs/cbo_medicare_benefit.py | 2 ++ 6 files changed, 18 insertions(+), 24 deletions(-) diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml index 6e84c8d8cac..283b1c21244 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml @@ -18,12 +18,10 @@ metadata: # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8; 2025 # report sha256 # 1b3de7a4faeee5ad42059e10740603182b716a5fa7b53b30d360b45b9e474d95. - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10 - href: https://www.cms.gov/oact/tr/2026#page=159 - - title: 2025 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10 + - title: "2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables IV.B9, IV.B10 and V.B3 #page 119,158-159,196" + href: https://www.cms.gov/oact/tr/2026#page=119 + - title: "2025 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10" href: https://www.cms.gov/oact/tr/2025#page=159 - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 - href: https://www.cms.gov/oact/tr/2026#page=196 values: # Historical. 2015-01-01: 460.52 diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml index 5049d213595..83d19fa398b 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml @@ -15,12 +15,8 @@ metadata: # Medicaid buy-in payments are included. 2026 Medicare Trustees Report, # transmitted 2026-06-09, retrieved 2026-10-11, sha256 # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table III.B4 + - title: "2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables III.B4 and V.B3 and glossary #page 64,196,257" href: https://www.cms.gov/oact/tr/2026#page=64 - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 - href: https://www.cms.gov/oact/tr/2026#page=196 - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, glossary, Part A premium - href: https://www.cms.gov/oact/tr/2026#page=257 values: # Historical. 2015-01-01: 57.57 diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml index 53b67c103aa..8816f80ea85 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml @@ -27,13 +27,7 @@ metadata: # 2026 Medicare Trustees Report, transmitted 2026-06-09, retrieved # 2026-10-11, sha256 # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table III.C7 - href: https://www.cms.gov/oact/tr/2026#page=102 - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table III.C4 - href: https://www.cms.gov/oact/tr/2026#page=96 - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 - href: https://www.cms.gov/oact/tr/2026#page=196 - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Part B premium income + - title: "2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables III.C2, III.C4, III.C7, V.B3 and V.E3 #page 88-89,96,102,196,215" href: https://www.cms.gov/oact/tr/2026#page=88 values: # Historical. diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml index 1c8af7fff7f..5c6c965ea3c 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml @@ -23,10 +23,8 @@ metadata: # Medicare enrollee. 2026 Medicare Trustees Report, transmitted # 2026-06-09, retrieved 2026-10-11, sha256 # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table III.D3 - href: https://www.cms.gov/oact/tr/2026#page=116 - - title: 2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 - href: https://www.cms.gov/oact/tr/2026#page=196 + - title: "2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables III.D3, V.B3 and V.E4 #page 109,116-117,151,154,196,218" + href: https://www.cms.gov/oact/tr/2026#page=109 values: # Historical. 2015-01-01: 224.86 diff --git a/policyengine_us/parameters/gov/household/cbo_social_insurance_benefits.yaml b/policyengine_us/parameters/gov/household/cbo_social_insurance_benefits.yaml index 0114e084d1d..4228013adb3 100644 --- a/policyengine_us/parameters/gov/household/cbo_social_insurance_benefits.yaml +++ b/policyengine_us/parameters/gov/household/cbo_social_insurance_benefits.yaml @@ -15,11 +15,17 @@ metadata: # Security (Old Age, Survivors, and Disability Insurance); Medicare # (measured as the average cost to the government of providing those # benefits, net of offsetting receipts); regular unemployment insurance - # ...; and workers' compensation." (Appendix A, note 3.) - - title: Congressional Budget Office, The Distribution of Household Income in 2021, Appendix A + # ...; and workers' compensation." (Appendix A, note 3, PDF page 27.) + # Appendix D (PDF page 39) defines Medicare as "measured by the average + # cost to the government of providing those benefits", with no netting + # clause. + - title: "Congressional Budget Office, The Distribution of Household Income in 2021, Appendixes A and D #page 27,39" href: https://www.cbo.gov/system/files/2024-09/60341-income.pdf#page=27 # "The measure of Medicare benefits in The Distribution of Household # Income includes the federal government's average cost per enrollee of - # providing Medicare, net of premiums paid by enrollees." + # providing Medicare, net of premiums paid by enrollees." (Report PDF, + # 61910-DOHI-health.pdf, page 27; the same report lists "Medicare (net + # of premiums paid by enrollees)" on PDF pages 5 and 37.) CBO calls that + # measure plus enrollee premiums "gross Medicare spending". - title: Congressional Budget Office, Sensitivity of the Distribution of Household Income to the Treatment of Health Insurance From 1979 to 2021 href: https://www.cbo.gov/publication/61910 diff --git a/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py b/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py index 1a4e1d96df5..b3be036092e 100644 --- a/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py +++ b/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py @@ -19,7 +19,9 @@ class cbo_medicare_benefit(Variable): definition_period = YEAR reference = ( "https://www.cbo.gov/publication/61910", + # PDF pages 27, 39 "https://www.cbo.gov/system/files/2024-09/60341-income.pdf#page=27", + # PDF pages 46, 52 "https://www.cbo.gov/system/files/2018-07/54234-workingpaper.pdf#page=46", ) defined_for = "medicare_enrolled" From 1934f23840a3348b063f1fc96459f5c61e0c20a9 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 03:33:04 +0000 Subject: [PATCH 4/7] Extend the four Medicare per-enrollee series back to 2013 cbo_medicare_benefit subtracts these series from calibration.gov.hhs.medicare.per_capita_cost, which starts in 2013, but each series started in 2015. So cbo_household_income raised ParameterNotFoundError in 2013 and 2014 for any household with a Medicare enrollee, where main returns a value. The 2022 to 2026 Trustees Reports drop 2013 and 2014 from Tables III.B4, III.C7 and V.B3, so Part A, Part B and enrollment come from the 2021 report. Part D premium income comes from the 2026 report's Table III.D3, whose footnote 6 lists no December 31 credit in either year, and the low-income subsidy from the 2023 report's Table IV.B10, the newest that shows both years. Each value is the aggregate over Table V.B3's total enrollment, rounded to the cent. The 2021 report reproduces every stored 2015 and 2016 value to the cent. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01H3DAwxuFHxBaZvWgnqNt1E --- ...art_d_low_income_subsidy_per_enrollee.yaml | 19 ++++++++++++--- .../premium_income_per_enrollee/part_a.yaml | 23 +++++++++++++------ .../premium_income_per_enrollee/part_b.yaml | 14 +++++++++-- .../premium_income_per_enrollee/part_d.yaml | 16 ++++++++++--- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml index 283b1c21244..13b64f885af 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml @@ -7,9 +7,9 @@ metadata: # spending per enrollee, so the subsidy keeps its 2035 share of spending. uprating: calibration.gov.hhs.medicare.per_capita_cost reference: - # Each value is Table IV.B10's "Low-income subsidy" payments ($ billions, - # incurred basis) over Table V.B3's total enrollment (file page 196, - # thousands), people with Part A and/or Part B coverage, so it is per + # From 2015, each value is Table IV.B10's "Low-income subsidy" payments ($ + # billions, incurred basis) over Table V.B3's total enrollment (file page + # 196, thousands), people with Part A and/or Part B coverage, so it is per # Medicare enrollee, not per subsidy recipient. 2016 to 2035 come from the # 2026 report's Table IV.B10 (file page 159); 2015, which that table no # longer shows, from the 2025 report's (file page 159). The two reports @@ -22,8 +22,21 @@ metadata: href: https://www.cms.gov/oact/tr/2026#page=119 - title: "2025 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10" href: https://www.cms.gov/oact/tr/2025#page=159 + # 2013 and 2014: the 2023 report's Table IV.B10 (file page 159), + # "Low-income subsidy", $ billions, incurred basis, over the 2021 + # report's Table V.B3 total enrollment (file page 199, thousands). Both + # retrieved 2026-11-04; 2023 report sha256 + # 89daaf2909ae18648783f652c05114d007c5f902cc5fa5fad0f76d43f6ccfa67, + # 2021 report sha256 + # ef3d1fa77e99362c460f45b3d0ff0734181340e617675e21fde99276a520fc8e. + - title: "2023 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10 #page 159" + href: https://www.cms.gov/oact/tr/2023#page=159 + - title: "2021 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 #page 199" + href: https://www.cms.gov/files/document/2021-medicare-trustees-report.pdf#page=199 values: # Historical. + 2013-01-01: 441.87 + 2014-01-01: 449.04 2015-01-01: 460.52 2016-01-01: 462.57 2017-01-01: 465.21 diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml index 83d19fa398b..00979049564 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_a.yaml @@ -7,18 +7,27 @@ metadata: # spending per enrollee, so premiums keep their 2035 share of spending. uprating: calibration.gov.hhs.medicare.per_capita_cost reference: - # Each value is Table III.B4's "Premiums from voluntary enrollees" (file - # page 64, $ billions, cash basis) over Table V.B3's total enrollment - # (file page 196, thousands), which footnote 2 defines as the "Number of - # beneficiaries with HI and/or SMI coverage". The Part A premium is paid - # "by or on behalf of" these enrollees (glossary, file page 257), so state - # Medicaid buy-in payments are included. 2026 Medicare Trustees Report, - # transmitted 2026-06-09, retrieved 2026-10-11, sha256 + # From 2015, each value is Table III.B4's "Premiums from voluntary + # enrollees" (file page 64, $ billions, cash basis) over Table V.B3's + # total enrollment (file page 196, thousands), which footnote 2 defines as + # the "Number of beneficiaries with HI and/or SMI coverage". The Part A + # premium is paid "by or on behalf of" these enrollees (glossary, file + # page 257), so state Medicaid buy-in payments are included. 2026 Medicare + # Trustees Report, transmitted 2026-06-09, retrieved 2026-10-11, sha256 # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. - title: "2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables III.B4 and V.B3 and glossary #page 64,196,257" href: https://www.cms.gov/oact/tr/2026#page=64 + # 2013 and 2014: the 2021 report's Table III.B4 (file page 62), + # "Premiums from voluntary enrollees", $ billions, cash basis, over its + # Table V.B3 total enrollment (file page 199, thousands). 2021 report + # retrieved 2026-11-04, sha256 + # ef3d1fa77e99362c460f45b3d0ff0734181340e617675e21fde99276a520fc8e. + - title: "2021 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables III.B4 and V.B3 #page 62,199" + href: https://www.cms.gov/files/document/2021-medicare-trustees-report.pdf#page=62 values: # Historical. + 2013-01-01: 64.76 + 2014-01-01: 60.98 2015-01-01: 57.57 2016-01-01: 57.82 2017-01-01: 59.64 diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml index 8816f80ea85..31a541d5142 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_b.yaml @@ -7,8 +7,9 @@ metadata: # spending per enrollee, so premiums keep their 2035 share of spending. uprating: calibration.gov.hhs.medicare.per_capita_cost reference: - # Each value is premium income over Table V.B3's total enrollment (file - # page 196, thousands), people with Part A and/or Part B coverage. + # From 2015, each value is premium income over Table V.B3's total + # enrollment (file page 196, thousands), people with Part A and/or Part B + # coverage. # - 2015 to 2026: Table III.C7 (file page 102), "Premium income", $ # millions, incurred basis. # - 2027 to 2035: Table III.C4 (file page 96), "Premium income", $ @@ -29,8 +30,17 @@ metadata: # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. - title: "2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables III.C2, III.C4, III.C7, V.B3 and V.E3 #page 88-89,96,102,196,215" href: https://www.cms.gov/oact/tr/2026#page=88 + # 2013 and 2014: the 2021 report's Table III.C7 (file page 104), + # "Premium income", $ millions, incurred basis, over its Table V.B3 + # total enrollment (file page 199, thousands). Incurred premium income + # needs no cash timing adjustment. 2021 report retrieved 2026-11-04, + # sha256 ef3d1fa77e99362c460f45b3d0ff0734181340e617675e21fde99276a520fc8e. + - title: "2021 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables III.C7 and V.B3 #page 104,199" + href: https://www.cms.gov/files/document/2021-medicare-trustees-report.pdf#page=104 values: # Historical. + 2013-01-01: 1_201.53 + 2014-01-01: 1_213.05 2015-01-01: 1_214.54 2016-01-01: 1_296.34 2017-01-01: 1_389.19 diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml index 5c6c965ea3c..87f69b20c84 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml @@ -7,9 +7,9 @@ metadata: # spending per enrollee, so premiums keep their 2035 share of spending. uprating: calibration.gov.hhs.medicare.per_capita_cost reference: - # Each value is Table III.D3's "Premium income" (file page 116, $ - # billions, cash basis) over Table V.B3's total enrollment (file page 196, - # thousands), people with Part A and/or Part B coverage. Footnote 1: + # From 2015, each value is Table III.D3's "Premium income" (file page 116, + # $ billions, cash basis) over Table V.B3's total enrollment (file page + # 196, thousands), people with Part A and/or Part B coverage. Footnote 1: # "Premiums include both amounts withheld from Social Security benefits or # other Federal payments, direct payments to the Federal government, and # those paid directly to Part D plans." Footnote 6 (file page 117) credits @@ -25,8 +25,18 @@ metadata: # ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. - title: "2026 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Tables III.D3, V.B3 and V.E4 #page 109,116-117,151,154,196,218" href: https://www.cms.gov/oact/tr/2026#page=109 + # 2013 and 2014: the 2026 report's Table III.D3 (file page 116), + # "Premium income", $ billions, cash basis, over the 2021 report's + # Table V.B3 total enrollment (file page 199, thousands). Footnote 6 + # (2026 report, file page 117) lists no December 31 credit in 2013 or + # 2014, so neither year moves. 2021 report retrieved 2026-11-04, sha256 + # ef3d1fa77e99362c460f45b3d0ff0734181340e617675e21fde99276a520fc8e. + - title: "2021 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 #page 199" + href: https://www.cms.gov/files/document/2021-medicare-trustees-report.pdf#page=199 values: # Historical. + 2013-01-01: 188.56 + 2014-01-01: 210.66 2015-01-01: 224.86 2016-01-01: 245.3 2017-01-01: 264.13 From fdee6880dfcf133733e7effcb07fed3244698514 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 03:45:53 +0000 Subject: [PATCH 5/7] Test the 2013 and 2014 Medicare per-enrollee values Nothing tested a year before 2015: the Hypothesis bounds test started at 2015 and every YAML case was 2015 or later, so the 2013 and 2014 crash in cbo_household_income went unseen. - cbo_medicare_benefit.yaml: Cases 6 and 7 assert the 2013 and 2014 net values. Case 3 is renamed, since 2015 is no longer the series' first year. - cbo_household_income.yaml: the review's 2014 witness, an enrollee with $10,000 of earnings, asserts the net benefit and total income. - test_cbo_medicare_benefit_series.py: a transcription test recomputes each 2013 and 2014 value from the Trustees cells, and the bounds test now starts at 2013 and always tries 2013. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01H3DAwxuFHxBaZvWgnqNt1E --- .../core/test_cbo_medicare_benefit_series.py | 42 ++++++++++++++++--- .../medicare/costs/cbo_medicare_benefit.yaml | 24 ++++++++++- .../household/cbo_household_income.yaml | 15 +++++++ 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py b/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py index c3da92714a1..c567ed0e5c1 100644 --- a/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py +++ b/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py @@ -5,8 +5,9 @@ low-income subsidy separately. ``cbo_medicare_benefit`` takes CMS Medicare spending per enrollee (``calibration.gov.hhs.medicare.per_capita_cost``) and subtracts four series under ``calibration.gov.hhs.medicare``, each an -aggregate from the 2026 Medicare Trustees Report over Table V.B3's total -enrollment (people with Part A and/or Part B): +aggregate from the Medicare Trustees Reports over Table V.B3's total +enrollment (people with Part A and/or Part B). From 2015 they come from the +2026 report: - ``premium_income_per_enrollee.part_a``: Table III.B4 premiums from voluntary enrollees. @@ -18,6 +19,11 @@ - ``part_d_low_income_subsidy_per_enrollee``: Table IV.B10 low-income subsidy (the 2025 report for 2015). +2013 and 2014 take enrollment from the 2021 report and each numerator from +the newest report that still shows both years: the 2021 report for Parts A +and B, the 2026 report for Part D and the 2023 report for the low-income +subsidy. + These tests read parameters only; the YAML tests cover the variable. Invariants: @@ -35,7 +41,7 @@ income-related premiums reproduces it within 0.5 percent, while the standard premium alone falls more than 5 percent short. 5. Bounds: every series is positive, and net Medicare spending per enrollee - stays between 0 and gross spending, in every year from 2015 to 2200. + stays between 0 and gross spending, in every year from 2013 to 2200. 6. Extension: from 2036 to 2100 each series grows with Medicare spending per enrollee, so each keeps its 2035 share of spending; later years hold the 2100 value. @@ -43,7 +49,7 @@ """ import pytest -from hypothesis import given +from hypothesis import example, given from hypothesis import strategies as st from policyengine_core.parameters.operations.get_parameter import get_parameter @@ -117,6 +123,23 @@ def _cells(*values): PART_B_ENROLLMENT_2019 = 56_019 PART_B_IRMAA_2019 = 8.4 +# 2013 and 2014: Table V.B3 of the 2021 report (page 199) for enrollment, +# and each numerator from the newest report that still shows both years. +# Footnote 6 to Table III.D3 (2026 report, page 117) lists no December 31 +# credit in either year. +BACKFILL_YEARS = (2013, 2014) +BACKFILL_ENROLLMENT = {2013: 52_504, 2014: 54_115} +BACKFILL_BILLIONS = { + # 2021 report, Table III.B4 (page 62), cash basis. + "part_a": {2013: 3.4, 2014: 3.3}, + # 2021 report, Table III.C7 (page 104), incurred basis, $ millions. + "part_b": {2013: 63_085 / 1e3, 2014: 65_644 / 1e3}, + # 2026 report, Table III.D3 (page 116), cash basis. + "part_d": {2013: 9.9, 2014: 11.4}, + # 2023 report, Table IV.B10 (page 159), incurred basis. + "lis": {2013: 23.2, 2014: 24.3}, +} + def _part_b_billions(year): if year in PART_B_INCURRED: @@ -174,6 +197,14 @@ def test_series_times_enrollment_returns_the_aggregate(series, year): assert rebuilt == pytest.approx(AGGREGATES[series](year), abs=1e-3) +@pytest.mark.parametrize("series", SERIES) +@pytest.mark.parametrize("year", BACKFILL_YEARS) +def test_2013_and_2014_are_the_trustees_aggregate_per_medicare_enrollee(series, year): + billions = BACKFILL_BILLIONS[series][year] + expected = billions * 1e9 / (BACKFILL_ENROLLMENT[year] * 1e3) + assert _value(series, year) == round(expected, 2) + + @pytest.mark.parametrize("year", YEARS) def test_part_d_series_matches_share_times_premium_plus_irmaa(year): share = _read(f"{MEDICARE}.part_d.enrollment_share", f"{year}-01-01") @@ -191,7 +222,8 @@ def test_part_b_premium_income_includes_income_related_premiums(): assert standard < published * 0.95 -@given(st.integers(FIRST_YEAR, END_YEAR + 100)) +@given(st.integers(BACKFILL_YEARS[0], END_YEAR + 100)) +@example(BACKFILL_YEARS[0]) def test_series_are_positive_and_net_spending_is_between_zero_and_gross(year): deductions = sum(_value(series, year) for series in SERIES) assert all(_value(series, year) > 0 for series in SERIES) diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicare/costs/cbo_medicare_benefit.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicare/costs/cbo_medicare_benefit.yaml index f3e1652a12b..f767fa56302 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicare/costs/cbo_medicare_benefit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicare/costs/cbo_medicare_benefit.yaml @@ -78,7 +78,7 @@ output: cbo_medicare_benefit: [15_033.14, 15_033.14, 15_033.14, 15_033.14, 0] -- name: Case 3, first year of the series. +- name: Case 3, first year with enrollment from the 2026 Trustees Report. period: 2015 absolute_error_margin: 0.01 input: @@ -109,3 +109,25 @@ medicare_enrolled: false output: cbo_medicare_benefit: 0 + +- name: Case 6, first year of CMS spending per enrollee. + period: 2013 + absolute_error_margin: 0.01 + input: + age: 70 + is_medicare_eligible: true + medicare_enrolled: true + output: + # $11,483 - $64.76 - $1,201.53 - $188.56 - $441.87. + cbo_medicare_benefit: 9_586.28 + +- name: Case 7, second year of CMS spending per enrollee. + period: 2014 + absolute_error_margin: 0.01 + input: + age: 70 + is_medicare_eligible: true + medicare_enrolled: true + output: + # $11,683 - $60.98 - $1,213.05 - $210.66 - $449.04. + cbo_medicare_benefit: 9_749.27 diff --git a/policyengine_us/tests/policy/baseline/household/income/household/cbo_household_income.yaml b/policyengine_us/tests/policy/baseline/household/income/household/cbo_household_income.yaml index d52fdf17f34..642eb31834d 100644 --- a/policyengine_us/tests/policy/baseline/household/income/household/cbo_household_income.yaml +++ b/policyengine_us/tests/policy/baseline/household/income/household/cbo_household_income.yaml @@ -45,6 +45,21 @@ cbo_household_income_before_transfers_and_taxes: 79_135.14 cbo_household_income: 79_135.14 +- name: CBO income counts a Medicare enrollee net of premiums in 2014 + period: 2014 + absolute_error_margin: 0.01 + input: + age: 70 + medicare_enrolled: true + employment_income: 10_000 + output: + # $11,683 - $60.98 - $1,213.05 - $210.66 - $449.04. + cbo_medicare_benefit: 9_749.27 + # $10,891, the same household's CBO income without an enrollee, plus + # $9,749.27. Counting gross Medicare spending per enrollee ($11,683) + # instead gives $10,891 + $11,683 = $22,574. + cbo_household_income: 20_640.27 + - name: CBO means-tested transfers include only the listed programs period: 2026 input: From b779c4156b8e9be8b7dda0d643fb2a4616f0c5ba Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 03:50:38 +0000 Subject: [PATCH 6/7] Say what cbo_medicare_benefit nets as premium income The documentation said "net of premiums paid by or on behalf of enrollees", stating as fact a reading CBO's own wording ("premiums paid by enrollees") leaves open. Say instead that the series net premium income as the Medicare Trustees count it, which includes premiums state Medicaid programs pay, and that PolicyEngine counts those in Medicaid: medicaid_cost_if_enrolled spreads state totals whose MACPAC (2021-2022) and KFF sources include Medicaid's payments of Medicare premiums. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01H3DAwxuFHxBaZvWgnqNt1E --- .../hhs/medicare/costs/cbo_medicare_benefit.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py b/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py index b3be036092e..a2b0c748dd2 100644 --- a/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py +++ b/policyengine_us/variables/gov/hhs/medicare/costs/cbo_medicare_benefit.py @@ -8,12 +8,15 @@ class cbo_medicare_benefit(Variable): documentation = ( "Medicare benefit as the Congressional Budget Office counts it in " "household income: the government's average cost per enrollee of " - "providing Medicare Parts A, B and D, net of premiums paid by or on " - "behalf of enrollees. CBO assigns the same average to every " - "enrollee and counts the Part D low-income subsidy separately as a " - "means-tested transfer, so this subtracts per-enrollee averages of " - "premium income and of the low-income subsidy from Medicare " - "spending per enrollee, rather than the person's own premiums." + "providing Medicare Parts A, B and D, net of premium income " + "(premiums paid by or on behalf of enrollees, as the Medicare " + "Trustees count it; this includes premiums state Medicaid programs " + "pay, which PolicyEngine counts in Medicaid). CBO assigns the same " + "average to every enrollee and counts the Part D low-income subsidy " + "separately as a means-tested transfer, so this subtracts " + "per-enrollee averages of premium income and of the low-income " + "subsidy from Medicare spending per enrollee, rather than the " + "person's own premiums." ) unit = USD definition_period = YEAR From c9dfbc2bdaefe635cc674aba4ea2bfcc112862a9 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 5 Nov 2026 00:12:02 -0500 Subject: [PATCH 7/7] Start the Medicare series date test at 2013 and drop single pages from titles The date test now draws from 2013 and pins December 28, 2013, so a mid-year entry under a 2013 value fails it. Three reference titles drop the one page they cite; each href keeps it. Co-Authored-By: Claude Opus 5.5 --- .../hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml | 4 ++-- .../gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml | 2 +- .../tests/core/test_cbo_medicare_benefit_series.py | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml index 13b64f885af..10d1046d1d9 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/part_d_low_income_subsidy_per_enrollee.yaml @@ -29,9 +29,9 @@ metadata: # 89daaf2909ae18648783f652c05114d007c5f902cc5fa5fad0f76d43f6ccfa67, # 2021 report sha256 # ef3d1fa77e99362c460f45b3d0ff0734181340e617675e21fde99276a520fc8e. - - title: "2023 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10 #page 159" + - title: "2023 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table IV.B10" href: https://www.cms.gov/oact/tr/2023#page=159 - - title: "2021 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 #page 199" + - title: "2021 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3" href: https://www.cms.gov/files/document/2021-medicare-trustees-report.pdf#page=199 values: # Historical. diff --git a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml index 87f69b20c84..f2b346c0f37 100644 --- a/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml +++ b/policyengine_us/parameters/calibration/gov/hhs/medicare/premium_income_per_enrollee/part_d.yaml @@ -31,7 +31,7 @@ metadata: # (2026 report, file page 117) lists no December 31 credit in 2013 or # 2014, so neither year moves. 2021 report retrieved 2026-11-04, sha256 # ef3d1fa77e99362c460f45b3d0ff0734181340e617675e21fde99276a520fc8e. - - title: "2021 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3 #page 199" + - title: "2021 Annual Report of the Boards of Trustees of the Federal Hospital Insurance and Federal Supplementary Medical Insurance Trust Funds, Table V.B3" href: https://www.cms.gov/files/document/2021-medicare-trustees-report.pdf#page=199 values: # Historical. diff --git a/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py b/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py index c567ed0e5c1..c9b916752ce 100644 --- a/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py +++ b/policyengine_us/tests/core/test_cbo_medicare_benefit_series.py @@ -245,7 +245,8 @@ def test_series_hold_the_2100_values_afterwards(year): assert _value(series, year) == _value(series, END_YEAR) -@given(st.integers(FIRST_YEAR, END_YEAR), st.integers(1, 12), st.integers(1, 28)) +@given(st.integers(BACKFILL_YEARS[0], END_YEAR), st.integers(1, 12), st.integers(1, 28)) +@example(BACKFILL_YEARS[0], 12, 28) def test_every_date_in_a_year_reads_the_january_value(year, month, day): date = f"{year}-{month:02d}-{day:02d}" for series in SERIES: