PolicyEngine / PolicyEngine/policyengine-us

Rules-based Marketplace net premium and Medicare Part B for reform-responsive MOOP

Open
#8,095 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
163
Forks
213
Avg merge
3d 3h
Merged PRs (30d)
96

Description

Part 3/4/5 of the architecture described in #8089. Filed as a dedicated issue because ACA has the largest MOOP magnitude among the rules-computable premium components.

## Same shape as CHIP

PolicyEngine-US already computes `premium_tax_credit` (the subsidy). What's missing is a **net Marketplace premium**:

```
marketplace_net_premium = silver_benchmark
× applicable_figure_of_income
× max(0, tax_unit_income − applicable_contribution_basis)
− premium_tax_credit
```

(Or more simply, applicant-contribution-based net premium for the benchmark silver plan.)

The CPS-imputed `health_insurance_premiums_without_medicare_part_b` in PolicyEngine-US already includes whatever a Marketplace enrollee reported paying post-PTC. So on a baseline run, MOOP is roughly right. But a PTC reform (e.g., eliminate the enhanced PTC, shift applicable-figure curves) changes computed PTC while imputed MOOP stays put, and SPM resources don't move.

Same swap the CHIP side needs:

```
health_insurance_premiums = imputed_residual
+ computed_marketplace_net_premium
+ computed_medicare_part_b_premium
+ computed_chip_premium
```

with `imputed_residual = imputed_total − baseline_computed_sum` (baseline computed at the CPS reference year's rules, **2024**, mirroring the CHIP approach).

## What's needed, roughly

1. **Rules-based `marketplace_net_premium` variable** in policyengine-us.
- Silver benchmark × applicable-figure formula.
- Gated on Marketplace enrollment (new flag or use an existing "does this tax unit buy on Marketplace" indicator; CPS has `Marketplace` coverage flag).
- Tax-unit or SPM-unit entity.
2. **Calibration** for Marketplace premium revenue per enrollee by state, sourced from HHS Marketplace effectuated enrollment + issuer premium data (or simpler, use average benchmark × applicable-figure at tax-unit-MAGI).
3. **MOOP swap** in cliff-watch (and eventually in the baseline us-data imputation) to avoid double-count.

## Why this matters for cliff-watch specifically

ACA subsidy cliffs are famously large — the subsidy-cliff removal through the ARPA/IRA enhanced PTC is a *policy reform itself*, so users simulating a return to pre-ARPA rules want the net-income impact to show up. With CPS-imputed MOOP alone, that reform shows up only as a `premium_tax_credit` drop on the benefits side, not as the corresponding premium spike on the costs side. Users see half the cliff.

## Medicare Part B as well

The same follow-up should set up computed Medicare Part B:

```
medicare_part_b = base_premium + IRMAA_surcharge(MAGI, filing_status)
```

Gated on Medicare enrollment (age ≥ 65 or disability-eligible). Current PolicyEngine-US uses `medicare_part_b_premiums` as a pure CPS-imputed input. Rules-based would respond to income cliffs (IRMAA tier crossings at MAGI thresholds) and to reforms to IRMAA breakpoints.

## Suggested sequencing

1. Rules-based `medicare_part_b_premium` variable (cleanest — single statutory formula).
2. Rules-based `marketplace_net_premium` variable (requires Marketplace enrollment flag; more data work).
3. `household_health_costs` list in policyengine-us (parallel to the existing `household_health_benefits`; extends #8088).
4. us-data baseline-year computed subtraction from imputed MOOP.
5. cliff-watch consumes new variables.

## Related

- #8086 — CHIP premium framework
- #8088 — household_net_income subtract
- #8089 — overarching MOOP architecture
- #8090 — CHIP premium into SPM expenses
- #8091 — 2024 CHIP rule history
- #8094 — gross CHIP reconstruction

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.