Repository navigation
Give the additional_tax_bracket reform's unset bracket zero tax instead of NaN - #9831
Merged
Merged
Conversation
With its shipped parameters, brackets 7 and 8 of the reform's schedule have infinite thresholds, and its income_tax_main_rates and regular_tax_before_credits are NaN for every household. Three YAML cases pin the finite tax the reform should give (2026 joint and zero-income filers, and the 2025 joint rate table from Rev. Proc. 2024-40, section 2.01). Property tests check tax_at_main_rates for any thresholds, finite or infinite, against policyengine-core's MarginalRateTaxScale and against the old clip form wherever it was defined. A reform-level property checks that, for any thresholds of brackets 7 and 8, the reform's taxes are finite and at least the taxes with the bracket removed. On main, the three YAML cases and seven of the eight Python tests fail with NaN. The check that the baseline schedule is unchanged passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tax_at_main_rates took each bracket's amount as amount_between's clip(x, bottom, top) - bottom. Above an infinite threshold, a bracket runs from infinity to infinity and that is inf - inf = NaN, so the additional_tax_bracket reform, whose brackets 7 and 8 ship with infinite thresholds, gave NaN for every household. The loop now takes max(0, min(x, top) - bottom), as policyengine-core's MarginalRateTaxScale.calc does. That is zero for such a bracket and equals the clip form bit for bit whenever the bottom is finite, so the baseline schedule is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Suppress Hypothesis's too_slow and data_too_large health checks, as the repository's other Hypothesis tests do: on a loaded machine one draw stalled for 180 seconds and failed the reform-level property. - Each reform-level example runs two simulations on clones of the reform's system, and the file runs in both the contrib YAML step and the contrib Python step. Set brackets 7 and 8 per filing status so that one simulation covers five threshold shapes, and run three explicit and three generated examples instead of four and twelve. - Say that no simulation sets a foreign earned income exclusion, so the reform's subtraction of the tax on the excluded amount is covered only through the schedule properties. - Note that the reform's own 2026 schedule is not current law, and that the fix also covers an infinite threshold below the baseline's top bracket. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both sides appended cases to additional_tax_bracket_reform.yaml; keep both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#9792 added amount_taxed_below_rate beside tax_at_main_rates. It walks the same clamped brackets but takes each bracket's amount with amount_between's clip form, so a bracket above an infinite threshold whose rate is below the limit still gave inf - inf = NaN: for the additional_tax_bracket reform, a bracket 8 rate under 25 percent with bracket 7 unset. Both functions now take each bracket's amount from amounts_in_brackets, which holds the #9084 clamp and the max(0, min(x, top) - bottom) form, so the amount below a rate stays consistent with the tax by construction. The tests check amount_taxed_below_rate for any thresholds and any rate limit: finite, between zero and the amount, bit for bit the tax at rates of 1 below the limit and 0 otherwise, close to MarginalRateTaxScale at those rates, and bit for bit the old clip form wherever that form gave a number, including on the baseline schedule for every year from 2018 to 2035. The simulation tests also check the reform's taxable_income_taxed_below_25_percent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9831 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 4 1 -3
Lines 76 19 -57
Branches 2 4 +2
=========================================
- Hits 76 19 -57
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- Add an explicit example where a bracket's rate equals the 25 percent limit, as the reform's 2026 bracket 3 does, so a rate equal to the limit stays outside the amount taxed below it whatever examples Hypothesis generates. - Say that amount_taxed_below_rate took the clip form only for brackets taxed below its limit, and that the brackets' pieces sum to at most the taxable amount. - Reword the changelog: the bracket adds nothing to the tax and to the income taxed below 25 percent; the total amount is not zeroed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The contrib YAML batch for this folder, which also collects the Python tests, peaked at 10,719 MB on CI at a42a678, against 6,578 MB for the same folder on a recent run from main (run 37388221916). The tests built a module-level reformed system and cloned it for every simulation. Instead, apply the reform to a clone of the already loaded default system for each simulation, and collect each simulation before building the next. Locally (macOS, Python 3.14t) the folder's peak resident set fell from 14.5 GB to 9.45 GB, with the same 18 tests passing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each reformed simulation in these tests applies the reform and its parameter changes to a clone of the loaded default system. After every simulation, assert that the default system still holds its own income_tax_main_rates, regular_tax_before_credits and taxable_income_taxed_below_25_percent, and its 2026 values of the reform's schedule, so a leak into the shared system fails here rather than in a later test. The folder passes locally: 18 tests. Correction to 80f291b's message: run 37388221916 is a pull-request run on a main-based branch (nc-reduced-price-school-meals) whose folder holds only the YAML file, not a run on main; and the old tests cloned their module-level reformed system only for the simulations with parameter changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Merged by the US + core hub on its merge gates. Audit:
|
MaxGhenis
added a commit
that referenced
this pull request
Oct 6, 2026
Brings in #9831 (amounts_in_brackets, the shared bracket walk that tax_at_main_rates and amount_taxed_below_rate use) and #9788 (capital gain distributions netted inside the capital loss limit). No textual conflicts: the additional_tax_bracket reform's tax_on_taxable_income_at_main_rates override calls tax_at_main_rates, so it takes #9831's walk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 6, 2026
…s netting - test_additional_tax_bracket_unset_bracket.py (#9831) listed regular_tax_before_credits among the variables the reform replaces. On this branch the reform replaces tax_on_taxable_income_at_main_rates instead, and regular_tax_before_credits is income_tax_main_rates plus capital_gains_tax. The default-system leak check now covers the three replaced variables, and the finite and monotone checks cover the reform's three taxes: income_tax_main_rates, tax_on_taxable_income_at_main_rates and regular_tax_before_credits. - test_regular_tax_before_credits.py set aside households with capital gain distributions and a Schedule D net loss in the monotonicity property. #9788 nets the distributions inside the capital loss limit in AGI, so the property now holds for every household. The exclusion is gone, and the minimized counterexample (2018 single, $50,000 of distributions, a $40,273 short-term loss, $1 more long-term gain) is an explicit example; it failed before #9788 (the regular tax fell by $0.12) and passes now. Both files pass after the merge: 9 and 6 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 6, 2026
MaxGhenis
added a commit
that referenced
this pull request
Oct 6, 2026
…1)) and use it on Form 6251 line 10 (#9852) * Cap the regular tax at the tax on all taxable income and use it on Form 6251 line 10 26 U.S.C. 1(h)(1) says the tax "shall not exceed" the sum of the subparagraph (A) to (F) amounts, and Schedule D Tax Worksheet line 47 takes the smaller of line 45 and line 46 (the tax on all of line 1). capital_gains_tax now stops at tax_on_taxable_income_at_main_rates (new, line 46) less income_tax_main_rates. The cap binds where gain taxed at 15 percent falls in the 12 percent bracket: up to $3.75 single and $7.50 joint in 2025, and $28.50 and $57 in 2026. The Biden and Harris capital gains reforms apply the same limit, and the additional_tax_bracket reform figures line 46 on its own schedule. regular_tax_before_credits was a second Schedule D Tax Worksheet (2017 numbering) whose result was min(worksheet tax including the gains, income_tax_main_rates excluding them). Form 6251 line 10 then added capital_gains_tax. Whenever the worksheet path fell below the main-rates path, line 10 understated the regular tax: before #9781 that happened for 18 dataset tax units in 2025 ($328M weighted), because dwks10 ignored the Form 4952 line 4g election and because the worksheet took line 28 as min(line 21, line 22) instead of their sum. regular_tax_before_credits is now income_tax_main_rates plus capital_gains_tax, the regular tax income_tax_before_credits charges, and Form 6251 line 10 uses it alone. Tests: real-unit regression cases for tax units 1101624, 1004930, 1156248 and 1032460; line 45/46 boundary cases for 2025 and 2026 (single, joint, head of household, Form 2555); the existing worksheet property tests now compare with line 47 and Foreign Earned Income Tax Worksheet line 25 exactly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Cite Rev. Proc. 2025-32 section 4 for 2026 amounts Section 3 of Rev. Proc. 2025-32 modifies 2025 items (only .01, the standard deduction, and .02, section 179); the 2026 adjusted items are section 4. The 2026 AMT breakpoints are section 4.10 (PDF page 16) and the 2026 additional standard deduction for the aged or blind is section 4.14(3) (PDF page 18). Also give the dependent standard deduction citation its section number (4.14(2)). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add property and differential tests for the regular tax and the line 47 limit test_regular_tax_before_credits.py transcribes the 2025 Schedule D Tax Worksheet, lines 1 to 47, with every skip instruction, the Form 4952 election, capital gain distributions, short-term losses and Schedule D lines 18 and 19. The regular rates come from the 2025 Tax Computation Worksheet rows. 2026 runs on Rev. Proc. 2025-32's tables and capital gains amounts. The model matches lines 10, 13, 14, 21, 44, 46 and 47 for a grid, households at the 0 percent amount, and Hypothesis draws. Properties, 2018 to 2035: - 0 <= regular tax <= line 46; - 0 <= capital_gains_tax <= line 46 - income_tax_main_rates; - regular_tax_before_credits = main rates + capital gains tax; - income_tax_before_credits = regular + AMT; - the AMT is line 9 less line 10; - without net capital gain, the regular tax is line 46; - the worksheet lines (dwks10, dwks13, line 18 <= 21 <= 14); - the tax is monotone in wages, gains and dividends; - results are independent of batch order. The limit binds at the top of the 12 percent bracket in every year and filing status, with the published band widths for 2018 to 2026. The monotonicity check sets aside households with capital gain distributions and a Schedule D net loss, a known defect it found. Gross income adds non_sch_d_capital_gains outside the loss limit, while net_capital_gain nets them (a 2018 single filer's tax falls $0.12 with $1 more gain). No dataset tax unit has both. It is left for a follow-up. Also adds 2026 joint, separate and non-binding line 45/46 YAML cases, from the same Rev. Proc. 2025-32 figures as the Axiom companion tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Align the merged tests with main: #9831's reform variables and #9788's netting - test_additional_tax_bracket_unset_bracket.py (#9831) listed regular_tax_before_credits among the variables the reform replaces. On this branch the reform replaces tax_on_taxable_income_at_main_rates instead, and regular_tax_before_credits is income_tax_main_rates plus capital_gains_tax. The default-system leak check now covers the three replaced variables, and the finite and monotone checks cover the reform's three taxes: income_tax_main_rates, tax_on_taxable_income_at_main_rates and regular_tax_before_credits. - test_regular_tax_before_credits.py set aside households with capital gain distributions and a Schedule D net loss in the monotonicity property. #9788 nets the distributions inside the capital loss limit in AGI, so the property now holds for every household. The exclusion is gone, and the minimized counterexample (2018 single, $50,000 of distributions, a $40,273 short-term loss, $1 more long-term gain) is an explicit example; it failed before #9788 (the regular tax fell by $0.12) and passes now. Both files pass after the merge: 9 and 6 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Say in the changelog that regular_tax_before_credits now includes the capital gains tax PolicyEngine/salt-amt-calculator's API reads regular_tax_before_credits as its regular tax, so the meaning change belongs in the release note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Point three Rev. Proc. 2025-32 links at the pages with their 2026 amounts Three links pointed into the wrong section of Rev. Proc. 2025-32: - the capital gains rate thresholds linked page 12, which is section 4.02 (kiddie tax). Section 4.03 and its 2026 amounts (49,450, 98,900, 66,200, 545,500, 613,700, 579,600 and 306,850) are on page 13; - the child tax credit amount ($2,200) and refundable maximum ($1,700) linked page 13, which holds sections 4.03 and 4.04. Section 4.05 and its amounts are on page 14. The other parameter links to the Rev. Proc. land on the page that has the 2026 amounts or on the page where their section starts. 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 7, 2026
…worksheets (#9893) * Cap the regular tax at the tax on all taxable income and use it on Form 6251 line 10 26 U.S.C. 1(h)(1) says the tax "shall not exceed" the sum of the subparagraph (A) to (F) amounts, and Schedule D Tax Worksheet line 47 takes the smaller of line 45 and line 46 (the tax on all of line 1). capital_gains_tax now stops at tax_on_taxable_income_at_main_rates (new, line 46) less income_tax_main_rates. The cap binds where gain taxed at 15 percent falls in the 12 percent bracket: up to $3.75 single and $7.50 joint in 2025, and $28.50 and $57 in 2026. The Biden and Harris capital gains reforms apply the same limit, and the additional_tax_bracket reform figures line 46 on its own schedule. regular_tax_before_credits was a second Schedule D Tax Worksheet (2017 numbering) whose result was min(worksheet tax including the gains, income_tax_main_rates excluding them). Form 6251 line 10 then added capital_gains_tax. Whenever the worksheet path fell below the main-rates path, line 10 understated the regular tax: before #9781 that happened for 18 dataset tax units in 2025 ($328M weighted), because dwks10 ignored the Form 4952 line 4g election and because the worksheet took line 28 as min(line 21, line 22) instead of their sum. regular_tax_before_credits is now income_tax_main_rates plus capital_gains_tax, the regular tax income_tax_before_credits charges, and Form 6251 line 10 uses it alone. Tests: real-unit regression cases for tax units 1101624, 1004930, 1156248 and 1032460; line 45/46 boundary cases for 2025 and 2026 (single, joint, head of household, Form 2555); the existing worksheet property tests now compare with line 47 and Foreign Earned Income Tax Worksheet line 25 exactly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Cite Rev. Proc. 2025-32 section 4 for 2026 amounts Section 3 of Rev. Proc. 2025-32 modifies 2025 items (only .01, the standard deduction, and .02, section 179); the 2026 adjusted items are section 4. The 2026 AMT breakpoints are section 4.10 (PDF page 16) and the 2026 additional standard deduction for the aged or blind is section 4.14(3) (PDF page 18). Also give the dependent standard deduction citation its section number (4.14(2)). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add property and differential tests for the regular tax and the line 47 limit test_regular_tax_before_credits.py transcribes the 2025 Schedule D Tax Worksheet, lines 1 to 47, with every skip instruction, the Form 4952 election, capital gain distributions, short-term losses and Schedule D lines 18 and 19. The regular rates come from the 2025 Tax Computation Worksheet rows. 2026 runs on Rev. Proc. 2025-32's tables and capital gains amounts. The model matches lines 10, 13, 14, 21, 44, 46 and 47 for a grid, households at the 0 percent amount, and Hypothesis draws. Properties, 2018 to 2035: - 0 <= regular tax <= line 46; - 0 <= capital_gains_tax <= line 46 - income_tax_main_rates; - regular_tax_before_credits = main rates + capital gains tax; - income_tax_before_credits = regular + AMT; - the AMT is line 9 less line 10; - without net capital gain, the regular tax is line 46; - the worksheet lines (dwks10, dwks13, line 18 <= 21 <= 14); - the tax is monotone in wages, gains and dividends; - results are independent of batch order. The limit binds at the top of the 12 percent bracket in every year and filing status, with the published band widths for 2018 to 2026. The monotonicity check sets aside households with capital gain distributions and a Schedule D net loss, a known defect it found. Gross income adds non_sch_d_capital_gains outside the loss limit, while net_capital_gain nets them (a 2018 single filer's tax falls $0.12 with $1 more gain). No dataset tax unit has both. It is left for a follow-up. Also adds 2026 joint, separate and non-binding line 45/46 YAML cases, from the same Rev. Proc. 2025-32 figures as the Axiom companion tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Align the merged tests with main: #9831's reform variables and #9788's netting - test_additional_tax_bracket_unset_bracket.py (#9831) listed regular_tax_before_credits among the variables the reform replaces. On this branch the reform replaces tax_on_taxable_income_at_main_rates instead, and regular_tax_before_credits is income_tax_main_rates plus capital_gains_tax. The default-system leak check now covers the three replaced variables, and the finite and monotone checks cover the reform's three taxes: income_tax_main_rates, tax_on_taxable_income_at_main_rates and regular_tax_before_credits. - test_regular_tax_before_credits.py set aside households with capital gain distributions and a Schedule D net loss in the monotonicity property. #9788 nets the distributions inside the capital loss limit in AGI, so the property now holds for every household. The exclusion is gone, and the minimized counterexample (2018 single, $50,000 of distributions, a $40,273 short-term loss, $1 more long-term gain) is an explicit example; it failed before #9788 (the regular tax fell by $0.12) and passes now. Both files pass after the merge: 9 and 6 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Say in the changelog that regular_tax_before_credits now includes the capital gains tax PolicyEngine/salt-amt-calculator's API reads regular_tax_before_credits as its regular tax, so the meaning change belongs in the release note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Point three Rev. Proc. 2025-32 links at the pages with their 2026 amounts Three links pointed into the wrong section of Rev. Proc. 2025-32: - the capital gains rate thresholds linked page 12, which is section 4.02 (kiddie tax). Section 4.03 and its 2026 amounts (49,450, 98,900, 66,200, 545,500, 613,700, 579,600 and 306,850) are on page 13; - the child tax credit amount ($2,200) and refundable maximum ($1,700) linked page 13, which holds sections 4.03 and 4.04. Section 4.05 and its amounts are on page 14. The other parameter links to the Rev. Proc. land on the page that has the 2026 amounts or on the page where their section starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Test 28-percent rate gain with a Form 4952 election against the 2025 worksheets - rate_gain_with_form_4952_election.yaml: the reproducer (no taxable income; taxable income below the gain; half and all of a collectibles gain elected; no election) and an election above the 24% bracket that leaves 28% on line 9 only, with Schedule D Tax Worksheet lines. - test_section_1h_regular_tax.py: for every household and year (2018 to 2030) with elections and both gains, the regular tax is at most line 46 figured from the rate parameters, exactly zero with no taxable income, and not negative; and electing more lowers it by at most the 12/15 rate overlap plus 3% of the smaller of the extra amount elected and the unrecaptured section 1250 gain. Pins the intended exception where an election moves gain from 28 to 25 percent (section 1(h)(1)(E)(ii) measures its excess with net capital gain, which section 1(h)(2) reduces): $68,874 to $67,374 on $50,000 elected. A 2025 differential compares Form 6251 Part III and line 11 after an election with nonzero Schedule D lines 18 and 19. - test_form_6251_part_iii.py: the Schedule D Tax Worksheet transcription takes amounts, Form 4952 lines 4g and 4e, and the Foreign Earned Income Tax Worksheet footnote's four modifications. - test_section_911_tax_stacking.py and test_form_4952_section_911_interaction.py: households with 28-percent rate and unrecaptured section 1250 gain are now compared with the forms (through the Schedule D Tax Worksheet and Form 6251 Part III with the AMT capital gain excess), including rows that reach modification 4, and kept in the monotonicity properties, with the corrected election bound in place of #9800's overlap-only bound. - Harris, Biden 2025 budget and additional tax bracket reforms: a case each where the line 47 limit binds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tighten reach assertions and fix a stale docstring (hard-tier review) - test_section_1h_regular_tax.py: the grid reaches 28% tax after an election only if some elected household has a positive Schedule D Tax Worksheet line 42; a positive capital gains tax could be all at 25%. - test_section_911_tax_stacking.py, test_form_4952_section_911_interaction.py: floor the unrecaptured section 1250 gain after modification 4 at zero, so a household whose line 9 the excess exhausts does not count as reaching it. - test_form_6251_part_iii.py: the transcription, not the model, leaves out the short-term loss netting (#9841 added it to the model). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- 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
The
additional_tax_bracketcontrib reform ships brackets 7 and 8 of its schedule (gov.contrib.additional_tax_bracket.bracket) with infinite thresholds for every filing status from 2018 on. Until a user sets bracket 7's threshold, itsincome_tax_main_ratesandregular_tax_before_creditsare NaN on main for every household at any income, and so isincome_tax. I reproduced this on main for 2025, 2026 and 2027, at taxable incomes of $50,000 and $1 million, with and without long-term gains.Cause.
tax_at_main_ratesis the bracket walk shared by the baseline and the reform. It took each bracket's amount asamount_between(x, bottom, top), which isnp.clip(x, bottom, top) - bottom. Bracket 8's bottom is bracket 7's infinite threshold, so that amount isinf - inf = NaN.#9792, merged in the meantime, added
amount_taxed_below_rate, the amount behind 26 U.S.C. 1(h)(1)(A)(ii)(I), beside it. That function walks the same brackets with the same clip form, and #9792 made the reform use it fortaxable_income_taxed_below_25_percent.tax_at_main_ratesalone, a bracket 8 rate below 25% with bracket 7 unset still gave NaN for that amount.capital_gains_excluded_from_taxable_income(max_/min_of NaN) intoincome_tax_main_ratesfor every household. That last step follows from numpy's NaN semantics; I did not run it as a simulation.Fix. A new generator,
amounts_in_brackets, now produces each bracket's amount for both functions. It keeps the running-maximum clamp from #9084, so brackets never overlap, and computesmax(0, min(x, top) - bottom), the form policyengine-core'sMarginalRateTaxScale.calcuses.Baseline impact: none
test_baseline_schedule_is_unchanged_in_every_yearcompares both functions with the old clip form ongov.irs.income.bracket, for every filing status and every year from 2018 to 2035.in_effectis false) and has no baseline impact, and the shared walk's baseline outputs are bit-identical.axiom: n/a: computation fix to a bracket walk for a contrib reform's unset bracket; enacted-law outputs are bit-for-bit unchanged, so rulespec-us has nothing to mirror
Invariants (property and differential tests)
Function properties. These hold for any thresholds, finite or infinite and in any order, for rates in [0, 1] and amounts in [0, $10 million]. Each test ran 300 Hypothesis examples plus explicit ones.
tax_at_main_ratesis finite and non-negative.MarginalRateTaxScaleover the same brackets.amount_taxed_below_rate, for any rate limit in [0, 1]:MarginalRateTaxScaleat those rates;An explicit example puts a rate exactly at the limit, as the reform's 2026 bracket 3 rate of 25% is.
The reform in simulations. The grid has 50 tax units: 5 filing statuses × 5 ordinary taxable incomes × with or without $170,000 of long-term gains and qualified dividends.
With default parameters, five variables are finite in 2025 and 2026:
income_tax_main_rates,regular_tax_before_credits,taxable_income_taxed_below_25_percent,income_tax_before_creditsandincome_tax.Differential: with brackets 1 to 7 set to current law and the added bracket unset, the reform reproduces the baseline for those five variables.
For any thresholds of brackets 7 and 8 and r8 ≥ r7:
Thresholds are set per filing status, so one simulation covers five shapes: both infinite; finite bracket 7 with bracket 8 unbounded; bracket 8 below bracket 7; a zero bracket 7 threshold; and bracket 7 unbounded above a finite bracket 8. Three explicit and three generated examples run.
Removing the bracket can move bracket 8 across the 25% limit, which changes the amount taxed below 25%. These households have no 28%-rate or unrecaptured section 1250 gain, so that amount changes neither
dwks19norcapital_gains_excluded_from_taxable_incomefor them, and the inequality concerns only the schedule.No simulation sets a foreign earned income exclusion. The reform's subtraction of the tax on the excluded amount is covered only through invariants 1 to 6, not end to end.
Tests
contrib/additional_tax_bracket:tax_at_main_rates.pyand policyengine-core, with the package imports stubbed. All four fail onupstream/main's version, including theamount_taxed_below_rateproperty, and all four pass on this branch.contrib/additional_tax_bracket: 18 passed (9 YAML cases, 9 Python tests).alternative_minimum_tax,before_credits,capital_gainsandforeign_earned_income_exclusionfolders,non_sch_d_capital_gains.yaml, the contribwatca, Bidencapital_gains_tax_increaseand Harriscapital_gainsYAML files,test_negative_main_rates_inverted_brackets.py,test_form_6251_part_iii.pyandtest_form_4952_section_911_interaction.py.tests/code_health: 136 passed.The new Python file runs in two CI steps:
make test-policy-contrib-python, and the contrib YAML batch, becausetest_batched.pyhandspolicyengine-core testthe whole subdirectory. Other contrib folders with Python tests, such ascontrib/local/ny, already run that way. That is why the simulation property is kept to six examples.The new YAML cases reuse the reform combo of #9792's case, so they add no cached system. The file's combo weight is 2.25, within the 5.0 budget.
Memory.
Review
Two independent Opus reviews.
too_slowhealth check, after a loaded host stalled one draw for 180 seconds;<=-for-<mutant, a mutant without the clamp, and the clip-form version. Its wording nits are made in a42a678.Not changed here (follow-ups, filed as #9832)
🤖 Generated with Claude Code