Files
stack/tests/lead/paper.py
kert cb9976e160
All checks were successful
CI / lint (push) Successful in 44s
CI / notebooks-smoke (push) Successful in 1m33s
Deploy / changes (push) Successful in 14s
CI / test (push) Successful in 3m9s
Infra CI / zotero (push) Successful in 14s
Infra CI / notebooks (push) Successful in 55s
Infra CI / api (push) Successful in 1m9s
Infra CI / docs (push) Successful in 1m23s
Infra CI / llm (push) Successful in 1m1s
Infra CI / mc (push) Successful in 16s
Infra CI / bcda (push) Successful in 1m43s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Package Supply Chain / pkg-supply-chain (push) Successful in 1m30s
Deploy / api (push) Successful in 1m17s
Deploy / llm (push) Successful in 1m18s
Deploy / mc (push) Has been skipped
Deploy / bcda (push) Successful in 1m42s
Deploy / report (push) Successful in 1m36s
feat(lead): LEAD PY2027 financial methodology — settlement and benchmark engines
Ports the public CMS "LEAD Model PY 2027 Alignment and Financial
Methodology Paper" v1.2 (bib E4PEU3HV) as generic engines: parameters
come from the paper, everything CMS computes per ACO or per year comes
from the caller. No participant data, no organization-specific rules.

- lead.params: Table 5.2.1 discounts, 3% Quality Withhold, 2% retention
  incentive, Box 5.3.3 Stop-Loss bands, Tables 5.4.1/5.4.3 corridors, 2%
  sequestration, base-year weights, Table 3.5.1 ACPT guardrails,
  risk-score growth caps, REA/PSA shares and caps, voluntary guardrail
  and 500 minimum, Table 2.6.1 base-year alignment minimums.
- lead.settlement: Final Financial Settlement, Table 5.6.1 line by line
  (settle(SettlementInputs) -> SettlementLines).
- lead.stop_loss: Box 5.3.3 charge, banded payout, neutrality factor,
  application to PY expenditure.
- lead.monies_owed: Table 5.5.1 Total Monies Owed, APO reconciliation.
- lead.timing: run-out end, settlement-basis rule, settlement-stage inputs.
- lead.benchmark: §3 formulas — risk standardization, two-/three-way
  trend, base-year weights and sufficiency, voluntary guardrail,
  regional FFS, spending designation, REA, PSA, risk-score cap, hybrid
  alignment dollars, category blend.
- lead.express: the same as narwhals Exprs; express.settlement.settle
  settles a frame of scenarios on any backend.

Rounding: every dollar line rounds to the cent (half away from zero) as
it is produced; PBPMs, rates and factors never do. It is the only rule
under which Tables 3.3.3, 3.5.3.2, 3.5.4, 5.5.1 and 5.6.1 all reproduce
(3.5.4 line 24 sums cent-rounded cells; 3.3.3 carries unrounded PBPMs).
The Expr cents snaps its ÷100 with round(2): polars 2.0 divides a column
by a literal as a reciprocal multiply (k × 0.01), one ulp off k/100 for
~15% of values.

Missing inputs stay missing (None/null or a refused input model); the
only zeros are the paper's own (Professional "N/A" discount, no
Stop-Loss election, sequestration on losses, ineligible REA/PSA).

Paper inconsistencies recorded in tests: Table 5.5.1 line 2 is a cent
below Table 5.6.1 line 28 (.43 vs .44); Box 3.3.2 prints 1.104 then says
1.103; §3.5.1 prose widens the ACPT lower bound a year later than
Table 3.5.1 (the table is followed).

Tests: 283 in tests/lead — every published line to the cent, Expr
builders on polars and DuckDB, bit-for-bit scalar/frame parity over 160
scenarios; 100% of src/lead.
2026-10-27 14:11:10 -04:00

251 lines
7.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Worked examples printed in the LEAD PY2027 methodology (bib E4PEU3HV).
Test fixtures only — never runtime parameters. Each value is copied from
the paper as printed; percentages are written as shares.
"""
from __future__ import annotations
# ── Table 5.6.1: Full Settlement Calculation ──────────────────────────────
TABLE_5_6_1_INPUTS = {
"py_benchmark": 150_000_000.00, # line 1
"spending_designation": "Lower-spending", # 3.00% discount (line 2)
"performance_year": 2027,
"quality_score": 0.95, # line 6
"capitation_payments": 10_000_000.00, # line 10
"participant_provider_claims": 1_003_442.00, # line 11
"preferred_provider_claims": 33_435_084.00, # line 12
"non_aco_provider_claims": 91_355_457.00, # line 13
"stop_loss_elected": True,
"stop_loss_charge": 2_948_334.28, # line 17
"stop_loss_payout": 2_900_000.00, # line 18
"stop_loss_neutrality_factor": 0.930, # line 19
"retention_incentive_applies": False,
}
# (paper line, SettlementLines field). Lines 16, 23 and 24 restate 15, 22
# and 9; "26.1"–"26.4" are the "Retained ... in Corridor n" lines.
TABLE_5_6_1_LINES = (
("1", "py_benchmark"),
("2", "discount_rate"),
("3", "discount_amount"),
("4", "benchmark_after_discount"),
("5", "quality_withhold"),
("6", "quality_score"),
("7", "quality_earn_back"),
("8", "net_quality_withhold"),
("9", "benchmark_after_adjustments"),
("10", "capitation_payments"),
("11", "participant_provider_claims"),
("12", "preferred_provider_claims"),
("13", "non_aco_provider_claims"),
("14", "total_ffs_payments"),
("15", "py_expenditure"),
("16", "py_expenditure"),
("17", "stop_loss_charge"),
("18", "stop_loss_payout"),
("19", "stop_loss_neutrality_factor"),
("20", "adjusted_stop_loss_payout"),
("21", "net_stop_loss_impact"),
("22", "py_expenditure_after_stop_loss"),
("23", "py_expenditure_after_stop_loss"),
("24", "benchmark_after_adjustments"),
("25", "gross_savings_losses"),
("26", "shared_savings_losses"),
("26.1", "retained_corridor_1"),
("26.2", "retained_corridor_2"),
("26.3", "retained_corridor_3"),
("26.4", "retained_corridor_4"),
("27", "sequestration_amount"),
("28", "shared_savings_losses_after_sequestration"),
)
_COMMON = {
"1": 150_000_000.00,
"5": 4_500_000.00, # printed ($4,500,000.00): a reduction
"6": 0.95,
"7": 4_275_000.00,
"8": 225_000.00, # printed ($225,000.00): a reduction
"10": 10_000_000.00,
"11": 1_003_442.00,
"12": 33_435_084.00,
"13": 91_355_457.00,
"14": 125_793_983.00,
"15": 135_793_983.00,
"16": 135_793_983.00,
"17": 2_948_334.28,
"18": 2_900_000.00,
"19": 0.930,
"20": 2_697_000.00,
"21": 251_334.28,
"22": 136_045_317.28,
"23": 136_045_317.28,
"26.2": 0.00,
"26.3": 0.00,
"26.4": 0.00,
}
TABLE_5_6_1 = {
"Global": {
**_COMMON,
"2": 0.03,
"3": 4_500_000.00,
"4": 145_500_000.00,
"9": 145_275_000.00,
"24": 145_275_000.00,
"25": 9_229_682.72,
"26": 9_229_682.72,
"26.1": 9_229_682.72,
"27": 184_593.65,
"28": 9_045_089.07,
},
"Professional": {
**_COMMON,
"2": 0.00,
"3": 0.00, # printed "N/A"
"4": 150_000_000.00,
"9": 149_775_000.00,
"24": 149_775_000.00,
"25": 13_729_682.72,
"26": 8_237_809.63,
"26.1": 8_237_809.63,
"27": 164_756.19,
"28": 8_073_053.44,
},
}
# ── Table 5.5.1: Calculation of Total Monies Owed (Professional, TCC) ─────
TABLE_5_5_1 = {
"1": 6_456_540.00, # Provisional Settlement Shared Savings (Losses)
"2": 8_073_053.43, # Final Settlement Shared Savings (Losses)
"3": 1_616_513.43, # Shared Savings (Losses) Owed
"4": 160_700.00, # Under (Over) Payments from Payment Arrangements
"4.capitation": 160_700.00,
"5": 100_000.00, # High-Performers Pool Incentive
"6": 260_700.00, # Adjustments Owed
"7": 1_877_213.43, # Total Monies Owed
}
# ── Box 5.3.3: Stop-Loss charge and payout illustration ───────────────────
STOP_LOSS_CHARGE = {
"1": 946.97, # Average Reference Year Expenditure PBPM, Trended
"2": 132_000, # ACO-Aligned Beneficiary Months in PY
"3": 1.160, # ACO Average Risk Score in PY
"4": 145_000_046.40, # Total Trended, Risk-Adjusted Reference Expenditure
"5": 0.0203, # 3-Year Average Payout Percentage, printed 2.03%
"RY": (0.0196, 0.0209, 0.0205),
"6": 2_948_334.28, # PY Stop-Loss Charge
}
STOP_LOSS_PAYOUT = {
"attachment_point": 150_000.00,
"predicted": 100_000.00,
"actual": 500_000.00,
"residual": 400_000.00,
"below_attachment_point": 150_000.00,
"band_1_exposure": 150_000.00,
"band_2_exposure": 100_000.00,
"total_payout": 220_000.00,
"band_1_payout": 120_000.00,
"band_2_payout": 100_000.00,
}
# ── Table 3.3.3: Historical Benchmark Calculation (Newly Entering, A&D) ───
TABLE_3_3_3 = {
# base year: (payments, months, risk, line 3, line 5, trend, line 7, weight, line 9)
"BY1": (87_856_003.26, 91_366, 1.122, 961.58, 857.03, 1.104, 946.16, 0.100, 94.62),
"BY2": (93_375_409.42, 94_577, 1.115, 987.30, 885.47, 1.076, 952.76, 0.300, 285.83),
"BY3": (
106_794_359.82,
104_671,
1.087,
1_020.29,
938.63,
1.000,
938.63,
0.600,
563.18,
),
"historical_benchmark": 943.62,
}
# ── Table 3.4.2 / Tables 3.4.3.1–3.4.3.4 ──────────────────────────────────
# category: (regional FFS PBPM, Historical Benchmark PBPM, BY 3 weight,
# uncapped REA, USPCC, PY risk score, REA cap, applied REA,
# Adjusted Historical Benchmark)
REA_TABLES = {
"A&D": (1_050, 1_000, 0.80, 25, 1_000, 1.02, 51, 25, 1_025),
"ESRD": (8_000, 8_500, 0.05, 0, 8_000, 0.99, 396, 0, 8_500),
"High Needs": (3_700, 3_200, 0.15, 250, 3_500, 1.03, 180.25, 180.25, 3_380.25),
}
TABLE_3_4_2_DIFFERENCE = 90.0
# ── Table 3.5.3.2: Hybrid Alignment Benchmark Adjustment ──────────────────
TABLE_3_5_3_2 = {
"1": 1_125.00,
"2": 60_000,
"3": 4_500,
"4": 1.0099,
"5": 1_136.14,
"6": 67_500_000.00,
"7": 5_112_618.75,
"8": 72_612_618.75,
}
# ── Table 3.5.4: Combined Benchmark Calculation ───────────────────────────
# category: (adjusted HB PBPM, trend, PY risk, full months, hybrid months,
# hybrid factor, line 8)
TABLE_3_5_4_CLAIMS = {
"ESRD": (10_175.00, 1.034, 1.007, 981, 120, 1.0099, 11_677_237.29),
"A&D": (796.00, 1.042, 1.045, 56_677, 11_570, 1.0085, 59_238_767.92),
"High Needs": (3_739.00, 1.037, 1.020, 9_806, 2_864, 1.0111, 50_234_182.06),
}
# category: (adjusted HB PBPM, trend, PY risk, full+Q1 months,
# (Q2, Q3, Q4 months), (Q2, Q3, Q4 factors), line 22)
TABLE_3_5_4_VOLUNTARY = {
"ESRD": (
9_543.00,
1.034,
0.990,
421,
(76, 62, 51),
(1.0099, 1.0236, 1.0352),
5_998_140.95,
),
"A&D": (
716.00,
1.042,
0.866,
5_514,
(825, 753, 538),
(1.0085, 1.0247, 1.0431),
4_961_259.64,
),
"High Needs": (
4_109.00,
1.037,
1.061,
2_393,
(734, 549, 240),
(1.0111, 1.0233, 1.0527),
17_855_909.55,
),
}
TABLE_3_5_4_TOTALS = {
"8": 121_150_187.27,
"22": 28_815_310.14,
"24": {
"ESRD": 17_675_378.24,
"A&D": 64_200_027.56,
"High Needs": 68_090_091.61,
"TOTAL": 149_965_497.41,
},
}