Files
stack/tests/lead/test_monies_owed.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

72 lines
3.0 KiB
Python
Raw 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.
"""lead.monies_owed reproduces Table 5.5.1 and keeps who-owes-whom signs."""
from __future__ import annotations
from lead.monies_owed import (
apo_adjustment,
payment_arrangement_adjustments,
total_monies_owed,
)
from lead.settlement import SettlementInputs, settle
from tests.lead.paper import TABLE_5_5_1, TABLE_5_6_1_INPUTS
def test_table_5_5_1_every_line():
# The example ACO elected TCC: no Enhanced PCC or APO (footnote 1).
arrangements = payment_arrangement_adjustments(
capitation_under_over_payment=TABLE_5_5_1["4.capitation"],
enhanced_pcc_paid=0.0,
apo_adjustment=0.0,
)
assert arrangements.capitation_under_over_payment == TABLE_5_5_1["4.capitation"]
assert arrangements.payment_arrangement_adjustments == TABLE_5_5_1["4"]
owed = total_monies_owed(
provisional_shared_savings_losses=TABLE_5_5_1["1"],
final_shared_savings_losses=TABLE_5_5_1["2"],
payment_arrangement_adjustments=arrangements.payment_arrangement_adjustments,
high_performers_pool_incentive=TABLE_5_5_1["5"],
)
assert owed.shared_savings_losses_owed == TABLE_5_5_1["3"]
assert owed.high_performers_pool_incentive == TABLE_5_5_1["5"]
assert owed.adjustments_owed == TABLE_5_5_1["6"]
assert owed.total_monies_owed == TABLE_5_5_1["7"]
def test_table_5_5_1_line_2_is_a_cent_below_table_5_6_1_line_28():
# The paper's own inconsistency: Table 5.5.1 carries the Professional
# final Shared Savings as $8,073,053.43, Table 5.6.1 line 28 as .44
# (60% × 13,729,682.72 = 8,237,809.632; less 2% = 8,073,053.439).
final = settle(SettlementInputs(**TABLE_5_6_1_INPUTS, risk_option="Professional"))
assert final.shared_savings_losses_after_sequestration == 8_073_053.44
owed = total_monies_owed(
provisional_shared_savings_losses=TABLE_5_5_1["1"],
final_shared_savings_losses=final.shared_savings_losses_after_sequestration,
payment_arrangement_adjustments=TABLE_5_5_1["4"],
high_performers_pool_incentive=TABLE_5_5_1["5"],
)
assert owed.total_monies_owed == 1_877_213.44 # Table 5.5.1 line 7: .43
def test_signs_follow_who_owes_whom():
# Overpaid capitation and the Enhanced PCC recoupment are owed to CMS.
lines = payment_arrangement_adjustments(
capitation_under_over_payment=-5_000.0,
enhanced_pcc_paid=120_000.0,
apo_adjustment=0.0,
)
assert lines.enhanced_pcc_repayment == -120_000.0
assert lines.payment_arrangement_adjustments == -125_000.0
owed = total_monies_owed(
provisional_shared_savings_losses=500_000.0,
final_shared_savings_losses=-200_000.0,
payment_arrangement_adjustments=lines.payment_arrangement_adjustments,
high_performers_pool_incentive=0.0,
)
assert owed.total_monies_owed == -825_000.0
def test_apo_reconciliation():
# Reductions above the APO payment are credited; below it, recouped.
assert apo_adjustment(110_000.0, 100_000.0) == 10_000.0
assert apo_adjustment(90_000.0, 100_000.0) == -10_000.0