From 7690853a3f10143c49d014e790aeaec05d50a8ca Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 20 Oct 2026 18:29:45 -0400 Subject: [PATCH] Decide CSR eligibility and tiers on the exact FPL ratio 42 U.S.C. 18071(c)(2) sets the cost-sharing tiers by household income "not more than 150 percent", "more than 150 percent but not more than 200 percent" and "more than 200 percent but not more than 250 percent" of the poverty line; 45 CFR 155.305(g) says "less than or equal to". The eligibility and category variables compared the truncated aca_magi_fraction with 1.5, 2.0 and 2.5, so every income from 150.00% to 150.99% got the 94% tier (and likewise above 200%), and 250.00%-250.99% stayed CSR-eligible. Test the exact ratio of nonnegative ACA MAGI to the prior-year guideline instead. Tests that supplied aca_magi_fraction now supply aca_magi against a prior-year guideline of $10,000; new cases use the real 2025 guideline at each tier edge. Co-Authored-By: Claude Opus 5.5 --- changelog.d/aca-csr-exact-fpl-ratio.fixed.md | 1 + .../gov/aca/csr/marketplace_csr_category.yaml | 143 +++++++++++++++++- .../gov/aca/csr/marketplace_csr_eligible.yaml | 8 +- ...marketplace_effective_actuarial_value.yaml | 4 +- .../gov/aca/csr/marketplace_csr_category.py | 14 +- .../gov/aca/csr/marketplace_csr_eligible.py | 6 +- 6 files changed, 164 insertions(+), 12 deletions(-) create mode 100644 changelog.d/aca-csr-exact-fpl-ratio.fixed.md diff --git a/changelog.d/aca-csr-exact-fpl-ratio.fixed.md b/changelog.d/aca-csr-exact-fpl-ratio.fixed.md new file mode 100644 index 00000000000..1ffc7687636 --- /dev/null +++ b/changelog.d/aca-csr-exact-fpl-ratio.fixed.md @@ -0,0 +1 @@ +Decide Marketplace cost-sharing reduction eligibility and tiers on the exact ratio of ACA MAGI to the prior-year poverty guideline instead of the truncated `aca_magi_fraction`, so incomes from 150.003% to 150.994% of the poverty line get the 87% tier rather than 94%, the same slivers above 200% get 73% rather than 87%, and incomes from 250.003% to 250.994% get no CSR (42 U.S.C. 18071(c)(2): "not more than 150 / 200 / 250 percent"; 45 CFR 155.305(g)). diff --git a/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_csr_category.yaml b/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_csr_category.yaml index 44b5184806f..04b8e5a0257 100644 --- a/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_csr_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_csr_category.yaml @@ -1,10 +1,19 @@ +# Tiers follow 42 U.S.C. 18071(c)(2) and 45 CFR 155.305(g)(2): household income +# "not more than" (the regulation: "less than or equal to") 150, 200 and 250 +# percent of the FPL, on the exact ratio of ACA MAGI to the prior-year guideline, +# not the truncated aca_magi_fraction. Supplied-income cases pin the prior-year +# guideline to $10,000; income-derived cases use the 2025 one-person guideline, +# $15,650. + - name: Case 1, silver enrollee at 125 percent FPL receives 94 percent AV CSR. absolute_error_margin: 0.001 period: 2026 input: pays_aca_premium: true is_aca_ptc_eligible: true - aca_magi_fraction: 1.25 + aca_magi: 12_500 + tax_unit_fpg: + 2025: 10_000 selected_marketplace_plan_category: SILVER output: person_receives_aca: true @@ -20,7 +29,9 @@ input: pays_aca_premium: true is_aca_ptc_eligible: true - aca_magi_fraction: 1.75 + aca_magi: 17_500 + tax_unit_fpg: + 2025: 10_000 selected_marketplace_plan_category: SILVER output: marketplace_csr_eligible: true @@ -34,7 +45,9 @@ input: pays_aca_premium: true is_aca_ptc_eligible: true - aca_magi_fraction: 2.25 + aca_magi: 22_500 + tax_unit_fpg: + 2025: 10_000 selected_marketplace_plan_category: SILVER output: marketplace_csr_eligible: true @@ -48,7 +61,9 @@ input: pays_aca_premium: true is_aca_ptc_eligible: true - aca_magi_fraction: 2.75 + aca_magi: 27_500 + tax_unit_fpg: + 2025: 10_000 selected_marketplace_plan_category: SILVER output: marketplace_csr_eligible: false @@ -72,7 +87,9 @@ tax_units: tax_unit: members: [person1] - aca_magi_fraction: 0.75 + aca_magi: 7_500 + tax_unit_fpg: + 2024: 10_000 filing_status: SINGLE selected_marketplace_plan_category: SILVER households: @@ -106,7 +123,9 @@ tax_units: tax_unit: members: [person1] - aca_magi_fraction: 0.75 + aca_magi: 7_500 + tax_unit_fpg: + 2025: 10_000 filing_status: SINGLE selected_marketplace_plan_category: SILVER households: @@ -126,3 +145,115 @@ selected_marketplace_plan_actuarial_value: 0 marketplace_csr_actuarial_value: 0 marketplace_effective_actuarial_value: 0 + +- name: Case 7, silver enrollee at 150% of the 2025 guideline ($23,475) gets AV 94. + absolute_error_margin: 0.001 + period: 2026 + input: + pays_aca_premium: true + is_aca_ptc_eligible: true + aca_magi: 23_475 + state_code: TX + selected_marketplace_plan_category: SILVER + output: + aca_magi_fraction: 1.50 + marketplace_csr_eligible: true + marketplace_csr_category: AV_94 + +- name: Case 8, silver enrollee at 150.003% of the 2025 guideline ($23,475.47) gets AV 87. + absolute_error_margin: 0.001 + period: 2026 + input: + pays_aca_premium: true + is_aca_ptc_eligible: true + aca_magi: 23_475.47 + state_code: TX + selected_marketplace_plan_category: SILVER + output: + aca_magi_fraction: 1.50 + marketplace_csr_eligible: true + marketplace_csr_category: AV_87 + +- name: Case 9, silver enrollee at 150.994% of the 2025 guideline ($23,630.56) gets AV 87. + absolute_error_margin: 0.001 + period: 2026 + input: + pays_aca_premium: true + is_aca_ptc_eligible: true + aca_magi: 23_630.56 + state_code: TX + selected_marketplace_plan_category: SILVER + output: + aca_magi_fraction: 1.50 + marketplace_csr_eligible: true + marketplace_csr_category: AV_87 + +- name: Case 10, silver enrollee at 200% of the 2025 guideline ($31,300) gets AV 87. + absolute_error_margin: 0.001 + period: 2026 + input: + pays_aca_premium: true + is_aca_ptc_eligible: true + aca_magi: 31_300 + state_code: TX + selected_marketplace_plan_category: SILVER + output: + aca_magi_fraction: 2.00 + marketplace_csr_eligible: true + marketplace_csr_category: AV_87 + +- name: Case 11, silver enrollee at 200.003% of the 2025 guideline ($31,300.47) gets AV 73. + absolute_error_margin: 0.001 + period: 2026 + input: + pays_aca_premium: true + is_aca_ptc_eligible: true + aca_magi: 31_300.47 + state_code: TX + selected_marketplace_plan_category: SILVER + output: + aca_magi_fraction: 2.00 + marketplace_csr_eligible: true + marketplace_csr_category: AV_73 + +- name: Case 12, silver enrollee at 250% of the 2025 guideline ($39,125) gets AV 73. + absolute_error_margin: 0.001 + period: 2026 + input: + pays_aca_premium: true + is_aca_ptc_eligible: true + aca_magi: 39_125 + state_code: TX + selected_marketplace_plan_category: SILVER + output: + aca_magi_fraction: 2.50 + marketplace_csr_eligible: true + marketplace_csr_category: AV_73 + +- name: Case 13, silver enrollee at 250.003% of the 2025 guideline ($39,125.47) gets no CSR. + absolute_error_margin: 0.001 + period: 2026 + input: + pays_aca_premium: true + is_aca_ptc_eligible: true + aca_magi: 39_125.47 + state_code: TX + selected_marketplace_plan_category: SILVER + output: + aca_magi_fraction: 2.50 + marketplace_csr_eligible: false + marketplace_csr_category: NONE + +- name: Case 14, silver enrollee at 250.994% of the 2025 guideline ($39,280.56) gets no CSR. + absolute_error_margin: 0.001 + period: 2026 + input: + pays_aca_premium: true + is_aca_ptc_eligible: true + aca_magi: 39_280.56 + state_code: TX + selected_marketplace_plan_category: SILVER + output: + aca_magi_fraction: 2.50 + marketplace_csr_eligible: false + marketplace_csr_category: NONE diff --git a/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_csr_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_csr_eligible.yaml index b3780f6fe83..94f370db756 100644 --- a/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_csr_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_csr_eligible.yaml @@ -4,7 +4,9 @@ input: pays_aca_premium: true is_aca_ptc_eligible: true - aca_magi_fraction: 1.25 + aca_magi: 12_500 + tax_unit_fpg: + 2025: 10_000 selected_marketplace_plan_category: BRONZE output: marketplace_csr_eligible: false @@ -19,7 +21,9 @@ input: pays_aca_premium: true is_aca_ptc_eligible: false - aca_magi_fraction: 1.25 + aca_magi: 12_500 + tax_unit_fpg: + 2025: 10_000 selected_marketplace_plan_category: SILVER output: person_receives_aca: false diff --git a/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_effective_actuarial_value.yaml b/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_effective_actuarial_value.yaml index 43254ed83c5..16baaae603f 100644 --- a/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_effective_actuarial_value.yaml +++ b/policyengine_us/tests/policy/baseline/gov/aca/csr/marketplace_effective_actuarial_value.yaml @@ -4,7 +4,9 @@ input: pays_aca_premium: true is_aca_ptc_eligible: true - aca_magi_fraction: 1.25 + aca_magi: 12_500 + tax_unit_fpg: + 2025: 10_000 selected_marketplace_plan_category: SILVER selected_marketplace_plan_premium_proxy: 5_000 used_aca_ptc: 3_000 diff --git a/policyengine_us/variables/gov/aca/csr/marketplace_csr_category.py b/policyengine_us/variables/gov/aca/csr/marketplace_csr_category.py index f747bf51f51..9ac71abb8a1 100644 --- a/policyengine_us/variables/gov/aca/csr/marketplace_csr_category.py +++ b/policyengine_us/variables/gov/aca/csr/marketplace_csr_category.py @@ -15,11 +15,21 @@ class marketplace_csr_category(Variable): entity = TaxUnit label = "Marketplace cost-sharing reduction category" definition_period = YEAR - reference = "https://www.law.cornell.edu/cfr/text/45/155.305#g_2" + reference = ( + "https://www.law.cornell.edu/uscode/text/42/18071#c_2", + "https://www.law.cornell.edu/cfr/text/45/155.305#g_2", + ) def formula(tax_unit, period, parameters): eligible = tax_unit("marketplace_csr_eligible", period) - magi_fraction = tax_unit("aca_magi_fraction", period) + # 42 U.S.C. 18071(c)(2) and 45 CFR 155.305(g)(2) set each tier by + # household income "not more than" (the regulation: "less than or equal + # to") 150, 200 and 250 percent of the poverty line. Test the exact + # ratio, not the truncated aca_magi_fraction: truncation maps + # 150.00%-150.99% to 1.50, which would put incomes above 150% in the + # 94% tier. + magi = max_(tax_unit("aca_magi", period), 0) + magi_fraction = magi / tax_unit("tax_unit_fpg", period.last_year) p = parameters(period).gov.aca.csr.income_threshold return select( [ diff --git a/policyengine_us/variables/gov/aca/csr/marketplace_csr_eligible.py b/policyengine_us/variables/gov/aca/csr/marketplace_csr_eligible.py index 837491802ee..6d8817e8736 100644 --- a/policyengine_us/variables/gov/aca/csr/marketplace_csr_eligible.py +++ b/policyengine_us/variables/gov/aca/csr/marketplace_csr_eligible.py @@ -13,7 +13,11 @@ def formula(tax_unit, period, parameters): receives_aca = tax_unit.sum(person("person_receives_aca", period)) > 0 category = tax_unit("selected_marketplace_plan_category", period) silver_selected = category == category.possible_values.SILVER - magi_fraction = tax_unit("aca_magi_fraction", period) + # 45 CFR 155.305(g)(1)(i)(C): household income that "does not exceed + # 250 percent of the FPL". Test the exact ratio, not the truncated + # aca_magi_fraction, which maps 250.00%-250.99% to 2.50. + magi = max_(tax_unit("aca_magi", period), 0) + magi_fraction = magi / tax_unit("tax_unit_fpg", period.last_year) income_eligible = ( magi_fraction <= parameters(period).gov.aca.csr.income_threshold.maximum )