Follow-up from #8086 and #8088.
Problem
Medical out-of-pocket expenses (MOOP) are used to compute SPM resources:
spm_unit_net_income = market_income + benefits − taxes − spm_expenses
spm_expenses = child_support + medical_out_of_pocket_expenses + capped_childcare
medical_out_of_pocket_expenses = health_insurance_premiums + other_medical_expenses
health_insurance_premiums (and its Medicare-Part-B split) are pure CPS-imputed inputs — no formula, just survey data uprated via calibration.gov.hhs.cms.moop_per_capita:
policyengine_us/variables/household/expense/health/health_insurance_premiums_without_medicare_part_b.py
policyengine_us/variables/household/expense/health/medicare_part_b_premiums.py
This means:
- Baseline SPM is fine: imputed MOOP already includes whatever CHIP / Medicare / Marketplace premiums CPS respondents reported.
- Reforms break: if a reform eliminates CHIP premiums, simulated
chip_premium drops to zero, but MOOP (survey-imputed) doesn't change, so SPM resources don't respond. Same for Medicare Part B IRMAA reforms, Marketplace benchmark changes, etc.
Proposed architecture
Whatever we compute from policy rules should replace (not add to) the corresponding slice of imputed MOOP:
medical_out_of_pocket_expenses = imputed_moop_residual
+ computed_chip_premium
+ computed_medicare_part_b_premium
+ computed_marketplace_net_premium
+ other_computed_premiums...
where
imputed_moop_residual = imputed_moop_total - baseline_computed_premium_sum
baseline_computed_premium_sum is pre-computed per CPS record during data construction using the rules that were in effect during the CPS reference year (currently 2024). In baseline simulations the two cancel; in reforms the computed piece moves and SPM adjusts correctly.
What's computable today
| Program |
Can we compute it from rules? |
Status |
| CHIP premiums |
Yes — #8086 |
chip_premium (17 states) |
| Medicare Part B |
Yes — statutory base + IRMAA tiers by MAGI |
Not computed |
| Marketplace net premium |
Yes — silver benchmark × applicable-fig percent of income − PTC |
premium_tax_credit computed; net premium not assembled |
| Medicaid cost-sharing |
Partial — varies widely by state |
Out of scope |
| Copays / deductibles |
No — not rule-driven |
Stay in imputed residual |
Staging
- us-model (this issue / follow-up PR) — add
chip_premium to the MOOP chain so reforms to CHIP premiums propagate to SPM. Accepts a small baseline double-count until step 2 lands.
- us-data — during data construction, compute each CPS record's CHIP premium under 2024 rules (the reference year) and subtract it from the imputed
health_insurance_premiums_without_medicare_part_b component. After this, baseline reconciles exactly.
- us-model (later) — rules-based Medicare Part B (standard premium + IRMAA by MAGI tier), plug into same MOOP chain.
- us-data (later) — strip Medicare Part B from imputed MOOP using 2024 rules.
- us-model / us-data (later) — rules-based Marketplace net premium using existing
premium_tax_credit plus benchmark × affordability percent.
Notes
- The "2024 rules" requirement for step 2 comes from the CPS reference year. As the dataset updates (CPS ASEC 2026 → reference year 2025 etc.), the anchor year updates too.
- Entity-mismatch caveat:
chip_premium is TaxUnit-level, medical_out_of_pocket_expenses is Person-level. Aggregation goes through add() at the SPM unit level (existing precedent: spm_unit_benefits adds TaxUnit-level premium_tax_credit). Architecturally clean at the SPM-unit boundary.
Follow-up from #8086 and #8088.
Problem
Medical out-of-pocket expenses (MOOP) are used to compute SPM resources:
health_insurance_premiums(and its Medicare-Part-B split) are pure CPS-imputed inputs — no formula, just survey data uprated viacalibration.gov.hhs.cms.moop_per_capita:policyengine_us/variables/household/expense/health/health_insurance_premiums_without_medicare_part_b.pypolicyengine_us/variables/household/expense/health/medicare_part_b_premiums.pyThis means:
chip_premiumdrops to zero, but MOOP (survey-imputed) doesn't change, so SPM resources don't respond. Same for Medicare Part B IRMAA reforms, Marketplace benchmark changes, etc.Proposed architecture
Whatever we compute from policy rules should replace (not add to) the corresponding slice of imputed MOOP:
where
baseline_computed_premium_sumis pre-computed per CPS record during data construction using the rules that were in effect during the CPS reference year (currently 2024). In baseline simulations the two cancel; in reforms the computed piece moves and SPM adjusts correctly.What's computable today
chip_premium(17 states)premium_tax_creditcomputed; net premium not assembledStaging
chip_premiumto the MOOP chain so reforms to CHIP premiums propagate to SPM. Accepts a small baseline double-count until step 2 lands.health_insurance_premiums_without_medicare_part_bcomponent. After this, baseline reconciles exactly.premium_tax_creditplus benchmark × affordability percent.Notes
chip_premiumis TaxUnit-level,medical_out_of_pocket_expensesis Person-level. Aggregation goes throughadd()at the SPM unit level (existing precedent:spm_unit_benefitsadds TaxUnit-levelpremium_tax_credit). Architecturally clean at the SPM-unit boundary.