Skip to content

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

Merged
MaxGhenis merged 5 commits into
mainfrom
aca-ptc-2027-applicable-percentage
Oct 25, 2026
Merged

MaxGhenis merged 5 commits into
mainfrom
aca-ptc-2027-applicable-percentage

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Part of #10442. That issue also asks for California Case 19 to derive the federal credit. The case arrives with #10305, so the issue stays open until #10305 lands (see "California Case 19" below).

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. This PR lands before #10305, so #10305, landing 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 stays open until then.

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 in the sloped bands 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)

The US hub ran the full default dataset for 2027: main at the merge base 41d218c474 against this PR's head 83c7d8cd1a, one run at a time under the shared heavy-job lock. Sums are weighted.

  • The premium tax credit (aca_ptc, per tax unit) falls by $2.00bn across 8,390 records (16.3 million weighted tax units); none rises, and the largest single drop is $548.
  • The credit tax units take up (used_aca_ptc) falls by $805M, and their net marketplace premiums rise by the same amount.
  • State subsidies that top up the federal credit rise by $105M in all, mostly California, Maryland, New Mexico and Massachusetts. The Basic Health Program falls by $35M.
  • Income tax, state income tax and household_net_income don't change. SPM unit net income falls by $805M, and 10 records (0.1 weighted people) move into poverty.
Output 2027 change 2027 records changed (weighted)
aca_ptc -2.00bn 8,390 (16,268,136)
assigned_aca_ptc -831.14M 2,745 (5,668,900)
used_aca_ptc -805.31M 2,718 (5,581,312)
marketplace_net_premium +805.31M 2,718 (5,581,312)
basic_health_program -34.57M 336 (692,558)
ca_premium_subsidy +22.86M 119 (421,410)
co_premium_assistance +0 2 (0)
md_premium_assistance +35.77M 134 (252,215)
nm_premium_assistance +16.40M 182 (170,993)
vt_premium_assistance +0 0 (0)
ct_covered_connecticut +629,568 18 (18,605)
ma_connector_care +29.67M 177 (265,266)
nj_njhps +0 0 (0)
wa_cascade_care_savings +21,139 2 (1,493)
healthcare_benefit_value -760.37M 3,097 (6,234,798)
household_net_income_including_health_benefits -760.37M 3,097 (6,234,798)
spm_unit_net_income -805.31M 2,591 (5,414,091)
person_in_poverty +0 10 (0)
state_income_tax +0 0 (0)
income_tax +0 0 (0)
household_net_income +0 0 (0)
household_benefits +0 0 (0)

Comparison files are in fixes/10443-impact/ on the hub host.

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
@MaxGhenis
MaxGhenis merged commit 15b2bdd into main Oct 25, 2026
39 checks passed
@MaxGhenis
MaxGhenis deleted the aca-ptc-2027-applicable-percentage branch October 25, 2026 11:42
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged at head 83c7d8cd1a97604afc65ea4f2e634158f82be1e2 with --admin --match-head-commit. The only open block was a required approving review that no one but the repo owner could give. This is a model-to-law fix, so no owner decision was needed. The gates:

  • Independent review: GPT-6.1 Sol, three rounds.
    • Round 1 (05310b2) requested changes: the property test rejected the 26 CFR 1.36B-3(g)(1) rounding. Fixed in aa7c814.
    • Round 2 (aa7c814) approved with two nits. Both were fixed in 83c7d8c with a pointwise interpolation-line bound and continuity wording.
    • Round 3 approved this head. Its one nit, a mutant that also bowed flat bands, was rerun with the bow limited to sloped bands. It fails at the line-bound assertion.
  • CI: gh pr checks exits 0, and the latest "Pull request" run at this head concluded success. MERGEABLE, not a draft, no CHANGES_REQUESTED.
  • Impact: the hub's full-file 2027 run (main 41d218c vs this head), in the body. aca_ptc falls $2.00bn, used_aca_ptc falls $805M, and state top-ups rise $105M. Income taxes and household_net_income are unchanged.
  • Partner tests: untouched, and none has a 2027 or later case.
  • Follow-up owed: Decide CA Premium Subsidy eligibility on the exact FPL ratio and adopt the Final 2027 design #10305 lands second, so it changes California Case 19 to derive aca_ptc ($6,091.82 federal, ca_premium_subsidy $478.80). Add the 2027 premium tax credit applicable percentages (Rev. Proc. 2026-26) #10442 stays open until then.
  • Separate follow-up: rounding the applicable percentage to the nearest hundredth of a percent (26 CFR 1.36B-3(g)(1)), which the model has never done.

🤖 Generated with Claude Code

MaxGhenis added a commit that referenced this pull request Oct 26, 2026
Main now carries the federal 2027 applicable percentage table (#10443,
Rev. Proc. 2026-26), which gives 6.78% at exactly 200% FPL. Case 19 no
longer supplies aca_ptc; it derives it and pins the federal credit,
8,256 - 0.0678 * 31,920 = 6,091.824, as an output. The state subsidy
stays 478.80.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 26, 2026
…t the Final 2027 design (#10305)

* Follow the adopted CA Premium Subsidy design at the 150% FPL boundary

Gov. Code 100800(c) delegates the state premium subsidy design to the
Covered California Board. The adopted 2026 Program Design runs its bands
"100% up to 150%" (0%) and "Above 150% up to 165%"; the 2026 Policy
Explainer labels the upper band "150% - At or Below 165%". The model now
puts a fraction equal to a threshold in the lower band (searchsorted
side="left"), keeping the existing whole-percentage FPL truncation.

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

* Tidy CA premium subsidy tests and pin the FPL truncation (review r1)

Review r1 P3s: searchsorted comments now say side="left"; Case 13 explains
the continuous rate at 165% in 2027; Case 2b tests 1.505 instead of
duplicating Case 7; a new case derives 150.49% from wages and shows the
truncated fraction pays 0%; the threshold comment notes the truncation is
the federal form's gap-fill; the eligibility test header matches the
formula's FPL-band description.

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

* Pin truncation, not rounding, in the CA 150% income case (review r2)

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

* Select California premium subsidy bands from exact income

* Document exact California subsidy boundaries and lookup rounding

* Decide CA Premium Subsidy eligibility on the exact FPL ratio

ca_premium_subsidy_eligible compared the truncated aca_magi_fraction with
<= 1.65, so every PY2026 income from 165.003% to 165.994% of FPL passed
an "at or below 165 percent" test (Program Design (d)(7)). Compare the
exact ratio of nonnegative ACA MAGI to prior-year FPG instead, as FTB 3849
Table 1-2 does for the predecessor program's band edges.

The PY2027 limit was 1.99 on the truncated fraction, which equals "under
200 percent" only under truncation. Express it as 2.0 with a new
fpl_limit_inclusive parameter (true in PY2026, false in PY2027), the same
pattern as NM's benchmark_gross_up.boundary_inclusive.

Tests: boundary cases from derived income at $25,822.50 / $25,823 /
$25,978 / $25,979 (PY2026) and $26,335 / $31,919 / $31,920 (PY2027);
supplied cases now set aca_magi and prior-year FPG instead of the
fraction; a Hypothesis differential test against an exact-rational
reading of (d)(7).

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

* Add 100% floor cases from derived income; merge duplicate reference

Cases 1b and 2b test the PY2026 floor at $15,649 (99.994%, ineligible)
and $15,650 (exactly 100%, eligible) of the 2025 one-person FPG, so the
PE tests mirror the companion cases added to rulespec-us#1832. The two
2026 Program Design references differed only by #page=, so they become
one entry per the repo's reference rules.

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

* Divide in float64; make the property test cache-safe

The model stores MAGI and FPG as float32. A float32 quotient can round a
ratio a fraction of a cent above 165% of a fractional guideline down to
1.65 (e.g. $18,711.599609375 over $11,340.36328125), so the gate now
divides in float64. On float32 inputs that classifies every ratio exactly
against 1.00, 1.65 and 2.00.

The property test built one simulation per year and reused it, deleting
only the output array, so derived intermediates could stay cached across
Hypothesis examples. It now builds a fresh simulation per example. Its
reference reads (d)(7) on the stored float32 values, the generator adds
fractional guidelines and incomes a few float32 steps from each edge, and
explicit examples cover the float32 counterexamples and a 72-person
household at exactly 166% that main's float32 truncation misrounds to
165.99%.

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

* Address California premium subsidy reviews and record the 150 percent source conflict

* Move PY2027 to the Final 2027 California Premium Subsidy Program Design

The Final 2027 Program Design replaces the V4 schedule this model carried:
(d)(4) has one paying band, "Above 150% up to 200%", from 2.8% to 5.28%
(V4: 2.69%-3.41% to 165%, then 3.41%-5.1%), and (d)(7) makes household
income "at or below 200 percent" eligible (V4: "under 200 percent").

- Thresholds [1, 1.5, 2.0], initial [0, 0.028], final [0, 0.0528].
- Both years' limits are inclusive, so drop fpl_limit_inclusive and test
  the exact ratio with <=.
- The OE27 enroller deck's summary slide says "up to under 200% FPL" while
  its own 200% example applies 5.28%; follow (d)(7) and record candidate
  us-ca:premium-subsidy-200-fpl-limit.
- Rate, amount and eligibility cases move to the Final Design, including
  the deck's $31,920 example (5.28%, $478.80 a year) and incomes that
  truncate to 2.00 but exceed 200%; the property tests read 2027 as
  inclusive and #10301's rate properties now cover 2027.

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

* Divide the CA Premium Subsidy band ratio in float64

The model stores aca_magi and tax_unit_fpg as float32. Their float32
quotient can round an exact ratio just above 150% of a fractional FPG
down onto 1.5, which side="left" then puts in the 0% band. Divide in
float64, as the eligibility gate already does, and add a float32
regression test for both plan years. Whole-dollar FPGs pick the same
band either way.

Amount Case 19 supplies aca_ptc at the official Rev. Proc. 2026-26
credit. Say why in the case: the federal parameters still carry the
2026 applicable percentages into 2027, so a derived credit would use
6.60% instead of 6.78% at 200% FPL.

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

* Derive Case 19's federal credit from the 2027 table

Main now carries the federal 2027 applicable percentage table (#10443,
Rev. Proc. 2026-26), which gives 6.78% at exactly 200% FPL. Case 19 no
longer supplies aca_ptc; it derives it and pins the federal credit,
8,256 - 0.0678 * 31,920 = 6,091.824, as an output. The state subsidy
stays 478.80.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant