Repository navigation
Tax Form 2555 filers' income at stacked rates (26 U.S.C. 911(f)) - #9761
Merged
Merged
Conversation
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>
…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>
- 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>
This was referenced Oct 3, 2026
Contributor
Author
|
Merged by the US + core hub at head Gates:
Follow-up noted by the reviewer, not in this PR's scope: |
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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,
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:taxable_income_plus_section_911_exclusionsection_911_capital_gain_excesssection_911_net_capital_gain,section_911_qualified_dividend_incomesection_911_28_percent_rate_gain,section_911_unrecaptured_section_1250_gain,section_911_adjusted_net_capital_gainamt_income_less_exemptions_plus_section_911_exclusionamt_section_911_capital_gain_excessFormulas 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_creditsand theadditional_tax_bracketreform, 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 (helperschedule_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 modeldwks10andnet_capital_gainare separate formulas that can disagree:net_capital_gainsubtracts 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.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 movedcapital_gains_taxby up to $0.004 for 3 tax units with nothing excluded (caught by the microsimulation below;test_nothing_excluded_changes_nothingnow 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).additional_tax_bracket(both variables, with the reform's own schedule for line 5), the Biden and Harriscapital_gains_taxcopies, and the CRFBhighest_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_exclusionis 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_creditson itsno_saltbranch (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: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.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_tablekeeps 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-existingcapital_gains_taxgaps 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.pyin the evidence folder.Tests
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_cgandalternative_minimum_tax, with worksheet line comments.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 withgit 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 noforeign_earned_income_exclusioncolumn (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
az_property_tax_credit_incomeaddscapital_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 hascapital_gains_excluded_from_taxable_income$10,000 on main and $0 here, soaz_property_tax_credit_incomefalls 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.Not covered
foreign_earned_income_exclusionstands for line 2c.capital_gains_taxtaxes 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 readsdwks14where 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