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 )