Skip to content

Glide CMS health spending upraters to the Trustees' long-range growth rates - #10119

Open
MaxGhenis wants to merge 4 commits into
mainfrom
cms-long-range-glide
Open

MaxGhenis wants to merge 4 commits into
mainfrom
cms-long-range-glide

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

CMS's National Health Expenditure (NHE) projections stop in 2034, and the 2026 Medicare Trustees Report's detailed projections stop in 2035. After that, extend_parameter_values repeats a series' last projected growth rate every year to 2100. The Trustees' own long-range path does not do that. They interpolate from the short-range rate to a long-range rate over 2036–2050, then follow rates near GDP growth. Repeating the last rate puts every health series off that path by 2100: about 2.7 times too high for Medicare spending per enrollee (#10107), and 4% to 42% off for the out-of-pocket and private premium series.

This PR adds optional long_range_growth knots to extend_parameter_values. With knots, growth after the last projected year moves linearly from the measured short-range rate to the Trustees' 2050 rate, then to their 2100 rate. Without knots, every other series extends exactly as before.

What the Trustees report says

Source: 2026 Medicare Trustees Report, transmitted 2026-06-09, sha256 ffa56b9137006872300b0346149eae1613d09a172b6ba118aad48e66dfc48fa8. Page numbers are PDF file pages. Every statement below was read from the report this session.

  • Transition method. The Trustees set detailed growth rates for 2026–2035. For each of Parts A, B and D, "the assumed cost growth rates for years 11 through 25 of the projection period" are set by interpolating between the rate at the end of the short-range period and the rate at the start of the last 50 years (pp. 24, 180). From 2050 the long-range rates decline gradually to 2100 (pp. 23, 173). Only the 2050 and 2100 rates are published, so the path between those two knots is linear here. That straight line is the one approximation this PR makes.

  • Per capita overall health spending: GDP plus 0.7 percent (4.3%) in 2050, declining gradually to GDP plus 0.4 percent (4.1%) by 2100. This comes from the factors model, which holds insurance coverage unchanged over the long range (pp. 173, 175).

  • Medicare cost growth, excluding demographic impacts:

    2050 2100 Pages
    Parts A, B and D combined 3.8% 3.7% 23, 180
    Part B 3.8% 3.8% ("remaining at") 23, 180
    Part D 4.1% 3.9% 23, 179

    Table II.C1's 2050–2100 averages are 3.7% total, 3.8% Part B and 4.0% Part D (p. 21).

  • How demographic effects enter a per-enrollee series. The cost growth rate is the increase in average expenditures per beneficiary before the effects of aging, the sex mix and proximity to death, "as the Trustees estimated these factors separately" (footnote 81, p. 172). These cost growth rates must then be modified for demographic impacts (pp. 23, 179). A series of spending per enrollee contains those effects. Table II.D1 (p. 29) puts the "beneficiary demographic mix" component at −0.1% a year in 2051–2100 for each of Parts A, B and D. So each Medicare per-enrollee knot is (1 + cost growth) × (1 − 0.001) − 1, for example 3.696% in 2050 and 3.596% in 2100 for all of Medicare. For 2036–2050, Table II.D1's mix is +0.2 (A), −0.1 (B) and −0.2 (D). Weighted by 2035 spending shares (Table V.B2, p. 194) that is about zero, and the interpolation handles it.

  • Private and out-of-pocket series. The Trustees publish no long-range private insurance rate: Table V.B5 (p. 200) leaves it blank after 2035. Those series use the per capita overall health spending rate. Two statements support that choice: the factors model holds coverage unchanged (p. 175), and the Trustees see "only a small likelihood that one part of the health sector could continue to grow indefinitely at significantly faster rates of growth than do other parts" (p. 177). Neither ESI nor out-of-pocket spending gets a demographic adjustment, because the Trustees publish none for them.

  • Premiums follow per-enrollee costs. The standard Part B premium "is set at the level of about 25 percent of average expenditures for beneficiaries aged 65 and over" (p. 97). From 2024, the Part D base beneficiary premium is the lesser of 25.5% of expected plan costs and the prior year's premium plus 6% (p. 113). With long-range cost growth near 4%, the 6% cap does not bind, so the premium grows with plan costs.

Check against the Trustees' own aggregates

The test below is independent of the knots' derivation. Take the Trustees' growth in incurred Medicare expenditures (Table V.B5, p. 200) and divide by their enrollment growth (Table V.B3, HI and/or SMI, p. 196). That implies per-enrollee growth for each long-range period. Starting the glide from Table V.D1's 2035 per-beneficiary growth (5.4%, p. 210), the knots reproduce it:

Period Expenditure growth (V.B5) Enrollment growth (V.B3) Implied per enrollee Glide Current rule
2036–2050 4.9% 0.38% 4.50% 4.49% 5.40%
2051–2075 4.3% 0.62% 3.66% 3.67% 5.40%
2076–2100 3.8% 0.14% 3.65% 3.62% 5.40%

The Part B and Part D knots against Table II.D1 (total increase net of beneficiary growth):

II.D1 total Beneficiaries Implied Glide (from V.D1 2035)
Part B 2036–2050 5.6% 0.4% 5.18% 5.09%
Part B 2051–2100 4.1% 0.4% 3.69% 3.70%
Part D 2036–2050 3.9% 0.4% 3.49% 3.58%
Part D 2051–2100 4.3% 0.4% 3.88% 3.89%

All of these agree within the tables' rounding to a tenth of a point.

Size of the change

Levels in 2050 and 2100 under the current rule and under the glide (scripts/quantify2.py, which imports the PR's helper and knots):

Series Status Last projected growth 2050 now 2050 glide Δ 2100 now 2100 glide Δ
moop_per_capita (main's values) wired 3.59% 4,018 4,246 +5.7% 23,388 33,184 +41.9%
moop_per_capita (#10084's values) wired 4.15% 4,812 4,873 +1.3% 36,679 38,082 +3.8%
esi_premium_per_enrollee wired 4.50% 26,537 26,111 −1.6% 239,554 204,072 −14.8%
direct_purchase_premium_per_enrollee #10085 4.71% 20,014 19,364 −3.2% 199,513 151,342 −24.1%
medicare.per_capita_cost #10107 5.43% (2031–32) 70,189 60,995 −13.1% 986,356 365,394 −63.0%
medicare_part_b_premium_per_enrollee (monthly) #10085 6.53% 931 751 −19.3% 21,998 4,612 −79.0%
part_d.premiums_per_enrollee #10111 3.29% 1,173 1,239 +5.6% 5,910 8,367 +41.6%

Main's moop_per_capita grows only 3.59% after 2033 because its 2033–2035 values are themselves extrapolated at the 2031–2032 rate. #10084 replaces them with the 2025–2034 NHE release, which is why the glide's effect on that series shrinks after #10084.

Long-run microsim

Pending: queued on the shared heavy lock. It runs base (main 065d0e9560) and this PR for 2050 and 2100 on the default dataset. Results will be added here.

Invariants

Tested in tests/core/test_long_range_health_growth.py: Hypothesis properties, a differential test against an independent numpy implementation, and published-table checks.

  1. Knots: the rate in a knot year is that knot's rate exactly.
  2. Betweenness: every rate lies between the two knots around it; after the last knot the rate holds.
  3. Closed form: values equal the last projected value times the product of 1 + rate. This is checked against np.interp plus np.cumprod for random series and for the two wired CMS series.
  4. Back-compatibility: knots equal to the short-range rate reproduce V_L (1 + g)^(y − L). Passing no knots leaves the old rule unchanged; it is the same code path.
  5. Monotonicity: raising any knot never lowers any extended value.
  6. Homogeneity: scaling the projected level scales every extended value by the same factor.
  7. Boundaries: projected years are untouched, and years after the end year hold the end-year value.
  8. Trustees consistency: the two tables above, with tolerances of 0.1 point (V.B5) and 0.15 point (II.D1).

The existing ESI tests now assert the glide instead of a constant rate. test_esi_premium_microsim_uprating.py already computes its expected factor from the parameter, so it needs no change.

Not done here

axiom: n/a: uprating extension of calibration series only (no policy rule)

🤖 Generated with Claude Code

MaxGhenis and others added 4 commits October 11, 2026 16:15
extend_parameter_values gains long_range_growth knots: after the last
projected year, growth moves linearly from the measured short-range rate
to the 2026 Medicare Trustees' 2050 and 2100 rates, as the Trustees
interpolate years 11-25 of their projection. moop_per_capita and
esi_premium_per_enrollee now glide to per capita health spending growth
(4.3% in 2050, 4.1% in 2100); Medicare, Part B and Part D per-enrollee
knots include the -0.1%/yr demographic mix from Table II.D1.

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

Copy link
Copy Markdown
Contributor Author

The CI run on this pull request was cancelled at 23:27Z on 2026-10-11 to free the organization's shared GitHub runners for an urgent fix in another repository. The US + core hub will re-run it automatically (cancelled jobs only; jobs that had passed are kept). Nothing in this pull request changed. Please don't push or reopen just to restart CI.

@DTrim99

DTrim99 commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Glide CMS health spending upraters to the Trustees' long-range growth rates

PR #10119 (author: MaxGhenis, head 5ea0535333, merge-base 065d0e9560). 6 files (+498/−19), 4 commits. Axiom: n/a: uprating extension of calibration series only (no policy rule).

Summary

After a series' last projected year, extend_parameter_values repeats the last projected growth rate every year to 2100. This PR adds optional long_range_growth knots. With knots, growth moves linearly from the measured short-range rate, placed at the last projected year, to the 2026 Medicare Trustees' 2050 rate and then to their 2100 rate. After 2100 the value holds, as before.

  • Wired:
    • calibration.gov.hhs.cms.moop_per_capita, the uprater for 11 medical expense inputs (prescription, physician, inpatient, outpatient, ER, urgent care, ambulance, imaging, lab, over-the-counter and other medical expenses).
    • calibration.gov.hhs.cms.esi_premium_per_enrollee, the uprater for employer_sponsored_insurance_premiums, pre_tax_health_insurance_premiums and, on main since Uprate premium inputs by premium series, not CMS out-of-pocket spending #10085, health_insurance_premiums_without_medicare_part_b and other_health_insurance_premiums.
    • Both glide to per capita overall health spending growth: 4.3 percent in 2050, falling to 4.1 percent in 2100.
  • Defined but not wired: Medicare, Part B and Part D per-enrollee knots, which compound the Trustees' cost growth rates with a −0.1 percent demographic mix.
  • Years affected: 2035 to 2100 only. Every projected year is unchanged.

The method and inputs are right:

  • The sources check out. I downloaded the 2026 Trustees Report, and its sha256 matches the PR's. Every page and quote the code and PR body cite is correct.
  • The arithmetic is right. I reproduced the glide by hand for eight years. Each PR-body effect size reproduces to the dollar on a parameter-only load of the head, the merge-base, main and a resolved merge.
  • The Trustees-consistency tables reproduce from the published tables, independently of the PR's code.
  • CI is green, and all 24 new or changed test items ran and passed.

Two should-fixes, both caused by today's merges to main:

Three suggestions follow.

Critical (must fix)

None.

Should address

1. Merging main breaks two of main's out-of-pocket tests and leaves five stale descriptions of the old extension rule.

  • What changed on main. Update CMS out-of-pocket per-capita uprater to NHE projections 2025-2034 #10084 (merged 2026-10-13) replaced moop_per_capita with the NHE 2025–2034 release. It moved the series' last projected year from 2035 to 2034 and added tests and comments for the constant extension rule: "each year from 2035 to 2100 grows by 2,512 / 2,412".
  • The code merges correctly. git merge-tree puts main's last_projected_year=2034 together with this PR's long_range_growth=HEALTH_SPENDING_PER_CAPITA_LONG_RANGE_GROWTH. The textual conflict is in comments only (Branch status).
  • The out-of-pocket series then glides. On the resolved merge:
    • 2035 growth is 4.1556 percent: 4.1459 + (4.3 − 4.1459) / 16. The constant rule gives 4.1459 percent.
    • 2050 growth is 4.3 percent.
  • Two tests then fail. Both check growth at rel=1e-12, and the 2035 gap is 9.2e-5 relative:
    • tests/core/test_cms_moop_uprating.py:252, test_extension_holds_the_last_projected_growth_rate, asserts growth == pytest.approx(EXTENSION_GROWTH, rel=1e-12) with EXTENSION_GROWTH = 2_512 / 2_412 (line 151).
    • tests/policy/baseline/parameters/test_uprating_extensions.py:138, test_cms_moop_per_capita_extends_to_2100, makes the same assertion for 2035, 2036, 2050 and 2100. This file auto-merges: it keeps main's out-of-pocket test next to the PR's new ESI test.
  • Five places go stale without a conflict:
    • parameters/calibration/gov/hhs/cms/moop_per_capita.yaml:49-51 says "2035 to 2100 grow at the 2033-2034 rate (2_512 / 2_412, 4.1% a year)".
    • tests/core/test_cms_moop_uprating.py describes the same rule in its docstring (lines 8–9) and in invariant 5 (line 30).
    • docs-quarto/methodology/spm-poverty.qmd:53 says premium inputs follow "premium series instead, each a per-person series that grows at its last published one-year rate to 2100 and holds the 2100 value after that". After this PR, the ESI premium series glides instead.
    • tests/core/test_premium_input_uprating.py:58, invariant 6, says "each index grows at its last published one-year rate". Its test (SPANS) leaves ESI out, so only the wording is wrong.
    • This PR's tests/core/test_long_range_health_growth.py:334 still anchors the out-of-pocket series at 2035. The test passes on the merge only because the straight line from (2034, 4.1459%) to (2050, 4.3%) also passes through 2035; the maximum relative error is 1e-15. So the test no longer pins the anchor.
  • Fix:
    • Merge main and resolve the comment conflict as Branch status describes.
    • Rewrite the two failing out-of-pocket tests the way this PR rewrote the ESI ones. With g = 2,512 / 2,412 − 1, assert:
      • growth(2035) = g + (0.043 − g) / 16
      • growth(2050) = 0.043
      • growth(2100) = 0.041
      • in test_cms_moop_uprating.py, the closed form against an independent np.interp and np.cumprod
    • Update the docstring and invariant 5 to match.
    • Replace the comment in moop_per_capita.yaml with the ESI file's wording: "From 2035, growth glides from the 2033-2034 rate (2_512 / 2_412, 4.1% a year) to the Medicare Trustees' long-range per capita health spending rates (4.3% in 2050, 4.1% in 2100), and later years hold the 2100 value".
    • Change WIRED_SERIES to (…moop_per_capita, 2034).
    • Reword the spm-poverty.qmd sentence and invariant 6 of test_premium_input_uprating.py so that the ESI series glides to the Trustees' rates and the other premium series keep their last rate.

2. The PR body no longer describes the merge.

Suggestions

1. Wire the series whose PRs have merged, or track them in an issue.

  • Why now. The reason for deferring was to keep Uprate premium inputs by premium series, not CMS out-of-pocket spending #10085's and Use CMS Medicare spending per enrollee for the Medicare per capita cost #10107's reviewed heads unchanged, and both have merged.

  • The gaps on main. direct_purchase_premium_per_enrollee, medicare_part_b_premium_per_enrollee and medicare.per_capita_cost still repeat their last rate.

    • Two premium series disagree. Direct purchase uses the same per capita knots as ESI, according to the PR body. After this PR, the ESI premium inputs glide while health_insurance_premiums (direct purchase) compounds at 4.71 percent.
    • The Medicare constants have no caller. MEDICARE_*_LONG_RANGE_GROWTH and with_medicare_demographic_mix are used only by tests.
  • Effect if wired. I computed these from main's parameter values and the PR's rule. They match the PR body.

    Series Last rate 2040 2050 2100
    direct_purchase_premium_per_enrollee 4.71% −0.5% −3.2% −24.1%
    medicare_part_b_premium_per_enrollee (monthly) 6.53% −2.6% −19.3% −79.0%
    medicare.per_capita_cost (growth_years=(2031, 2032)) 5.43% −2.1% −13.1% −63.0%
  • One wiring detail. medicare.per_capita_cost extends from 2034, so its glide would start at 2034 from 5.43 percent. The PR's Trustees-consistency test starts at 2035 from Table V.D1's 5.4 percent. If it's wired, align the test anchor, or check the 2034 anchor against the same tables.

2. Cite the Trustees' own NHE extension, and the shape of their 2050–2100 path.

  • The Trustees extend NHE the same way. The constant's comment justifies the transition with the Medicare interpolation for "each of Parts A, B, and D" (file pages 24 and 180). A more direct authority covers the NHE series: Table V.B5's footnote 1 (file page 200) says the Trustees' national health expenditure figures are "Based on a national health expenditure projections article published in July 2025 ... years after 2033 were determined based on the methods described in section IV.D". Section IV.D is the long-range cost growth section that begins on file page 172. Adding this reference shows that the Trustees extend CMS's NHE projections with the same long-range method.
  • Their 2050–2100 path isn't a straight line. The comment already says the path between 2050 and 2100 is "linear here". File page 175 gives the direction of that approximation: the income-technology elasticity "declines at a slowing pace" from 2050 to 2100, and the price elasticity "will follow a non-linear path". A clause saying so would help readers.
  • The docstring says more than the Trustees do. "The rate moves linearly between adjacent knots, as the Medicare Trustees interpolate" (long_range_growth_rate) reads as if the Trustees say "linearly". They say only "interpolating". Consider "the Trustees interpolate; this path is linear".

3. (Optional) Keep the knots in a calibration parameter.

  • Where they are now. HEALTH_SPENDING_PER_CAPITA_LONG_RANGE_GROWTH = {2050: 0.043, 2100: 0.041} and the Medicare knots are Python literals. Their provenance is in comments.
  • Why a parameter would help. A YAML file such as calibration/gov/hhs/medicare/trustees/long_range_per_capita_health_spending_growth.yaml, with #page=173 references, would show up in the parameter tree and could be cited or changed per scenario. set_all_uprating_parameters can read it, since the function already reads the raw tree.
  • Why this is optional. main already keeps sourced constants in this module, for example HSA_CONTRIBUTION_LIMIT_STATUTORY_BASES.

Verified correct

  • The source. I downloaded https://www.cms.gov/oact/tr/2026; its sha256 is ffa56b91…48fa8, as the code says. Each citation below shows the stated text or value:

    File page Content
    173 (printed 167) "the long-range per capita overall health spending growth is GDP plus 0.7 percent (or 4.3 percent) for 2050, gradually declining to GDP plus 0.4 percent by 2100 (or 4.1 percent)"
    24 and 180 "For each of Parts A, B, and D, the assumed cost growth rates for years 11 through 25 of the projection period ... are set by interpolating between the rate at the end of the short-range projection period and the rate at the start of the last 50 years"
    23 and 180 Part B 3.8 percent in 2050, "remaining at 3.8 percent by 2100"; Parts A, B and D combined 3.8 percent, "declining to 3.7 percent ... by 2100"
    23 and 179 Part D "decline from 4.1 percent in 2050 ... to 3.9 percent by 2100"
    172 Footnote 81: the Medicare cost growth rate "excludes the impacts of the aging of the population, changes in the sex composition ... and ... proximity to death"
    175 "insurance coverage is assumed to be unchanged over the long range"
    177 "only a small likelihood that one part of the health sector could continue to grow indefinitely at significantly faster rates of growth than do other parts"
    29 Table II.D1, beneficiary demographic mix: −0.1 in 2051–2100 for Parts A, B and D; +0.2, −0.1 and −0.2 in 2036–2050
    21 Table II.C1, 2050–2100: 3.7 total, 3.8 Part B, 4.0 Part D
    200 Table V.B5: incurred Medicare expenditures 4.9, 4.3 and 3.8; private health insurance "--" after 2035
    196 Table V.B3, HI and/or SMI: 80,632, 85,413, 99,585 and 103,133
    210 Table V.D1, 2035 per beneficiary growth: 5.4 total, 6.7 Part B, 3.1 Part D
    97 The Part B premium is "about 25 percent of average expenditures for beneficiaries aged 65 and over"
    113 The Part D base premium is "the lesser of 25.5 percent ... or the prior year's base beneficiary premium increased by 6 percent"
  • Glide arithmetic, by hand. For ESI, g₀ = 13,124 / 12,559 − 1 = 4.4988 percent, and each year from 2035 to 2050 moves (4.3 − 4.4988) / 16 = −0.012425 point.

    Year Rate Value
    2035 4.4863% 13,124 × 1.044863 = 13,712.79
    2036 4.4739% 14,326.29
    2040 4.4242%
    2045 4.3621%
    2050 4.3000% 26,110.71
    2060 4.3 − 10 × 0.004 = 4.26%
    2075 4.20%
    2100 4.10% 204,072.49

    2101 and 2150 hold the 2100 value. The parameter load matches every row.

  • Continuity and boundaries.

    • The first extended year moves 1/16 of the way from the last projected rate, so there is no step at the splice.
    • Every projected year is unchanged: head against merge-base for both series through 2034/2035, and the resolved merge against main through 2034.
    • Direct purchase, Part B and Medicare per capita cost are identical on the merge and on main.
  • Effect on the uprated inputs. These are the series values on the resolved merge against main:

    Series 2035 2040 2050 2075 2100
    ESI premium −0.01% −0.25% −1.60% −7.34% −14.81%
    Out-of-pocket +0.01% +0.19% +1.26% +3.77% +3.83%
    • A $1,000 prescription expense in 2024 becomes $2,986 in 2050 instead of $2,948.
    • An $8,000 ESI premium in 2024 becomes $204,072 in 2100 instead of $239,554.
    • No parameter uses either series as uprating: metadata, so the change reaches only these input variables, and only after 2034.
  • Code.

    • long_range_growth_rate (uprating_extensions.py:557-587):
      • It sorts the knots.
      • It rejects knots at or before the last projected year, and years up to that year.
      • It interpolates linearly, returns a knot's rate exactly in its year, and holds the last rate after the last knot.
    • Old rule untouched. With no knots, extend_parameter_values runs the old expression unchanged (if long_range_growth is None).
    • growth_years still works. The short-range rate comes from the growth_years ratio when one is given.
  • Trustees consistency. I computed these from the published tables, not from PR output:

    Period V.B5 expenditure growth V.B3 enrollment growth Implied per enrollee Glide from 5.4% in 2035
    2036–2050 4.9% 0.385% 4.498% 4.49%
    2051–2075 4.3% 0.616% 3.661% 3.67%
    2076–2100 3.8% 0.140% 3.655% 3.62%

    Against Table II.D1:

    Implied Glide
    Part B 2036–2050 1.056 / 1.004 − 1 = 5.18% 5.10%
    Part B 2051–2100 3.685% 3.696%
    Part D 2036–2050 3.486% 3.58%
    Part D 2051–2100 3.884% 3.894%

    All are within the tests' 0.1-point and 0.15-point tolerances.

  • Choice of rate for the out-of-pocket and ESI series. The Trustees publish no long-range out-of-pocket or private insurance rate. The overall per capita rate is a reasonable proxy, and the body discloses it:

    • The factors model holds coverage unchanged. That coverage is measured as cost-sharing (file page 175, footnote 90), which supports out-of-pocket spending growing with the total.
    • No demographic adjustment is applied, and none is published for these series.
  • The ACA benchmark claim. The uprater's 2024–2025 trend is 497 / 477 = 4.19 percent, between the two knots, as the body says.

  • Tests.

    • Hand checks. I checked these expectations by hand:
      • ESI growth(2035) = g₀ + (0.043 − g₀) / 16, and growth(2050) and growth(2100)
      • the 2150 hold
      • the first-segment closed form, with 0.05 − 0.00125 × offset
      • the Medicare knots: 1.038 × 0.999 − 1 = 3.6962% and 1.037 × 0.999 − 1 = 3.5963%
      • all seven Trustees-consistency figures
    • The property tests are meaningful. Each one fails if the glide misbehaves. For example, test_constant_knots_reproduce_compound_growth pins the no-change case to 100(1 + g)^(y − L + 1).
    • The differential test checks against an independent numpy implementation.
  • Changelog. changelog.d/cms-long-range-glide.changed.md is top-level and typed changed. "After 2034" is right once the branch merges main.

  • Local run. policyengine-core 3.26 can't import the head tree (_uprating_index_value is missing; CI uses ≥ 3.32.8). Instead, I loaded each tree's parameter directory and applied set_all_uprating_parameters directly, for the head, the merge-base, main and a resolved merge. The figures above come from those loads. I computed the post-merge test failures in Should 1 from the same values.

Axiom line assessment

Valid: n/a: uprating extension of calibration series only (no policy rule).

  • No legal provision changes. The PR changes only how two CMS calibration growth indexes extend after their last projected year. Those indexes age dataset inputs.
  • No statute or regulation sets these paths. The Trustees' rates are economic assumptions, not law, so RuleSpec has nothing to encode.
  • The unwired Medicare knots would also be n/a when wired. medicare.per_capita_cost is an expenditure estimate, and the Part B series is an input uprater.

CI status

All 26 checks pass (gh pr checks 10119, run 38172381802, attempt 2, on head 5ea0535333).

  • Skipped jobs. Three aggregate jobs from run 38171753724 show as skipping. The author's comment says that run was cancelled to free shared runners and re-run without changes.
  • The PR's tests ran. The "Python tests / Full Suite - Rest" log shows all 24 new or changed items passing:
    • 22 in test_long_range_health_growth.py, including both test_cms_series_glide_to_per_capita_health_spending cases
    • the ESI glide tests in test_esi_premium_uprating.py and test_uprating_extensions.py
    • The existing test_cms_moop_per_capita_extends_to_2100 also passed at the head. Its main version is the one that fails after the merge.
  • The ESI microsimulation uprating test passed in "Full Suite - Microsimulation". It reads its expected factor from the parameter.
  • Partner tests. The PR touches none, and the Household API Partners job passes.

Branch status

  • Position: 4 commits ahead of PolicyEngine/main (cee4d59284, 2026-10-13) and 61 behind.
  • Merge: git merge-tree --write-tree PolicyEngine/main 5ea0535333 conflicts in policyengine_us/parameters/uprating_extensions.py. There are two comment-only hunks, above the out-of-pocket and ESI extend_parameter_values calls.
    • The code lines merge cleanly and correctly. The out-of-pocket call gets main's last_projected_year=2034 (from Update CMS out-of-pocket per-capita uprater to NHE projections 2025-2034 #10084) and this PR's long_range_growth=..., and the ESI call gets the knots.
    • The constant block, the helper and the new extend_parameter_values argument merge without conflict.
    • test_uprating_extensions.py auto-merges, but it keeps main's constant-rule out-of-pocket test (Should 1).
  • Resolution:
    • Out-of-pocket hunk: keep main's "(January values, last projection year 2034). Health expense inputs use this as their uprater." Replace the constant-rule sentence with "Growth glides from the 2033-2034 rate to the Medicare Trustees' long-range per capita health spending rates."
    • ESI hunk: keep main's "Employer and employee premium inputs use this as their uprater." Add the PR's glide sentence.
    • Then make the test, YAML and docs updates in Should 1.
  • Checked on a resolved merge:
    • Growth for both wired series matches this PR's own glide tests. ESI: 4.4863 percent in 2035. Out-of-pocket: 4.1556 percent in 2035. Both: 4.3 percent in 2050 and 4.1 percent in 2100.
    • The other main series are unchanged.
    • The only failures are the two main tests named in Should 1.
  • Related PRs: Update CMS out-of-pocket per-capita uprater to NHE projections 2025-2034 #10084, Uprate premium inputs by premium series, not CMS out-of-pocket spending #10085 and Use CMS Medicare spending per enrollee for the Medicare per capita cost #10107 are merged; Subtract the expected Part D premium from medicare_cost #10111 (Part D) is still open.

Verdict: REQUEST_CHANGES

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every cited Trustees Report page and quote checks out, the glide arithmetic is right with no step at the splice, and projected years are unchanged. Two should items (see the comment above): (1) merged with main (#10084 moved out-of-pocket to the 2025-2034 NHE release), two main tests fail because they assert the constant last-rate rule (test_cms_moop_uprating.py::test_extension_holds_the_last_projected_growth_rate, test_uprating_extensions.py::test_cms_moop_per_capita_extends_to_2100), and five descriptions go stale, including the WIRED_SERIES anchor, which should be 2034. (2) The PR body is outdated: #10107 and #10085 have merged, the wired out-of-pocket effect is +3.8% in 2100, not +41.9%, and the microsim section is still pending.

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.

2 participants