Skip to content

Exclude section 68(c) deductions from the pre-2026 80 percent ceiling on the itemized deduction limitation - #9695

Merged
MaxGhenis merged 4 commits into
mainfrom
fix-68-80pct-cap-exclusions
Oct 4, 2026
Merged

MaxGhenis merged 4 commits into
mainfrom
fix-68-80pct-cap-exclusions

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #9693.

axiom: TheAxiomFoundation/rulespec-us#1449 queued (26 USC 68 as in effect for TY2013-2017, including the (c) exclusions, and the (f) TY2018-2025 suspension)
axiom: us:statutes/26/68#itemized_deduction_reduction_base encoded-correct (TY2026: section 68 as rewritten by P.L. 119-21 has no (c) carve-out; companion tests itemized-medical-only, itemized-interest-only, itemized-casualty-completed and itemized-68-single-deduction-lesser in us/policies/income_tax/itemized_taxable_income_deductions_pipeline.test.yaml)

rulespec-us encodes only the P.L. 119-21 section 68, from 2026. The pinned axiom-corpus release has no pre-2026 text of section 68, so the TY2013-2017 version can't be encoded until that text is ingested. The rulespec-us issue lays out that ingest and the encode.

Summary

Before P.L. 119-21, 26 USC 68(a)(2) capped the overall limitation on itemized deductions at "80 percent of the amount of the itemized deductions otherwise allowable". Section 68(c) says that, "for purposes of this section", "itemized deductions" does not include:

  • the section 213 medical deduction;
  • investment interest;
  • casualty, theft and wagering losses.

Line 2 of the Schedule A Itemized Deductions Worksheet—Line 29 removes the same amounts before line 4 takes 80%. PolicyEngine took 80% of all itemized deductions. So whenever the 80% ceiling bound, it reduced deductions too much. The verbatim law and worksheet text are in #9693.

This PR:

  1. Adds gov.irs.deductions.itemized.limitation.excluded_deductions: medical_expense_deduction, investment_interest_expense and casualty_loss_deduction, from 2009.
    • investment_interest_expense is the investment interest that interest_deduction includes (deductible_interest_expense → non_mortgage_interest).
    • wagering_losses_deduction is deducted outside total_itemized_taxable_income_deductions, so gambling losses were never in the base and are not subtracted again.
  2. In the non-OBBB branch of itemized_taxable_income_deductions_reduction, takes the 80% ceiling on the total minus those amounts: min(3% × AGI excess, 80% × max(0, total − excluded)).
  3. Leaves the OBBB branch unchanged. P.L. 119-21 sec. 70111(a) says "Section 68 is amended to read as follows" and the new text has only (a) and (b). The current OLRC note confirms that the former (c), "exception for certain itemized deductions", is gone. Medical, investment interest and casualty deductions therefore count toward the 2/37 base from 2026, and a new 2026 test pins that.
  4. Points the variable's references at the 2016 USC edition (which has (c)) and at the current OLRC text.

Changes in results

  • TY2015-2017: the reduction falls for filers above the applicable amount who have medical, investment interest or casualty deductions, whenever 80% of their other itemized deductions is below 3% of their AGI excess.
  • TY2013-2014: not computable before or after. agi_rate, itemized_deduction_rate and itemized_deductions don't resolve before 2015, and they raise ParameterNotFoundError.
  • TY2018-2025: no change; the limitation doesn't apply.
  • TY2026 onward, baseline: no change; the OBBB branch is untouched.
  • TY2026 onward, with limitation.obbb.applies set false (the prior-law counterfactual): the (c) exclusions now apply.

Engine runs, same inputs on main (bf71be3) and on this branch:

Case Worksheet Before After
2016 single, AGI 400,000, medical 60,000, charity 5,000 4,000 4,218 4,000
2017 joint, AGI 600,000, investment interest 30,000, casualty 20,000, charity 10,000 8,000 8,586 8,000
2015 head of household, AGI 500,000, medical 40,000 only 0 (line 3: "Your deduction isn't limited") 6,478.50 0
2016 separate, AGI 200,000, medical 10,000, SALT 40,000 (3% binds) 1,330.50 1,330.50 1,330.50
2026 single, AGI 900,000, medical 150,000, charity 50,000 (OBBB) 10,810.81 (2/37 × 200,000) 10,810.81 10,810.81

The figures are the reduction. policyengine-taxsim routes TAXSIM's mortgage and otheritem into deductible_mortgage_interest, so emulator outputs don't change.

Impact (real microsimulation)

Real PolicyEngine-US microsimulations, default dataset populace_us_2024.h5@populace-us-2024-spm-20260909 (79,729 tax units), policyengine-core 3.32.15. Base is main at 6b0e773; the PR is head 64f3613 (main merged in). One run per side per year, compared record by record.

  • 2026: no change. itemized_taxable_income_deductions ($1,856.0bn), taxable_income, income_tax ($2,592.6bn) and household_net_income are identical on every record. This is expected: the change applies to tax years 2013–2017 only, and 2026 uses P.L. 119-21 section 70111.
  • 2017 (an affected year): not measurable on this dataset. The same four variables are $0 in total for every record on both main and the PR (records_nonzero = 0). The 2024-based dataset carries no pre-2024 incomes, so the default data cannot price the 2013–2017 change. The household examples above are the evidence for those years.

Tests

itemized_taxable_income_deductions_reduction.yaml has five new cases. Their expected values come from the worksheet arithmetic, written out line by line in comments:

  • the five rows above;
  • the first three fail on main; the separate-filer case (the 3% leg binds) and the 2026 case pass on both, as intended;
  • the 2017 joint case uses investment_interest_expense as a person input, so it also checks how that input reaches interest_deduction and the exclusion;
  • the 2026 case takes the 37% bracket start ($640,600) from Rev. Proc. 2025-32 sec. 4.01, Table 3.

policyengine_us/tests/core/test_itemized_deduction_limitation_properties.py (new) runs 600 seeded random tax units per case through one simulation each: all five filing statuses, AGI from $0 to $1.5 million, and random mixes of the seven deduction components, with every fifth unit holding only excluded deductions. It follows the grid pattern of test_ar_medical_expense_deduction_properties.py, so it needs no new dependency. On main, 7 of its 8 tests fail. The exception is the 2026 composition test, which guards the unchanged branch.

Invariants

Property Where checked Years
Differential: the reduction and allowed deductions equal an independent restatement of worksheet lines 1-10, with the line 6 applicable amounts restated from each year's worksheet (and checked against applicable_amount.yaml) test_reduction_matches_the_line_29_worksheet 2015-2017
Bounds: 0 ≤ reduction ≤ 3% × AGI excess, and reduction ≤ 80% × non-excluded deductions (so 0 when all are excluded) test_reduction_matches_the_line_29_worksheet, test_2026_prior_law_counterfactual_uses_the_worksheet 2015-2017, 2026 counterfactual
Excluded deductions pass through: allowed ≥ excluded + 20% × non-excluded same two tests same
Invariance: raising medical, casualty or investment interest leaves the reduction unchanged and raises allowed deductions one for one test_reduction_responds_to_components_and_income 2015-2017
Monotonicity: allowed deductions never fall when any component rises; the reduction never falls when AGI rises test_reduction_responds_to_components_and_income 2015-2017
No (c) after 2025: the reduction depends only on total itemized deductions, not their mix; 0 ≤ reduction ≤ 2/37 × total test_2026_reduction_ignores_the_mix_of_deductions 2026
Prior-law counterfactual: with obbb.applies false, 2026 follows the worksheet logic at the 2026 applicable amounts test_2026_prior_law_counterfactual_uses_the_worksheet 2026

The float32 tolerance scales with the size of the operands: $0.01 plus a relative 1e-6. The 80% base is a difference of two float32 sums, which at $200,000 can leave about a cent where exact arithmetic gives 0.

Not changed here

  • 2017 disaster-relief contributions. The 2017 worksheet's line 2 also removes "qualified contributions" (P.L. 115-63 sec. 504(a)(3), and for the California wildfires P.L. 115-123 sec. 20104(a)(3), which say they "shall not be treated as an itemized deduction for purposes of section 68"). PolicyEngine doesn't model them.
  • Inputs that bypass the chain. A dataset that supplies interest_deduction, deductible_interest_expense or non_mortgage_interest directly bypasses investment_interest_expense, so the investment interest inside those amounts is not excluded.
  • §163(d). investment_interest_expense has no net-investment-income cap federally. The exclusion subtracts exactly what the total includes, so the 80% base is right either way.
  • The OBBB branch has separate issues, tracked in a follow-up: wagering losses left out of the 2/37 base, and a taxable-income leg of AGI minus exemptions that ignores the QBI, tips, overtime, car-loan-interest and senior deductions.

Verification

  • The IRS YAML suite (tests/policy/baseline/gov/irs, 1,132 passed) and the state suites that read federal itemized deductions (5,617 passed) pass locally: GA, CO, NM, ID, SC, UT, MO, LA, ME, MT, AR, states/tax, and CA deductions.
  • tests/core passes, and ruff format --check passes.

🤖 Generated with Claude Code

Before P.L. 119-21, 26 USC 68(a)(2) capped the overall limitation on
itemized deductions at 80 percent of "the itemized deductions otherwise
allowable", and 68(c) excluded medical expenses, investment interest,
and casualty, theft and wagering losses from that term. The Schedule A
Itemized Deductions Worksheet—Line 29 (2013-2017) implements this on
line 2. PolicyEngine applied the 80 percent to all itemized deductions,
so filers with medical expenses, investment interest or casualty losses
got too large a reduction whenever the ceiling bound.

Add gov.irs.deductions.itemized.limitation.excluded_deductions and
subtract it from the base of the 80 percent ceiling in the non-OBBB
branch. The P.L. 119-21 branch (2026+) is unchanged: sec. 70111(a)
rewrote section 68 without subsection (c).

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

codecov Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (909176a) to head (7b673ec).
⚠️ Report is 158 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9695   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         1    -3     
  Lines           76        30   -46     
  Branches         2         2           
=========================================
- Hits            76        30   -46     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Addresses the independent review of #9695: the excluded_deductions
comment now says the 2017 worksheet's qualified disaster-relief
contributions are not modeled, and the property test builds the
parameter tree once instead of per call.

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

Copy link
Copy Markdown
Contributor Author

Independent review, for the merge record:

  • Full review, head 86e9d4b45e: Opus 5.5 peer (subfleet job 20260929-203723-pe9695-review), APPROVE. No blockers and no majors. It recomputed every YAML expectation from the 2015-2017 worksheets and Rev. Proc. 2025-32, and traced interest_deduction → deductible_interest_expense → non_mortgage_interest → investment_interest_expense. It also confirmed that wagering_losses_deduction is outside the total, so it isn't excluded twice, and that the OBBB branch is right to stay unchanged. It raised two minor findings and two nits:
    • inputs that bypass investment_interest_expense: disclosed in the PR body;
    • the 2017 disaster-relief contributions: now noted in excluded_deductions.yaml;
    • the property test rebuilding the tax system: now cached;
    • OBBB wagering losses: out of scope, tracked as a follow-up.
  • Delta review, 86e9d4b45e → 066a85ed8e: Opus 5.5 peer (20260929-204915-pe9695-delta), APPROVE. Only the two expected files changed. The P.L. 115-63 sec. 504(a)(3) and P.L. 115-123 sec. 20104(a)(3) citations are accurate, and the cache is read-only and doesn't change behavior.
  • Local runs at 066a85ed8e:
    • property file: 8 passed;
    • reduction and limitation YAML files: 15 passed.
  • Local runs at 86e9d4b45e's content:
    • IRS YAML: 1,132 passed;
    • state suites that read federal itemized deductions: 5,617 passed;
    • tests/core and ruff format --check: passed.
  • Mutation checks: 3 of the 5 new YAML cases and 7 of the 8 property tests fail on the old formula. The rest guard branches this PR leaves unchanged.

Axiom mirror: TheAxiomFoundation/rulespec-us#1449 (queued, pe-parity).

@MaxGhenis
MaxGhenis merged commit 33424bc into main Oct 4, 2026
105 of 107 checks passed
@MaxGhenis
MaxGhenis deleted the fix-68-80pct-cap-exclusions branch October 4, 2026 13:21
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged by the US + core hub (acting as lander) on the merge gates:

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.

Pre-2026 itemized deduction limitation applies the 80% ceiling to medical, investment interest and casualty deductions

1 participant