feat: beneficiary cost sharing notebook — coinsurance trends and CY2026 impact
Some checks failed
CI / skinny-install (aco) (push) Successful in 51s
CI / lint-test (push) Successful in 1m18s
CI / skinny-install (api) (push) Successful in 26s
CI / skinny-install (cli) (push) Successful in 32s
CI / skinny-install (cms) (push) Successful in 29s
CI / skinny-install (conf) (push) Successful in 31s
CI / skinny-install (opps) (push) Successful in 32s
CI / skinny-install (bcda) (push) Successful in 33s
CI / skinny-install (bib) (push) Successful in 34s
CI / skinny-install (bls) (push) Successful in 24s
CI / skinny-install (ccw) (push) Successful in 31s
CI / skinny-install (rex) (push) Successful in 40s
CI / skinny-install (aco) (pull_request) Successful in 48s
CI / lint-test (pull_request) Successful in 1m24s
CI / skinny-install (bls) (pull_request) Successful in 27s
CI / skinny-install (bib) (pull_request) Successful in 31s
CI / skinny-install (ccw) (pull_request) Successful in 26s
CI / skinny-install (cli) (pull_request) Successful in 32s
Infra CI / zotero (push) Successful in 6s
Infra CI / docs (push) Failing after 5s
Infra CI / api (push) Successful in 6s
Infra CI / notebooks (pull_request) Successful in 6s
CI / skinny-install (perf) (push) Successful in 33s
CI / skinny-install (pfs) (push) Successful in 32s
CI / skinny-install (bcda) (pull_request) Successful in 29s
CI / skinny-install (api) (pull_request) Successful in 32s
CI / skinny-install (cms) (pull_request) Successful in 28s
CI / skinny-install (conf) (pull_request) Successful in 27s
CI / skinny-install (opps) (pull_request) Successful in 28s
CI / skinny-install (perf) (pull_request) Successful in 30s
CI / skinny-install (pfs) (pull_request) Successful in 33s
CI / skinny-install (rex) (pull_request) Successful in 29s
Infra CI / notebooks (push) Successful in 8s
Infra CI / mc (push) Successful in 6s
Infra CI / zotero (pull_request) Successful in 7s
Infra CI / docs (pull_request) Failing after 7s
Infra CI / api (pull_request) Successful in 7s
Infra CI / mc (pull_request) Successful in 8s
Some checks failed
CI / skinny-install (aco) (push) Successful in 51s
CI / lint-test (push) Successful in 1m18s
CI / skinny-install (api) (push) Successful in 26s
CI / skinny-install (cli) (push) Successful in 32s
CI / skinny-install (cms) (push) Successful in 29s
CI / skinny-install (conf) (push) Successful in 31s
CI / skinny-install (opps) (push) Successful in 32s
CI / skinny-install (bcda) (push) Successful in 33s
CI / skinny-install (bib) (push) Successful in 34s
CI / skinny-install (bls) (push) Successful in 24s
CI / skinny-install (ccw) (push) Successful in 31s
CI / skinny-install (rex) (push) Successful in 40s
CI / skinny-install (aco) (pull_request) Successful in 48s
CI / lint-test (pull_request) Successful in 1m24s
CI / skinny-install (bls) (pull_request) Successful in 27s
CI / skinny-install (bib) (pull_request) Successful in 31s
CI / skinny-install (ccw) (pull_request) Successful in 26s
CI / skinny-install (cli) (pull_request) Successful in 32s
Infra CI / zotero (push) Successful in 6s
Infra CI / docs (push) Failing after 5s
Infra CI / api (push) Successful in 6s
Infra CI / notebooks (pull_request) Successful in 6s
CI / skinny-install (perf) (push) Successful in 33s
CI / skinny-install (pfs) (push) Successful in 32s
CI / skinny-install (bcda) (pull_request) Successful in 29s
CI / skinny-install (api) (pull_request) Successful in 32s
CI / skinny-install (cms) (pull_request) Successful in 28s
CI / skinny-install (conf) (pull_request) Successful in 27s
CI / skinny-install (opps) (pull_request) Successful in 28s
CI / skinny-install (perf) (pull_request) Successful in 30s
CI / skinny-install (pfs) (pull_request) Successful in 33s
CI / skinny-install (rex) (pull_request) Successful in 29s
Infra CI / notebooks (push) Successful in 8s
Infra CI / mc (push) Successful in 6s
Infra CI / zotero (pull_request) Successful in 7s
Infra CI / docs (pull_request) Failing after 7s
Infra CI / api (pull_request) Successful in 7s
Infra CI / mc (pull_request) Successful in 8s
Tracks skin substitute beneficiary out-of-pocket costs over time: 1. Application fee coinsurance by region (20% of PFS carrier fee) 2. Product coinsurance trajectory (20% of ASP+6% per cm²) 3. Total episode cost sharing for 25cm² wound (product + application) 4. OPPS copayment collapse: $105-366 (2021-2025) → $25.43 flat (2026) 5. Winners/losers: high-ASP products save, low-ASP products pay more 6. Episode scenarios: Apligraf, EpiFix, GrafixCore before/after CY2026 7. Part B deductible context ($147 in 2015 → $257 in 2025-2026) 8. Key takeaways refs #246
This commit is contained in:
512
notebooks/skin_sub_cost_sharing.py
Normal file
512
notebooks/skin_sub_cost_sharing.py
Normal file
@@ -0,0 +1,512 @@
|
||||
import marimo
|
||||
|
||||
__generated_with = "0.21.1"
|
||||
app = marimo.App(width="medium")
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _():
|
||||
import marimo as mo
|
||||
|
||||
return (mo,)
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
# Beneficiary Cost Sharing for Skin Substitutes
|
||||
|
||||
Medicare Part B beneficiaries pay **20% coinsurance** on both the
|
||||
application procedure (PFS) and the product (ASP + 6%). This
|
||||
notebook tracks how cost sharing has changed over time and how
|
||||
the CY2026 reclassification affects out-of-pocket exposure.
|
||||
|
||||
**Cost-sharing components:**
|
||||
- **Application fee**: 20% of PFS carrier locality fee (15271–15278)
|
||||
- **Product cost**: 20% of ASP + 6% payment limit × units
|
||||
- **OPPS copayment**: minimum unadjusted copayment per APC (hospital outpatient)
|
||||
- **Limiting charge**: non-participating providers may charge up to 115% of fee schedule
|
||||
|
||||
**CY2026 change:** All skin subs move to a flat $127.28/cm². OPPS copay
|
||||
drops from ~$165–$366 per code to $25.43 flat. Product coinsurance
|
||||
collapses to $25.43/unit regardless of actual ASP.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _():
|
||||
import altair as alt
|
||||
import polars as pl
|
||||
from conf import connect
|
||||
from pfs.rules import RULES
|
||||
|
||||
con = connect.duckdb()
|
||||
|
||||
def q(sql):
|
||||
return con.execute(sql).pl()
|
||||
|
||||
SKIN_CODES = "('15271','15272','15273','15274','15275','15276','15277','15278')"
|
||||
|
||||
# Part B deductible history (published by CMS annually)
|
||||
DEDUCTIBLES = {
|
||||
2015: 147.00, 2016: 166.00, 2017: 183.00, 2018: 183.00,
|
||||
2019: 185.00, 2020: 198.00, 2021: 203.00, 2022: 233.00,
|
||||
2023: 226.00, 2024: 240.00, 2025: 257.00, 2026: 257.00,
|
||||
}
|
||||
|
||||
return DEDUCTIBLES, RULES, SKIN_CODES, alt, con, pl, q
|
||||
|
||||
|
||||
# ── 1. Application fee coinsurance over time ─────────────────────────
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
## 1. Application Fee Coinsurance by Region
|
||||
|
||||
The beneficiary pays 20% of the PFS-approved amount for the
|
||||
application procedure. This varies by locality and year.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(alt, q):
|
||||
regions = [
|
||||
"MANHATTAN", "REST OF FLORIDA", "REST OF TEXAS",
|
||||
"REST OF CALIFORNIA", "SOUTH CAROLINA",
|
||||
]
|
||||
region_list = ", ".join(f"'{r}'" for r in regions)
|
||||
|
||||
app_coinsurance = q(f"""
|
||||
SELECT c.year, g.locality_name,
|
||||
c.non_fac_fee,
|
||||
round(c.non_fac_fee * 0.20, 2) as bene_coinsurance,
|
||||
c.non_fac_limiting_charge,
|
||||
round(c.non_fac_limiting_charge * 0.20, 2) as bene_limiting_coinsurance
|
||||
FROM pfs.carrier_locality c
|
||||
JOIN pfs.gpci g ON c.mac = g.mac AND c.locality = g.locality AND c.year = g.year
|
||||
WHERE c.hcpcs = '15271'
|
||||
AND g.locality_name IN ({region_list})
|
||||
ORDER BY c.year, g.locality_name
|
||||
""")
|
||||
|
||||
app_chart = (
|
||||
alt.Chart(app_coinsurance.to_pandas())
|
||||
.mark_line(point=True)
|
||||
.encode(
|
||||
x=alt.X("year:O", title="Year"),
|
||||
y=alt.Y("bene_coinsurance:Q", title="Beneficiary Coinsurance ($)"),
|
||||
color=alt.Color("locality_name:N", title="Region"),
|
||||
tooltip=["year", "locality_name", "non_fac_fee",
|
||||
"bene_coinsurance", "non_fac_limiting_charge"],
|
||||
)
|
||||
.properties(
|
||||
title="15271 Application — Beneficiary 20% Coinsurance by Region",
|
||||
width=700, height=350,
|
||||
)
|
||||
)
|
||||
app_chart
|
||||
return
|
||||
|
||||
|
||||
# ── 2. Product coinsurance trajectory ────────────────────────────────
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
## 2. Product Coinsurance Over Time (Per Unit)
|
||||
|
||||
The beneficiary pays 20% of the ASP + 6% payment limit **per cm²**.
|
||||
For high-ASP products, this adds up fast — a 25cm² application of
|
||||
a $150/cm² product means $750 in coinsurance just for the product.
|
||||
|
||||
The red dashed line shows the CY2026 flat-rate coinsurance:
|
||||
20% × $127.28 = **$25.46/cm²**.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(alt, pl, q):
|
||||
product_coins = q("""
|
||||
SELECT quarter, hcpcs_code, short_description,
|
||||
payment_limit,
|
||||
round(payment_limit * 0.20, 2) as bene_per_unit
|
||||
FROM skin_subs.asp_quarterly
|
||||
WHERE hcpcs_code IN ('Q4101','Q4186','Q4132','Q4116','Q4100')
|
||||
ORDER BY quarter, hcpcs_code
|
||||
""")
|
||||
|
||||
flat_coins = (
|
||||
alt.Chart(pl.DataFrame({"y": [127.28 * 0.20]}).to_pandas())
|
||||
.mark_rule(color="red", strokeDash=[4, 4], strokeWidth=2)
|
||||
.encode(y="y:Q")
|
||||
)
|
||||
|
||||
product_lines = (
|
||||
alt.Chart(product_coins.to_pandas())
|
||||
.mark_line()
|
||||
.encode(
|
||||
x=alt.X("quarter:O", title="Quarter",
|
||||
axis=alt.Axis(labelAngle=-45, labelFontSize=8)),
|
||||
y=alt.Y("bene_per_unit:Q", title="Beneficiary Coinsurance per cm² ($)"),
|
||||
color=alt.Color("short_description:N", title="Product"),
|
||||
tooltip=["quarter", "hcpcs_code", "short_description",
|
||||
"payment_limit", "bene_per_unit"],
|
||||
)
|
||||
)
|
||||
|
||||
product_chart = (
|
||||
(product_lines + flat_coins)
|
||||
.properties(
|
||||
title="Product Coinsurance per Unit (20% of ASP + 6%)",
|
||||
width=700, height=400,
|
||||
)
|
||||
)
|
||||
product_chart
|
||||
return
|
||||
|
||||
|
||||
# ── 3. Total episode cost sharing ────────────────────────────────────
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
## 3. Total Episode Cost Sharing (25cm² Wound)
|
||||
|
||||
For a typical 25cm² wound treated in an office setting, the
|
||||
beneficiary's total out-of-pocket is:
|
||||
|
||||
```
|
||||
total = 20% × application_fee + 20% × (ASP+6% × 25 units)
|
||||
```
|
||||
|
||||
This chart shows how that total has changed over time for
|
||||
selected products, with the post-2026 flat-rate equivalent shown.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(alt, pl, q):
|
||||
# Use Q1 of each year for annual comparison
|
||||
episode_sharing = q("""
|
||||
WITH asp_annual AS (
|
||||
SELECT CAST(substr(quarter, 1, 4) AS INTEGER) as year,
|
||||
hcpcs_code, short_description,
|
||||
payment_limit
|
||||
FROM skin_subs.asp_quarterly
|
||||
WHERE substr(quarter, 6, 2) = 'Q1'
|
||||
AND hcpcs_code IN ('Q4101','Q4186','Q4132','Q4116')
|
||||
),
|
||||
app_fee AS (
|
||||
SELECT c.year, avg(c.non_fac_fee) as avg_app_fee
|
||||
FROM pfs.carrier_locality c
|
||||
WHERE c.hcpcs = '15271'
|
||||
GROUP BY c.year
|
||||
)
|
||||
SELECT a.year, a.hcpcs_code, a.short_description,
|
||||
round(a.payment_limit, 2) as asp_per_unit,
|
||||
round(f.avg_app_fee, 2) as avg_app_fee,
|
||||
round(f.avg_app_fee * 0.20, 2) as app_coinsurance,
|
||||
round(a.payment_limit * 25 * 0.20, 2) as product_coinsurance_25cm,
|
||||
round(f.avg_app_fee * 0.20 + a.payment_limit * 25 * 0.20, 2) as total_bene_cost
|
||||
FROM asp_annual a
|
||||
LEFT JOIN app_fee f ON a.year = f.year
|
||||
ORDER BY a.year, a.hcpcs_code
|
||||
""")
|
||||
|
||||
flat_episode = 127.28 * 25 * 0.20 # $636.40 product + ~$28 application
|
||||
|
||||
flat_line = (
|
||||
alt.Chart(pl.DataFrame({"y": [flat_episode]}).to_pandas())
|
||||
.mark_rule(color="red", strokeDash=[4, 4], strokeWidth=2)
|
||||
.encode(y="y:Q")
|
||||
)
|
||||
|
||||
episode_lines = (
|
||||
alt.Chart(episode_sharing.to_pandas())
|
||||
.mark_line(point=True)
|
||||
.encode(
|
||||
x=alt.X("year:O", title="Year"),
|
||||
y=alt.Y("total_bene_cost:Q",
|
||||
title="Beneficiary Total Cost Sharing ($)"),
|
||||
color=alt.Color("short_description:N", title="Product"),
|
||||
tooltip=["year", "hcpcs_code", "short_description",
|
||||
"asp_per_unit", "app_coinsurance",
|
||||
"product_coinsurance_25cm", "total_bene_cost"],
|
||||
)
|
||||
)
|
||||
|
||||
episode_chart = (
|
||||
(episode_lines + flat_line)
|
||||
.properties(
|
||||
title="Total Beneficiary Cost Sharing — 25cm² Wound Episode",
|
||||
width=700, height=400,
|
||||
)
|
||||
)
|
||||
episode_chart
|
||||
return
|
||||
|
||||
|
||||
# ── 4. OPPS copayment collapse ───────────────────────────────────────
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
## 4. OPPS Copayment Collapse in CY2026
|
||||
|
||||
In the hospital outpatient setting (HOPD), beneficiaries pay a
|
||||
minimum unadjusted copayment per APC. For skin substitutes:
|
||||
|
||||
- **2021–2025**: Copays ranged from $105–$366 depending on the
|
||||
product's APC assignment (high-cost vs. low-cost categories)
|
||||
- **CY2026**: All products reclassified to a single flat rate
|
||||
with copay of **$25.43** — a >85% reduction
|
||||
|
||||
This is the most dramatic beneficiary cost-sharing change in
|
||||
the CY2026 reclassification.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(alt, q):
|
||||
opps_copay = q("""
|
||||
SELECT year,
|
||||
count(*) as products,
|
||||
round(avg(minimum_unadjusted_copayment), 2) as avg_copay,
|
||||
round(min(minimum_unadjusted_copayment), 2) as min_copay,
|
||||
round(max(minimum_unadjusted_copayment), 2) as max_copay,
|
||||
round(max(minimum_unadjusted_copayment) -
|
||||
min(minimum_unadjusted_copayment), 2) as copay_spread
|
||||
FROM opps.skin_sub_addendum_b
|
||||
WHERE minimum_unadjusted_copayment > 0
|
||||
GROUP BY year ORDER BY year
|
||||
""")
|
||||
|
||||
copay_chart = (
|
||||
alt.Chart(opps_copay.to_pandas())
|
||||
.mark_bar()
|
||||
.encode(
|
||||
x=alt.X("year:O", title="Year"),
|
||||
y=alt.Y("avg_copay:Q", title="Average OPPS Copayment ($)"),
|
||||
color=alt.condition(
|
||||
alt.datum.year == 2026,
|
||||
alt.value("#2ca02c"),
|
||||
alt.value("#1f77b4"),
|
||||
),
|
||||
tooltip=["year", "products", "avg_copay", "min_copay",
|
||||
"max_copay", "copay_spread"],
|
||||
)
|
||||
.properties(
|
||||
title="OPPS Minimum Unadjusted Copayment — Skin Substitutes",
|
||||
width=700, height=300,
|
||||
)
|
||||
)
|
||||
|
||||
mo.vstack([copay_chart, opps_copay])
|
||||
return
|
||||
|
||||
|
||||
# ── 5. Winners and losers: beneficiary perspective ────────────────────
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
## 5. Beneficiary Impact: Who Pays More, Who Pays Less?
|
||||
|
||||
Under the flat rate, beneficiaries using **high-ASP products**
|
||||
(EpiFix, GrafixCore) see their per-unit coinsurance drop
|
||||
dramatically. Those using **low-ASP products** (Apligraf at
|
||||
~$30/unit) see coinsurance rise from ~$6 to ~$25.
|
||||
|
||||
This is a wealth transfer: beneficiaries who previously used
|
||||
expensive products benefit; those with cheaper products pay more.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(alt, q):
|
||||
bene_impact = q("""
|
||||
SELECT hcpcs_code, short_description,
|
||||
payment_limit as current_asp_payment,
|
||||
round(payment_limit * 0.20, 2) as current_bene_per_unit,
|
||||
127.28 as flat_rate,
|
||||
round(127.28 * 0.20, 2) as flat_bene_per_unit,
|
||||
round(127.28 * 0.20 - payment_limit * 0.20, 2) as bene_delta_per_unit,
|
||||
CASE
|
||||
WHEN payment_limit * 0.20 > 127.28 * 0.20 THEN 'bene saves'
|
||||
WHEN payment_limit * 0.20 < 127.28 * 0.20 THEN 'bene pays more'
|
||||
ELSE 'neutral'
|
||||
END as bene_impact
|
||||
FROM skin_subs.asp_quarterly
|
||||
WHERE quarter = (SELECT max(quarter) FROM skin_subs.asp_quarterly)
|
||||
ORDER BY bene_delta_per_unit
|
||||
""")
|
||||
|
||||
bene_chart = (
|
||||
alt.Chart(bene_impact.to_pandas())
|
||||
.mark_bar()
|
||||
.encode(
|
||||
x=alt.X("bene_delta_per_unit:Q",
|
||||
title="Change in Beneficiary Coinsurance per Unit ($)"),
|
||||
y=alt.Y("short_description:N", title="", sort="x",
|
||||
axis=alt.Axis(labelLimit=300)),
|
||||
color=alt.Color("bene_impact:N",
|
||||
scale=alt.Scale(
|
||||
domain=["bene saves", "bene pays more", "neutral"],
|
||||
range=["#2ca02c", "#d62728", "#7f7f7f"],
|
||||
),
|
||||
title="Impact"),
|
||||
tooltip=["hcpcs_code", "short_description",
|
||||
"current_bene_per_unit", "flat_bene_per_unit",
|
||||
"bene_delta_per_unit"],
|
||||
)
|
||||
.properties(
|
||||
title="CY2026 Beneficiary Coinsurance Change per Unit",
|
||||
width=700,
|
||||
)
|
||||
)
|
||||
bene_chart
|
||||
return
|
||||
|
||||
|
||||
# ── 6. Episode scenario comparison ───────────────────────────────────
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
## 6. Episode Scenarios: Before vs. After CY2026
|
||||
|
||||
Three wound scenarios showing the complete beneficiary cost
|
||||
breakdown before and after the flat-rate reclassification.
|
||||
All assume office setting (POS 11), participating provider,
|
||||
national average application fee.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(pl, q):
|
||||
# Get average national app fee for 2025
|
||||
avg_fee = q("""
|
||||
SELECT round(avg(non_fac_fee), 2) as avg_fee
|
||||
FROM pfs.carrier_locality
|
||||
WHERE year = 2025 AND hcpcs = '15271'
|
||||
""").item()
|
||||
|
||||
scenarios = pl.DataFrame({
|
||||
"scenario": [
|
||||
"Small wound (10cm²) — Q4101 Apligraf",
|
||||
"Medium wound (25cm²) — Q4186 EpiFix",
|
||||
"Large wound (50cm²) — Q4132 GrafixCore",
|
||||
],
|
||||
"units": [10, 25, 50],
|
||||
"asp_per_unit": [30.23, 151.17, 106.70],
|
||||
"product_name": ["Apligraf", "EpiFix", "GrafixCore"],
|
||||
}).with_columns(
|
||||
# Pre-2026: ASP + 6%
|
||||
(pl.col("asp_per_unit") * pl.col("units") * 0.20).round(2).alias("pre_product_coins"),
|
||||
pl.lit(avg_fee * 0.20).round(2).alias("pre_app_coins"),
|
||||
# Post-2026: flat $127.28
|
||||
(pl.lit(127.28) * pl.col("units") * 0.20).round(2).alias("post_product_coins"),
|
||||
pl.lit(avg_fee * 0.20).round(2).alias("post_app_coins"),
|
||||
).with_columns(
|
||||
(pl.col("pre_product_coins") + pl.col("pre_app_coins")).alias("pre_total"),
|
||||
(pl.col("post_product_coins") + pl.col("post_app_coins")).alias("post_total"),
|
||||
).with_columns(
|
||||
(pl.col("post_total") - pl.col("pre_total")).round(2).alias("delta"),
|
||||
)
|
||||
scenarios
|
||||
return
|
||||
|
||||
|
||||
# ── 7. Part B deductible context ─────────────────────────────────────
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
## 7. Part B Deductible Context
|
||||
|
||||
Before coinsurance applies, beneficiaries must meet the annual
|
||||
Part B deductible. A single skin substitute episode can exceed
|
||||
the entire deductible, meaning the full coinsurance amount is
|
||||
additional out-of-pocket cost for most beneficiaries.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(DEDUCTIBLES, alt, pl):
|
||||
deductible_df = pl.DataFrame({
|
||||
"year": list(DEDUCTIBLES.keys()),
|
||||
"deductible": list(DEDUCTIBLES.values()),
|
||||
})
|
||||
|
||||
ded_chart = (
|
||||
alt.Chart(deductible_df.to_pandas())
|
||||
.mark_bar(color="#ff7f0e")
|
||||
.encode(
|
||||
x=alt.X("year:O", title="Year"),
|
||||
y=alt.Y("deductible:Q", title="Annual Part B Deductible ($)"),
|
||||
tooltip=["year", "deductible"],
|
||||
)
|
||||
.properties(
|
||||
title="Medicare Part B Annual Deductible",
|
||||
width=700, height=250,
|
||||
)
|
||||
)
|
||||
ded_chart
|
||||
return
|
||||
|
||||
|
||||
# ── 8. Key takeaways ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(mo):
|
||||
mo.md("""
|
||||
## 8. Key Takeaways
|
||||
|
||||
1. **OPPS copay drops >85% in CY2026.** From $105–$366 per code
|
||||
to $25.43 flat. This is the single largest beneficiary-facing
|
||||
change in the reclassification.
|
||||
|
||||
2. **High-ASP product users save significantly.** For EpiFix
|
||||
(Q4186, ~$151/unit), coinsurance per cm² drops from ~$30 to
|
||||
~$25 — but for a 25cm² wound, the total product coinsurance
|
||||
drops from ~$755 to ~$636 ($119 savings).
|
||||
|
||||
3. **Low-ASP product users pay more.** For Apligraf (Q4101,
|
||||
~$30/unit), per-unit coinsurance rises from ~$6 to ~$25.
|
||||
A 25cm² wound goes from ~$30 to ~$636 in product coinsurance.
|
||||
|
||||
4. **Application fee coinsurance is stable.** The PFS component
|
||||
(~$27–$35 for 15271 depending on locality) is a small fraction
|
||||
of total cost sharing and relatively stable over time.
|
||||
|
||||
5. **Deductible is a floor, not a ceiling.** The $257 Part B
|
||||
deductible (2025–2026) is typically exceeded by a single skin
|
||||
sub episode, so coinsurance applies to the full amount.
|
||||
|
||||
6. **No Medigap/supplement analysis.** Most beneficiaries have
|
||||
supplemental coverage (Medigap, employer, Medicaid dual) that
|
||||
covers the 20% coinsurance. Actual out-of-pocket may be lower
|
||||
depending on coverage type.
|
||||
""")
|
||||
return
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
Reference in New Issue
Block a user