Skip to content

Tax Form 2555 filers' income at stacked rates (26 U.S.C. 911(f)) - #9761

Merged
MaxGhenis merged 8 commits into
mainfrom
feie-tax-stacking-911f
Oct 5, 2026
Merged

MaxGhenis merged 8 commits into
mainfrom
feie-tax-stacking-911f

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A filer who excludes foreign earned income under section 911 pays tax on the rest of their income at the rates it would face on top of the excluded amount. The model did not do this: nothing in the income tax read foreign_earned_income_exclusion, so the included income was taxed from the bottom bracket. This PR applies 26 U.S.C. 911(f) to the regular tax, the capital gains rates and the alternative minimum tax, following the IRS worksheets line by line.

Example (2025, head of household, $60,000 of included wages, $40,000 excluded): tax before credits was $4,025. The Foreign Earned Income Tax Worksheet gives tax on $76,375 ($9,978 by the Tax Table) less tax on $40,000 ($4,463) = $5,515. The model now gives $5,517.50: the Tax Table taxes the middle of each $50 row, the model the exact amounts.

The law

26 U.S.C. 911(f)(1) (read at https://www.law.cornell.edu/uscode/text/26/911#f on 2026-10-02): if any amount is excluded under section 911(a), then, notwithstanding sections 1 and 55,

(A) if such taxpayer has taxable income for such taxable year, the tax imposed by section 1 for such taxable year shall be equal to the excess (if any) of— (i) the tax which would be imposed by section 1 for such taxable year if the taxpayer's taxable income were increased by the amount excluded under subsection (a) for such taxable year, over (ii) the tax which would be imposed by section 1 for such taxable year if the taxpayer's taxable income were equal to the amount excluded under subsection (a) for such taxable year, and

(B) if such taxpayer has a taxable excess (as defined in section 55(b)(1)(B)) for such taxable year, the amount determined under the first sentence of section 55(b)(1)(A) for such taxable year shall be equal to the excess (if any) of— (i) the amount which would be determined under such sentence for such taxable year (subject to the limitation of section 55(b)(3)) if the taxpayer's taxable excess (as so defined) were increased by the amount excluded under subsection (a) for such taxable year, over (ii) the amount which would be determined under such sentence for such taxable year if the taxpayer's taxable excess (as so defined) were equal to the amount excluded under subsection (a) for such taxable year.

For purposes of this paragraph, the amount excluded under subsection (a) shall be reduced by the aggregate amount of any deductions or exclusions disallowed under subsection (d)(6) with respect to such excluded amount.

911(f)(2)(A) handles a filer whose net capital gain exceeds taxable income (the "capital gain excess"): in figuring the tax under (1)(A)(i), "(i) the taxpayer's net capital gain (determined without regard to section 1(h)(11)) shall be reduced (but not below zero) by such capital gain excess, (ii) the taxpayer's qualified dividend income shall be reduced by so much of such capital gain excess as exceeds the taxpayer's net capital gain (determined without regard to section 1(h)(11) and the reduction under clause (i)), and (iii) adjusted net capital gain, unrecaptured section 1250 gain, and 28-percent rate gain shall each be determined after increasing the amount described in section 1(h)(4)(B) by such capital gain excess." 911(f)(2)(B) applies the same rules to the AMT with the taxable excess in place of taxable income, and keeps the regular tax's 0% and 15% bracket room for Form 6251 Part III.

Effective dates. Pub. L. 109-222 (TIPRA) §515(c) added 911(f); §515(d): "shall apply to taxable years beginning after December 31, 2005." Pub. L. 110-172 §4(c) rewrote it in its current form (the capital gain excess rules and "if such taxpayer has taxable income"); §4(d)(3): "The amendment made by subsection (c) shall apply to taxable years beginning after December 31, 2006." Pub. L. 113-295 §215(a) restored the (d)(6) sentence and §202(b) widened (2)(B)(ii), both as technical corrections. The earliest year the model computes the federal income tax is 2015 (2014 raises ParameterNotFoundError), so no date gate is needed.

The IRS worksheets (2025, https://www.irs.gov/pub/irs-pdf/i1040gi.pdf#page=37): Foreign Earned Income Tax Worksheet—Line 16. "If Form 1040 or 1040-SR, line 15, is zero, don't complete this worksheet." Line 1 is taxable income; line 2a the Form 2555 lines 45 and 50 amounts; line 2b "the total amount of any itemized deductions or exclusions you couldn't claim because they are related to excluded income"; line 2c = 2a − 2b, not below zero; line 3 = 1 + 2c; line 4 = tax on line 3 (the Qualified Dividends and Capital Gain Tax Worksheet or Schedule D Tax Worksheet with line 3 as its line 1); line 5 = tax on line 2c (Tax Table or Tax Computation Worksheet); line 6 = 4 − 5, not below zero. Its footnote defines the capital gain excess as "line 4 of your Qualified Dividends and Capital Gain Tax Worksheet (line 10 of your Schedule D Tax Worksheet)" less Form 1040 line 15, and makes four modifications to a second worksheet: reduce line 3 (Schedule D Tax Worksheet line 9) by the excess; reduce line 2 (line 6) by the excess not used; reduce Schedule D line 18 by the excess; enter the excess as a loss on line 16 of the Unrecaptured Section 1250 Gain Worksheet. The 2025 Form 6251 instructions (https://www.irs.gov/pub/irs-pdf/i6251.pdf#page=10) have the same worksheet for line 7, figured at the 26%/28% rates or through Part III, and (page 13) the same four modifications for an "AMT capital gain excess" (gains less Form 6251 line 6). Lines 20 and 27 of Part III "take into account your regular tax capital gain excess".

What changed

New variables (variables/gov/irs/tax/federal_income/foreign_earned_income_exclusion/), each equal to the existing amount for a filer without an exclusion:

Variable Law Worksheet
taxable_income_plus_section_911_exclusion 911(f)(1)(A)(i) line 3
section_911_capital_gain_excess 911(f)(2)(A) footnote
section_911_net_capital_gain, section_911_qualified_dividend_income 911(f)(2)(A)(i)-(ii) modifications 1 and 2
section_911_28_percent_rate_gain, section_911_unrecaptured_section_1250_gain, section_911_adjusted_net_capital_gain 911(f)(2)(A)(iii), 1(h)(3)-(6) modifications 3 and 4
amt_income_less_exemptions_plus_section_911_exclusion 911(f)(1)(B)(i) Form 6251 worksheet line 3
amt_section_911_capital_gain_excess 911(f)(2)(B)(i) Form 6251 Part III, Form 2555 (line 10 of the Schedule D Tax Worksheet less line 6)

Formulas changed:

  • income_tax_main_rates: tax on line 3 less capital gains, less the tax on the excluded amount (lines 4 to 6). A shared helper, tax_at_main_rates, now runs the bracket loop for it, regular_tax_before_credits and the additional_tax_bracket reform, and keeps the income_tax_main_rates returns large negative values (−$81.7k on $8.2k taxable income) under TCJA-expiration parameters; NE/CO/OR conformity imports it into state tax #9084 clamp.
  • capital_gains_excluded_from_taxable_income, capital_gains_tax: section 1(h) on line 3 with the reduced gains.
  • dwks14, dwks19, regular_tax_before_credits (the Schedule D Tax Worksheet copy used as the AMT comparator): line 1 is line 3 and lines 9, 10, 13 and Schedule D line 19 are refigured for the excess (helper schedule_d_tax_worksheet_after_capital_gain_excess). The worksheet path measures the excess from worksheet line 10, as the footnote does; the section 1(h) path measures it from net capital gain, as the statute does. On a return the two are the same amount. In the model dwks10 and net_capital_gain are separate formulas that can disagree: net_capital_gain subtracts the Form 4952 election and the worksheet lines do not apply it as lines 3 to 9 do. That predates this PR and is filed as a follow-up; two YAML cases set the two amounts apart by direct input, labelled synthetic, to pin which one each path reads.
  • The reduced non-dividend gain used for unrecaptured section 1250 gain is computed in place (section_911_net_capital_gain_other_than_dividends) rather than stored: a stored amount is rounded to single precision, and an earlier revision that stored it moved capital_gains_tax by up to $0.004 for 3 tax units with nothing excluded (caught by the microsimulation below; test_nothing_excluded_changes_nothing now has households with cent amounts and compares the helper with main's expression bit for bit, so it would catch that).
  • amt_lower_base_tax, amt_higher_base_tax, amt_tax_including_cg: Form 6251 on line 3, Part III lines 13 to 15 after the AMT capital gain excess, lines 20 and 27 from the regular tax.
  • alternative_minimum_tax: subtracts the AMT on the excluded amount (Form 6251 worksheet lines 5 and 6).
  • Reform copies kept consistent: additional_tax_bracket (both variables, with the reform's own schedule for line 5), the Biden and Harris capital_gains_tax copies, and the CRFB highest_tax_rate. In the Biden reform the rates stack but the $1 million threshold is tested on taxable income without the excluded amount: the proposal tests the filer's income, which leaves out amounts excluded under section 911.
  • foreign_earned_income_exclusion is relabelled "Foreign earned income exclusion" (it was "Foreign earned income ALD"; it is not subtracted in AGI).

The child tax credit's tax limit reads income_tax_before_credits on its no_salt branch (ctc_limiting_tax_liability), so it sees the stacked tax with no change; the itemization branches likewise compare stacked liabilities.

Invariants (stated and executed)

policyengine_us/tests/test_section_911_tax_stacking.py, run on a 700-household grid (four filing statuses × wages, gains and exclusions) and on Hypothesis-generated households (some itemizing), for 2018, 2022, 2025 and 2026:

  1. With nothing excluded, every amount section 911(f) replaces equals the amount it replaces, bit for bit: the stacked bases, the reduced gains, and the refigured Schedule D Tax Worksheet lines 9, 10, 13 and Schedule D line 19 (test_nothing_excluded_changes_nothing, on households with 28-percent rate gain, unrecaptured section 1250 gain and itemized deductions, 2018, 2025, 2026). A household without an exclusion also gets the same results whatever other households in the batch exclude.
  2. Worksheet line 3 is line 1 plus line 2c.
  3. The stacked tax is never below the unstacked tax (regular tax and tax before credits).
  4. The tax never falls as the excluded amount rises.
  5. Zero taxable income gives zero regular tax, whatever is excluded.
  6. The regular tax is at most 37% of taxable income.
  7. The capital gain excess is non-negative and only a filer with an exclusion has one.

Differential test. The same file transcribes the 2025 Foreign Earned Income Tax Worksheet, Qualified Dividends and Capital Gain Tax Worksheet, Form 6251 worksheet and Part III line by line, and compares them with the model household by household. The model reaches the tax by a different route (the section 1(h) formulas), so this checks one against the other. The transcribed rate schedule matches all 8,240 cells of the 2025 Tax Table (rounded at each row's midpoint) and the Tax Computation Worksheet exactly; the full check ran outside the repo, and test_transcribed_schedule_matches_the_2025_tax_table keeps 12 Tax Table rows and 8 Tax Computation Worksheet rows in the repo. The differential and property tests leave out 28-percent rate gain and unrecaptured section 1250 gain because of the pre-existing capital_gains_tax gaps listed under "Not covered"; YAML cases cover the excess reductions of those gains.

Regression against main (run outside the repo). A 4,000-household random grid per year (2018, 2022, 2025, 2026; wages, self-employment income, long- and short-term gains, collectibles, unrecaptured section 1250 gain, dividends, interest, itemized deductions; all four filing statuses), plus the additional bracket, Biden and Harris capital gains reforms in 2025 and 2026, with no exclusion: all 234 output arrays are bitwise identical on main and this branch. (In the additional bracket reform, 16 arrays are NaN for every household on both, at the same positions; that predates this PR.) Scripts: grid.py / grid_diff.py in the evidence folder.

Tests

  • YAML unit tests for each new variable and for income_tax_main_rates, capital_gains_excluded_from_taxable_income, capital_gains_tax, dwks14, dwks19, regular_tax_before_credits, the AMT base taxes, amt_tax_including_cg and alternative_minimum_tax, with worksheet line comments.
  • Household cases (foreign_earned_income_exclusion/integration.yaml): head of household in the 12% bracket where the Tax Table is exact (line 4 $6,869, line 5 $3,263, line 6 $3,606, against $3,266 unstacked), the review example, joint filers on the Tax Computation Worksheet, gains with and without a capital gain excess, an excess that reaches qualified dividends, zero taxable income, and an AMT case with an AMT capital gain excess.
  • credits/ctc/integration.yaml: a 2025 head of household with two children, $60,000 of wages and $40,000 excluded (positive taxable income). The CTC limit sees the stacked tax ($5,517.50), which covers the whole $4,400 credit, so income tax is $1,117.50 and nothing is refundable with or without the section 24(d)(3) bar of Deny the refundable CTC and the EITC to section 911 filers (26 U.S.C. 24(d)(3), 32(c)(1)(C), 6012(c)) #9750. Deny the refundable CTC and the EITC to section 911 filers (26 U.S.C. 24(d)(3), 32(c)(1)(C), 6012(c)) #9750's own household case uses zero taxable income, where stacking cannot matter; the new case sits at the top of the file so the two PRs do not conflict (checked with git merge-tree).

Microsimulation

Default dataset (populace_us_2024.h5@populace-us-2024-spm-20260909), 2026, main (615a0f2) against this branch, one run each, compared per tax unit (79,729 tax units, 165.4 million weighted). The dataset has no foreign_earned_income_exclusion column (no tax unit has a positive value), so the expected impact is $0, and it is: all 18 outputs compared are bitwise identical on every tax unit (taxable_income, capital_gains_excluded_from_taxable_income, income_tax_main_rates, capital_gains_tax, dwks14, dwks19, regular_tax_before_credits, amt_income_less_exemptions, amt_base_tax, amt_tax_including_cg, alternative_minimum_tax, income_tax_before_credits, non_refundable_ctc, refundable_ctc, income_tax_capped_non_refundable_credits, income_tax, state_income_tax, and the exclusion itself). Weighted federal income tax: $2,571.09bn on both. Peak memory 13.8 GB (main) and 15.5 GB (branch) on policyengine-core 3.32.12. The change takes effect for Form 2555 filers once a dataset carries the exclusion.

Other readers of the changed amounts

  • Arizona property tax credit. az_property_tax_credit_income adds capital_gains_excluded_from_taxable_income, which for a Form 2555 filer is now figured on the stacked base. For a filer whose gains exceed taxable income this lowers that amount. Run on both: a single 2025 Arizona filer with $10,000 of long-term gains and $40,000 excluded has capital_gains_excluded_from_taxable_income $10,000 on main and $0 here, so az_property_tax_credit_income falls from $20,000 to $10,000 (on main the gains were counted twice, once in AGI). Arizona's use of this variable was already wrong: ARS 43-1072 counts "capital gains excluded from adjusted gross income", while the variable is gains taxed at the capital gains rates, which are already in AGI. That is filed as a follow-up rather than patched here.
  • Form 6251 line 18 for separate filers (the existing bug below) now applies to more filers: line 17 includes the excluded amount, so a separate filer with gains and a large exclusion reaches the misapplied breakpoint more often. Run here: a 2025 separate filer with $100,000 of qualified dividends and $200,000 excluded has Form 6251 line 12 of $231,500 and line 17 of $200,000. The model's line 38 is $56,725 where the form gives $58,334 (line 18 at the separate filer's breakpoint, $53,609 rather than $52,000), so worksheet line 6 is $3,116 rather than $4,725. The regular tax ($12,637.50) is higher either way, so the AMT is $0 in both.

Not covered

  • Line 2b (itemized deductions disallowed because they relate to excluded income) and the Form 2555 line 50 housing deduction have no separate inputs; foreign_earned_income_exclusion stands for line 2c.
  • Schedule J and Form 8615 are not modeled, so there is no interaction to handle.
  • Three gaps in the model's capital gains and AMT computations that predate this PR and are not about section 911 showed up in the differential test: capital_gains_tax taxes 28-percent rate gain in full even beyond taxable income (1(h)(1)(F)), uses the zero-rate amount where 1(h)(1)(A)(ii)(I) says "taxed at a rate below 25 percent", and omits the 1(h)(1) cap at the ordinary-rate tax (worksheet line 25); and Form 6251 Part III line 18 ignores the separate-filer breakpoint. Each is filed as a follow-up. The tests here stay out of those cases and say so. Related and also predating this PR: Form 6251 line 27 reads dwks14 where the form asks for Schedule D Tax Worksheet line 21, which differs for filers with 25% or 28% gains above the 24% bracket (covered by the capital gains follow-up).

axiom: TheAxiomFoundation/rulespec-us#1478 queued (us:statutes/26/911/f; rulespec-us has no 911(f) module, and its §55 module fails closed for any section 911 exclusion)

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 2, 2026 18:08
A filer who excludes foreign earned income under section 911(a) pays tax on
the rest of their income at the rates it would face on top of the excluded
amount (26 U.S.C. 911(f); the Foreign Earned Income Tax Worksheet for Form
1040 line 16 and Form 6251 line 7). Nothing in the income tax read
foreign_earned_income_exclusion, so that income was taxed from the bottom
bracket.

- income_tax_main_rates, capital_gains_excluded_from_taxable_income and
  capital_gains_tax apply section 1 to taxable income plus the excluded
  amount and subtract the tax on the excluded amount alone.
- A capital gain excess (911(f)(2)(A)) reduces net capital gain, qualified
  dividends, 28-percent rate gain and unrecaptured section 1250 gain, so the
  excluded amount is never taxed at the capital gains rates.
- The Schedule D Tax Worksheet copy (dwks14, dwks19,
  regular_tax_before_credits) and Form 6251 (base taxes, Part III,
  alternative_minimum_tax) follow the same worksheets, with the AMT capital
  gain excess of 911(f)(2)(B).
- The bracket loop is shared (tax_at_main_rates) and keeps the #9084 clamp;
  the additional bracket, Biden and Harris reform copies stay consistent.

Tests: YAML unit and household cases with worksheet line comments, checked
against the 2025 Tax Table and Tax Computation Worksheet; Hypothesis property
tests and a differential test against a line-by-line transcription of the
2025 worksheets.

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 2, 2026 22:13
…reshold

- test_nothing_excluded_changes_nothing checks, bit for bit, that every
  amount section 911(f) replaces equals the original when nothing is
  excluded (stacked bases, reduced gains, refigured worksheet lines), on
  households with 28-percent rate and unrecaptured section 1250 gains and
  itemized deductions; the property tests now include itemizers, and a
  Tax Table spot check keeps the transcribed schedule honest in the repo.
- section_911_net_capital_gain_other_than_qualified_dividends replaces three
  copies of the same reduction (capital_gains_tax and the Biden and Harris
  reform copies).
- The Biden reform tests its $1 million threshold on taxable income without
  the excluded amount; only the rates stack.
- Excess YAML cases no longer pass an adjusted net capital gain input the
  formula rebuilds; foreign_earned_income_exclusion is relabelled.

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

- schedule_d_tax_worksheet_after_capital_gain_excess takes the taxable base
  (taxable income, or Form 6251 line 6) and measures the capital gain excess
  from worksheet line 10, as the Form 1040 and Form 6251 instructions do;
  amt_section_911_capital_gain_excess uses the same definition. The section
  1(h) formulas keep the statute's net capital gain measure.
- The reduced non-dividend gain is a helper again rather than a stored
  variable: storing it rounded it to single precision and moved
  capital_gains_tax by fractions of a cent for filers with nothing excluded
  (3 tax units in the 2026 microsimulation). With the helper, the 2026
  microsimulation is bitwise identical to main.
- The differential test checks the line-25 cap for separate filers too; new
  dwks14 case for an investment income election; comment fixes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 2, 2026 22:55
- test_nothing_excluded_changes_nothing adds households with cent amounts
  (single precision cannot store them exactly) and compares the in-place
  reduced-gain helper with main's expression bit for bit, so the rounding
  the 2026 microsimulation caught would now fail in the repo.
- The helper's file is named after its function.
- amt_section_911_capital_gain_excess and section_911_capital_gain_excess
  say which measure each uses (worksheet line 10 or net capital gain); new
  AMT case with an investment income election.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CTC's tax limit sees the stacked tax: 2025 head of household, two
children, $60,000 wages, $40,000 excluded: tax before credits $5,517.50,
CTC $4,400 non-refundable, income tax $1,117.50.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cases used a Form 4952 election to set worksheet line 10 apart from net
capital gain and presented the result as worksheet arithmetic. On the real
worksheet the election reduces line 9 (lines 3, 4 and 8), so line 10 equals
net capital gain; the model's dwks09/dwks10 do not apply it, which predates
this branch. The cases now set dwks10 and net_capital_gain by direct input,
say they are synthetic, and only pin which amount each excess reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 3, 2026
The new test file skips itself through pytest.importorskip when hypothesis
is missing, and main's dev extras did not include it. Same line as
#9761; locked with uv 0.12.13, the version CI
uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis merged commit 94c4453 into main Oct 5, 2026
35 checks passed
@MaxGhenis
MaxGhenis deleted the feie-tax-stacking-911f branch October 5, 2026 01:18
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged by the US + core hub at head 8f283a5aa3ff4bd923514a805e856204a5973e37 (squash, --admin --match-head-commit). The only block was the required approving review, which no one else can give on Max's PRs.

Gates:

  • Model review: delta round 5 (GPT-6.1 Sol) approved e962c91f5a with no findings.
  • Main merge: the branch was 51 commits behind main, so the hub merged main into it with update-branch, giving 8f283a5aa3. The PR's own diff, uv.lock included, is byte-identical before and after. An independent Opus 5.5 review of the merge approved 8f283a5aa3. It checked that the delta is only main's changes, that pyproject and uv.lock are consistent, and that none of the 11 IRS commits on main since 615a0f2d97 affects the PR. It also checked the PR together with Order the residential clean energy credit after the CTC, following Schedule 8812 Credit Limit Worksheets A and B #9742 (merged just before this): 112 + 11 YAML cases pass.
  • CI: gh pr checks exits 0. All 35 check runs on 8f283a5aa3 succeeded, including the Hypothesis property tests in the Rest job.
  • State: MERGEABLE, not a draft, no CHANGES_REQUESTED review.
  • Impact: the PR body has the real-microsimulation result, $0 on the default dataset, which has no foreign earned income exclusion.
  • Judgment: a bug fix to 26 U.S.C. 911(f) stacking, with nothing needing Max's judgment.

Follow-up noted by the reviewer, not in this PR's scope: niit_magi does not add back the section 911 exclusion.

MaxGhenis added a commit that referenced this pull request Oct 5, 2026
…ne 18 (#9780)

* Use the separate-filer breakpoint on Form 6251 Part III line 18

Line 18 applied the 26%/28% AMT scale to line 17 with the full breakpoint
($239,100 in 2025) for every filing status. 26 U.S.C. 55(b)(1)(C) halves
the dollar amount for a married individual filing a separate return, and
55(b)(3)(A) figures line 18 "at the rates and in the same manner" as
55(b)(1)(A); the 2025 Form 6251 line 18 reads "$239,100 or less ($119,550
or less if married filing separately) ... subtract $4,782 ($2,391 if
married filing separately)". Lines 7 and 39 (amt_lower_base_tax and
amt_higher_base_tax) already used the multiplier.

The scale is now applied with the filing-status multiplier as its
threshold factor. Filers other than married filing separately have a
multiplier of 1, which is the scale's default factor, so their line 18 is
unchanged bit for bit.

Tests: YAML cases with Form 6251 line comments (2025 and 2026, both sides
of the separate breakpoint, unrecaptured section 1250 gain, a full-chain
household), and Hypothesis property and differential tests against a
transcription of 2025 Form 6251 lines 12 to 40.

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

* Add hypothesis to the dev extras so CI runs the Part III property tests

The new test file skips itself through pytest.importorskip when hypothesis
is missing, and main's dev extras did not include it. Same line as
#9761; locked with uv 0.12.13, the version CI
uses.

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

* Read only the AMT parameter subtree in the line 18 schedule test

Building the whole parameter tree at each of the 23 years made the test
take 195 s in CI; the gov.irs.income.amt subtree takes well under a second.

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

* Address review notes on the Part III property tests

Reuse the shared tax-benefit system instead of building a second one,
compare the bitwise line 18 check over the same array, derandomize the
Hypothesis tests so unrelated pull requests draw the same examples, and
ignore the .hypothesis/ example database.

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

* Compare separate filers' AMT in the section 911(f) worksheet tests

The worksheet comparison skipped the AMT of married-filing-separately
filers with dividends or gains because Form 6251 line 18 used the full
breakpoint. With line 18 fixed, those filers match the transcribed Form
6251 too, so the skip and its docstring note go.

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

* Pin the shrunk line 18 counterexample; derandomize the 911(f) tests

Derandomizing the Part III tests meant the properties test no longer drew
the 2018 separate filer $5 above the $95,550 breakpoint that caught the
full-breakpoint line 18. Pin it as an explicit example (it fails on the
pre-fix formula). The 911(f) worksheet tests now compare separate filers'
AMT too, so give them fixed examples as well.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 5, 2026
)

* Test a Form 4952 election with section 911(f) stacking end to end

Neither the Form 4952 line 4g election test (#9781) nor the section 911(f)
stacking test (#9761) covered households with both. The new Hypothesis
tests check, on generated households with an election and an exclusion:

- closed forms for net capital gain and the section 911 amounts after the
  election (min(D, N), min(N, T), min(D, N, T));
- that the Schedule D Tax Worksheet route and the section 1(h) route give
  the same capital gain excess and reduced amounts, regular tax and AMT;
- that a zero election or exclusion matches the situation without that
  input, bit for bit;
- monotonicity in both amounts, with the intended 12%/15% overlap
  exception in the election bounded from the parameters;
- the regular tax and AMT against the transcribed 2025 Schedule D Tax
  Worksheet, Foreign Earned Income Tax Worksheet and Form 6251.

The election and the exclusion can change taxable income through the
choice to itemize (an AMT filer may itemize below the standard deduction),
so amounts that depend on taxable income are compared only where that
choice holds; income_tax, which it minimizes, is compared across it.

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

* Address review: exact gain checks, AMT excess once, docstring fixes

- Gains and worksheet lines 6-10 do not depend on taxable income, so they
  are checked exactly for every whole-dollar household, itemizers with
  fractional taxable income included (property 5 as stated).
- The AMT capital gain excess has one route; check it once against its
  closed form instead of against itself.
- Correct the wages in the 12%/15% overlap example and an inverted grid
  comment; say the zero-input test guards against leakage between
  households.

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

* Say which closed forms are exact for whole-dollar itemizers

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

* Docstring: Form 6251 line 6 can have cents without itemizing

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 5, 2026
…% bracket top, and use Schedule D Tax Worksheet line 21 on Form 6251 line 27 (#9792)

* Use the separate-filer breakpoint on Form 6251 Part III line 18

Line 18 applied the 26%/28% AMT scale to line 17 with the full breakpoint
($239,100 in 2025) for every filing status. 26 U.S.C. 55(b)(1)(C) halves
the dollar amount for a married individual filing a separate return, and
55(b)(3)(A) figures line 18 "at the rates and in the same manner" as
55(b)(1)(A); the 2025 Form 6251 line 18 reads "$239,100 or less ($119,550
or less if married filing separately) ... subtract $4,782 ($2,391 if
married filing separately)". Lines 7 and 39 (amt_lower_base_tax and
amt_higher_base_tax) already used the multiplier.

The scale is now applied with the filing-status multiplier as its
threshold factor. Filers other than married filing separately have a
multiplier of 1, which is the scale's default factor, so their line 18 is
unchanged bit for bit.

Tests: YAML cases with Form 6251 line comments (2025 and 2026, both sides
of the separate breakpoint, unrecaptured section 1250 gain, a full-chain
household), and Hypothesis property and differential tests against a
transcription of 2025 Form 6251 lines 12 to 40.

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

* Add hypothesis to the dev extras so CI runs the Part III property tests

The new test file skips itself through pytest.importorskip when hypothesis
is missing, and main's dev extras did not include it. Same line as
#9761; locked with uv 0.12.13, the version CI
uses.

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

* Read only the AMT parameter subtree in the line 18 schedule test

Building the whole parameter tree at each of the 23 years made the test
take 195 s in CI; the gov.irs.income.amt subtree takes well under a second.

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

* Address review notes on the Part III property tests

Reuse the shared tax-benefit system instead of building a second one,
compare the bitwise line 18 check over the same array, derandomize the
Hypothesis tests so unrelated pull requests draw the same examples, and
ignore the .hypothesis/ example database.

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

* Compare separate filers' AMT in the section 911(f) worksheet tests

The worksheet comparison skipped the AMT of married-filing-separately
filers with dividends or gains because Form 6251 line 18 used the full
breakpoint. With line 18 fixed, those filers match the transcribed Form
6251 too, so the skip and its docstring note go.

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

* Pin the shrunk line 18 counterexample; derandomize the 911(f) tests

Derandomizing the Part III tests meant the properties test no longer drew
the 2018 separate filer $5 above the $95,550 breakpoint that caught the
full-breakpoint line 18. Pin it as an explicit example (it fails on the
pre-fix formula). The 911(f) worksheet tests now compare separate filers'
AMT too, so give them fixed examples as well.

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

* Tax gain below the 24 percent bracket top at regular rates; use worksheet line 21 on Form 6251 line 27

26 U.S.C. 1(h)(1)(A) taxes at the regular rates the greater of taxable
income less net capital gain, or the lesser of "the amount of taxable
income taxed at a rate below 25 percent" and taxable income less adjusted
net capital gain. The model stood in the 0 percent capital gains threshold
for the below-25-percent amount, which matched only before 2018. Since
then that amount is taxable income up to the top of the 24 percent
bracket (2025 Schedule D Tax Worksheet line 19: $197,300 single).

- taxable_income_taxed_below_25_percent: the 1(h)(1)(A)(ii)(I) amount,
  from the regular rate schedule and a new 25 percent parameter.
- capital_gains_excluded_from_taxable_income and dwks19 (worksheet line
  21) use it.
- capital_gains_tax taxes at 28 percent only the 28 percent rate gain left
  after subparagraphs (A) to (E) (1(h)(1)(F), worksheet lines 41 to 43),
  so the part (A) now taxes at the regular rates is not taxed twice.
- Form 6251 Part III line 27 reads worksheet line 21 rather than line 14.
  Without 28 percent rate or unrecaptured section 1250 gain the two are
  equal, so that path is unchanged.

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

* Apply the below-25-percent amount and the 28 percent residual in the contrib reforms

Review r1 of #9792:
- The additional_tax_bracket reform replaces the regular rate schedule, so
  it now figures taxable_income_taxed_below_25_percent on its own schedule
  (from 2026 its 15 percent bracket ends at $49,300 single).
- The 1(h)(1)(F) amount is one helper, rate_gain_taxed_at_28_percent, used
  by the baseline and by the Harris and Biden capital gains reforms, which
  still taxed all 28 percent rate gain and would now tax part of it twice.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 6, 2026
Since #9761, main taxes a Form 2555 filer's included income at the rates
it would face with the exclusion added back. The grid test's docstring
and the integration.yaml note said the model did not, which contradicted
the #9761 case at the top of the same file. Both now describe the stacked
tax, and the grid test asserts that it reaches filers whose stacked tax
leaves part of the credit to refund, so the tax identity is checked on
stacked tax. The changelog fragment now names the state credits, the
reforms and the new filing reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 9, 2026
… 24(d)(3), 32(c)(1)(C), 6012(c)) (#9750)

* Deny the refundable CTC to filers electing the section 911 exclusion

26 U.S.C. 24(d)(3) says the refundable portion of the Child Tax Credit
"shall not apply to any taxpayer for any taxable year if such taxpayer
elects to exclude any amount from gross income under section 911 for such
taxable year". refundable_ctc never read foreign_earned_income_exclusion,
so Form 2555 filers got the additional child tax credit.

- Add gov.irs.credits.ctc.refundable.foreign_earned_income_exclusion_bar_applies
  (false before 2015, true from 2015: Pub. L. 114-27 section 807 applies to
  taxable years beginning after 2014).
- refundable_ctc is zero when the exclusion is positive and the bar applies.
  The fully refundable year (2021) is unchanged: section 24(i)(1)(A) switched
  off subsection (d) for filers living in the United States, which the model
  assumes.
- Apply the same bar in the Wyden-Smith reform's copy of refundable_ctc
  (H.R. 7024 amends section 24(h) and leaves 24(d)(3) in place).
- Add YAML unit, household and reform tests, and Hypothesis property tests
  (hypothesis joins the dev extras).

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

* Skip the section 911 property tests when hypothesis is not installed

Hypothesis is a dev extra. Importing it at module level would fail test
collection in any environment installed without dev extras.

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

* Apply the section 911 bar to the Puerto Rico refundable CTC

Review of the first version found two problems.

pr_refundable_ctc takes the larger of refundable_ctc and social security
taxes less the EITC, so the social security route handed the refund back
to a filer the bar had just denied. Section 24(k)(2)(B) drops only the
three-children condition for residents of Puerto Rico; it does not waive
section 24(d)(3). The bar now lives in one variable,
refundable_ctc_barred_by_section_911_exclusion, read by refundable_ctc,
the Wyden-Smith reform and pr_refundable_ctc.

The household test gave a tax figure the model computes without section
911(f), which taxes included income at the rates it would face with the
excluded amount added back. The test now uses zero taxable income, where
the Foreign Earned Income Tax Worksheet is skipped, so its figures match
the form.

Also fix two reference URLs fused by a missing comma in pr_refundable_ctc.

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

* Count the section 911 exclusion in the filing requirement; review fixes

Second review of this PR (APPROVE WITH CHANGES) found:

- With the bar on, a Form 2555 filer whose only reason to file was the
  refundable credit could become a model non-filer, which zeroes the
  premium tax credit and switches on Medicaid non-filer rules. The root
  cause predates this PR: 26 U.S.C. 6012(c) computes gross income for the
  filing requirement "without regard to the exclusion provided for in
  section 911", and tax_unit_is_required_to_file did not. It now adds the
  exclusion to gross income (as earned income, not unearned).
- The household test's counterfactual and "every figure is the form's"
  wording overclaimed; it now asserts the section 26(a)-limited credits.
- The social security case did not route through ctc_phase_in; it now
  computes the phase-in from social security taxes.
- The 2021 Puerto Rico case used an input combination 2021 law rules out.
- The property test replaces a 26(a) check that could not fail with the
  equality of the limited credits under the bar and without it, covers
  pr_refundable_ctc, and caps dependants at 17.

Also: changelog and parameter text name the 2021 exception, cite
24(k)(2)(B)(ii) and the prior-year Schedule 8812 instructions URL, fix
two fused reference URLs, and ignore .hypothesis/.

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

* Deny the EITC to section 911 claimants (26 U.S.C. 32(c)(1)(C))

Third review of this PR found that the section 6012(c) filing fix made a
Form 2555 filer a required filer, which let the EITC through: the
model's EITC lacked section 32(c)(1)(C), "The term 'eligible individual'
does not include any individual who claims the benefits of section 911".
In the new filing fixture (single, $5,000 included wages, $30,000
excluded) the EITC went from $0 to $382.50.

eitc_eligible now excludes a tax unit with a positive
foreign_earned_income_exclusion. Unlike the CTC bar, the rule has no 2015
start or 2021 exception, so it does not reuse the CTC bar variable.

Also: the deterministic grid tests move out of the Hypothesis module so
they run without the dev extra, the property tests assert a zero EITC for
section 911 claimants, and a Puerto Rico test comment cites
24(k)(2)(B)(ii).

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

* Keep section 911 filers out of New Jersey's EITC and Colorado's CTC

Fourth review of this PR found two state credits that the federal
changes made worse for section 911 filers.

- New Jersey: with the federal EITC now denied (32(c)(1)(C)), a childless
  section 911 filer fell into nj_eitc's age-exception fallback, which pays
  40% of the federal childless maximum. A single 40-year-old with $5,000 of
  included wages and a $30,000 exclusion went from $153 to $259.60; the
  law gives $0. P.L. 2021, c.130, section 1a(4) requires the filer to
  "meet all qualifications, except for the minimum or maximum age, for
  the federal earned income tax credit". nj_childless_eitc_age_eligible
  now excludes section 911 claimants.
- Colorado: co_refundable_ctc replicates the federal refundable CTC and
  subtracts the federal EITC from social security taxes. With that EITC
  now zero, a 2022 filer with three young children, $1,000 of included
  wages and a $30,000 exclusion got $76.50 of refundable basis. Colorado
  matches the allowed federal credit (1 CCR 201-2, Rule 39-22-129(1)), so
  the section 24(d)(3) bar now applies to the replica.

Removing either guard fails exactly the new cases that assert it.

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

* Section 911 claimants file, and state EITC recomputations exclude them

Fifth review of this PR found three more places where the earlier changes
moved a section 911 claimant the wrong way.

- Filing: with the refundable CTC and the EITC denied, a claimant below
  the filing threshold lost the refundable-credit reason to file and became
  a model non-filer (no premium tax credit; Medicaid non-filer rules). But
  the exclusion is claimed on Form 2555 attached to the return (Treas.
  Reg. 1.911-7(a)(1): the election "must be filed either with the income
  tax return, or with an amended return"). tax_unit_is_filer now treats a
  positive exclusion as filing.
- State EITCs: counting the exclusion toward the filing requirement
  (6012(c)) opened state credits that recompute a federal-style EITC
  without 32(c)(1)(C): Colorado's ITIN and under-25 paths, DC's childless
  credit, Illinois, Indiana's conformity check and Washington's WFTC. Each
  waives only named federal rules (age, SSN, separate filing). A new
  helper, eitc_section_911_eligible, applies the exclusion in
  calculate_eitc_like_amount and in DC's and Washington's own paths.
- AFA: the reform's copy of refundable_ctc runs current law before 2025
  and lacked the section 24(d)(3) bar, so a 2024 claimant gained $76.50
  once the federal EITC went to zero.

Removing any of the three guards fails exactly the new cases for it.

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

* Section 911 claimants file by propensity; AFA bar only before 2025

A continuing section 911 election needs no return below the filing
threshold (Treas. Reg. 1.911-7(a)(1)), so a claimant under the threshold
files only when the tax unit would file to claim a tax benefit. The
American Family Act has no section 911 bar, so the reform's copy of the
refundable CTC applies the bar only to years before 2025.

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

* Read the section 24(d)(3) bar in Credit Limit Worksheet B

ctc_credit_limit_worksheet_b_applies (#9742) repeated the bar's test
(exclusion > 0 and the parameter on, outside fully refundable years)
instead of reading refundable_ctc_barred_by_section_911_exclusion. The two
agree whenever both are calculated, so no output changes; they could
disagree only when the bar is set as an input. Worksheet B now reads the
bar, so one variable decides both the refund and the worksheet (2025
Schedule 8812 instructions: Worksheet B only if "You are not filing Form
2555").

Two YAML cases set the bar as an input in each direction, and the grid
and Hypothesis invariants check that Worksheet B equals its bar-off value
less the barred filers.

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

* Update section 911(f) comments now that main stacks the tax

Since #9761, main taxes a Form 2555 filer's included income at the rates
it would face with the exclusion added back. The grid test's docstring
and the integration.yaml note said the model did not, which contradicted
the #9761 case at the top of the same file. Both now describe the stacked
tax, and the grid test asserts that it reaches filers whose stacked tax
leaves part of the credit to refund, so the tax identity is checked on
stacked tax. The changelog fragment now names the state credits, the
reforms and the new filing reason.

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

* Describe the section 911 filing reason as a propensity in the changelog

The filing reason reads would_file_if_eligible_for_refundable_credit; the
claimant needs no refundable credit. The integration.yaml note now says
the Foreign Earned Income Tax Worksheet is skipped for the Form 2555
filer (the second case has no exclusion) and why the capped credits
equal Schedule 8812 line 14 there.

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

* Preserve AFA Puerto Rico refundable CTC after 2039

---------

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