Skip to content

Add the 2027 ACA premium tax credit applicable percentage table - #10443

Open
MaxGhenis wants to merge 5 commits into
mainfrom
aca-ptc-2027-applicable-percentage
Open

MaxGhenis wants to merge 5 commits into
mainfrom
aca-ptc-2027-applicable-percentage

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #10442.

The bug

gov.aca.required_contribution_percentage.initial and .final stopped at 2026 (Rev. Proc. 2025-25), so 2027 reused the 2026 table. At 200% FPL the model used 6.60% where the law for 2027 says 6.78%. Every 2027 percentage is higher than its 2026 counterpart, so the model set the required contribution too low for every household with positive income at or below 400% FPL. For those households it overstated the 2027 federal premium tax credit wherever that credit was above $0 under the 2026 table. Where the benchmark premium is below the required contribution under both tables, the credit is $0 either way. Programs built on the federal credit inherit the error. The California Premium Subsidy, for example, is max(0, slcsp − aca_ptc − ca_pct × income), so while that subsidy is above $0, each dollar of extra federal credit is a dollar less of it (#10305).

The fix

Rev. Proc. 2026-26 §3.01 sets the table for taxable years beginning in 2027. I checked each value against the PDF:

Household income (% FPL) 2026 (Rev. Proc. 2025-25) 2027 (Rev. Proc. 2026-26)
Less than 133% 2.10% 2.15%
At least 133% but less than 150% 3.14% → 4.19% 3.23% → 4.3%
At least 150% but less than 200% 4.19% → 6.60% 4.3% → 6.78%
At least 200% but less than 250% 6.60% → 8.44% 6.78% → 8.66%
At least 250% but less than 300% 8.44% → 9.96% 8.66% → 10.22%
At least 300% but not more than 400% 9.96% 10.22%
  • initial.yaml and final.yaml get 2027-01-01 rows, and all three table files cite Rev. Proc. 2026-26 (file page 3).
  • threshold.yaml needs no new values. The 2027 bands are the same six as 2026: 133, 150, 200, 250, 300 and 400 percent.
  • The Rev. Proc. 2025-25 hrefs gain #page=3, where the 2026 table is, per the reference rules.
  • §3.02 also sets the 2027 Required Contribution Percentage (employer-coverage affordability, §36B(c)(2)(C)) at 10.22%. PolicyEngine-US has no parameter for it: affordability is the input offered_aca_disqualifying_esi. A search of parameters/ and variables/ for 9.96% (the 2026 Required Contribution Percentage), "affordab", 36B(c)(2)(C) and Rev. Proc. 2025-25 found no other 2026-only ACA indexing parameter.

Tests

YAML, with expected values from the Rev. Proc., not from model output.

  • aca_required_contribution_percentage.yaml: 15 cases in 2027. Cases at 100% and 132% are flat 2.15%. Each edge from 133 to 300 percent gives that band's initial percentage, and 400 percent gives 10.22%. Interior points sit at 140, 175, 199, 225, 275 and 350 percent, and 401 percent gives 0.
  • aca_ptc.yaml: 9 cases in 2027 that derive the percentage, at 100, 133, 150, 200, 275, 350 and 390 percent (the last floors at $0). Two cases derive the FPL fraction from income and the 2026 HHS guideline: one person at $31,920 (200%) and a couple at $54,100 (250%). The 200% case is the Covered California OE27 example: $8,256 − 6.78% × $31,920 = $6,091.82.
  • Against main's parameters, 14 of the 15 new percentage cases and 8 of the 9 new credit cases fail. The two that pass on main pass for the right reason: 401% is $0 under both tables, and the 390% credit floors at $0 under both.

Existing 2027 expectations. None move. I listed every YAML case whose period is 2027 or later (305 files) and kept those whose outputs depend on aca_required_contribution_percentage. To find those, I built a static reverse-dependency closure over formulas, adds and subtracts, and the list parameters passed to add(). That left 17 files with 35 cases. Each file passes unchanged on this branch, one file per process: those cases supply aca_ptc as an input or test eligibility and program years. No partner contract test has a 2027 or later case.

California Case 19. #10305 adds amount Case 19 to ca_premium_subsidy.yaml, the OE27 example, and supplies aca_ptc: 6_091.824 because main lacks this table. #10305 is not on main yet, so whichever of the two PRs lands second changes Case 19 to derive aca_ptc. The expected values are a federal credit of $6,091.82 and ca_premium_subsidy of $478.80 (#10442 tracks this).

Invariants

These hold for every income, in every year from 2018 through 2027, against that year's table. policyengine_us/tests/core/test_aca_required_contribution_percentage_properties.py checks them with Hypothesis:

  1. At each band's lower edge, the applicable percentage equals that band's initial percentage. At exactly 400 percent it equals the top band's final percentage.
  2. Within a band the percentage is the straight line from the band's initial to its final percentage, rounded to the nearest hundredth of a percent (26 CFR 1.36B-3(g)(1)). So it stays between the band's initial and final percentages, reaches the final percentage just below the next edge, and at every income is within half a rounding step (0.005 percentage point) of the line. The bound holds whether or not the model rounds (it doesn't yet; see below).
  3. The percentage never decreases as income rises from 0 to 400 percent, including across edges. Before rounding, the line is continuous within each band and the only jump between bands is at 133 percent: 2.15% → 3.23% in 2027. Rounding adds steps of 0.01 percentage point.
  4. The required contribution (income × percentage) never decreases with income. So with a fixed benchmark premium, the credit never rises with income up to 400 percent. This is checked for 2026 and 2027, from income in dollars through the FPL fraction. Every example includes four fixed incomes ($10,000, $25,000, $40,000 and $60,000, one person) in four different bands, so no example compares only equal incomes.

The test also asserts that every year's band edges are among the edges it probes, so a mistyped edge can't pass by being skipped.

Mutation checks (each mutant run against the property test at 83c7d8c, one process at a time, RSS-capped at 2 GB):

  • Caught: a 2027 final percentage below its initial (property 2), 2027 rows out of order (property 3), a mistyped 2026 edge, 1.35 for 1.33 (the edge guard), an interpolation that overshoots by 20% (property 2), and a bow of up to 0.008 percentage point that keeps every endpoint and the order (property 2's line bound; Sol's second review found that the earlier pairwise bound let it through).
  • Passes, as intended: rounding the percentage to the nearest hundredth of a percent, as 26 CFR 1.36B-3(g)(1) requires. Sol's first review found that the first version of the test rejected it.
  • Survived: searching edges with side="left". It is an equivalent mutant: the model stores the FPL fraction in float32, and float32(1.33) is just above 1.33, so 133% still lands in the upper band. At every other edge the two bands meet at the same value.

Cost (Python test, measured twice locally on a shared macOS host, not Linux CI): 4–6 s of test calls, 7–12 s in pytest and 29–36 s wall time with the model import; peak memory footprint 1.7 GB. It runs in the core group of the rest Python tests, like test_aca_ptc_filing_gate_invariants.py.

Impact (2027)

Pending: the full-file 2027 run is queued in the US hub's impact queue behind a host reservation that ends at 22:00Z. This section will carry its numbers.

This is a model-to-law fix, so the size of the aggregate change doesn't need approval.

Not in this PR

  • 26 CFR 1.36B-3(g)(1) rounds the interpolated applicable percentage "to the nearest one-hundredth of one percent". The model doesn't round, in any year: at 140% FPL in 2027 it uses 3.6706% where the regulation gives 3.67%. This PR's interior YAML points are chosen so the expected value is the regulation's rounded figure and the unrounded value is within 0.001 percentage points of it. I'll propose the rounding as its own change.

axiom: us/guidance/irs/rev-proc-2026-26 TheAxiomFoundation/rulespec-us#1909 queued (the corpus scope holding Rev. Proc. 2026-26 is not in rulespec-us's pinned release)

🤖 Generated with Claude Code

MaxGhenis and others added 3 commits October 24, 2026 13:15
Rev. Proc. 2026-26 section 3.01 sets the premium tax credit applicable
percentage table for taxable years beginning in 2027. Before this,
initial.yaml and final.yaml stopped at 2026, so 2027 reused the 2026
table (6.60% instead of 6.78% at 200% FPL).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
YAML cases pin aca_required_contribution_percentage at every 2027 band edge
and at interior points, and derive aca_ptc in 2027 from the table, including
two cases that derive the poverty-line fraction from income and the 2026 HHS
guideline. Expected values come from Rev. Proc. 2026-26 section 3.01.

The Hypothesis test checks every year's table from 2018 through 2027: the
percentage equals the table at each edge, stays within and is continuous in
each tier, never decreases with income, and the required contribution never
decreases with income.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 24, 2026 16:15
26 CFR 1.36B-3(g)(1) rounds the interpolated applicable percentage to the
nearest hundredth of a percent. The pairwise slope bound now allows one
rounding step (0.0001), so the test stays valid if the model adopts that
rounding. The contribution test also keeps four fixed incomes in distinct
tiers, so no example compares only equal incomes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…come

Replace the pairwise step bound with a pointwise one: at each drawn income the
percentage is within half a rounding step (0.00005) of the tier's straight
line. That is the regulation's statement, interpolation then rounding to the
nearest hundredth of a percent, and it implies the pairwise bound. A bow of
up to 0.00008 that keeps endpoints and order passed the pairwise bound and
fails this one; rounding still passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 24, 2026 20:54

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the 2027 premium tax credit applicable percentages (Rev. Proc. 2026-26)

1 participant