Skip to content

Net losses against 28 percent rate gain and unrecaptured section 1250 gain (26 U.S.C. 1(h)(4), 1(h)(6)) - #9841

Merged
MaxGhenis merged 1 commit into
mainfrom
fix-dwks-28-1250-netting
Oct 6, 2026
Merged

MaxGhenis merged 1 commit into
mainfrom
fix-dwks-28-1250-netting

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

26 U.S.C. 1(h)(4) and 1(h)(6)(A) define the 28 percent rate gain and unrecaptured section 1250 gain by netting losses: collectibles loss, the net short-term capital loss and the long-term capital loss carryover come off collectibles gain and section 1202 gain, and what they do not absorb comes off unrecaptured section 1250 gain. The model had no way to apply that netting. Its only inputs, long_term_capital_gains_on_collectibles, long_term_capital_gains_on_small_business_stock and unrecaptured_section_1250_gain, are Schedule D lines 18 and 19 as reported, after the netting; the microdata fill them from the PUF's lines 18 and 19. A household that entered $10,000 of collectibles gain and an $8,000 short-term loss had all $10,000 taxed as 28 percent rate gain instead of $2,000.

This PR adds inputs for the amounts before netting and nets them as the 2025 28% Rate Gain Worksheet and Unrecaptured Section 1250 Gain Worksheet do. The existing inputs keep their meaning and pass through unchanged, so no existing dataset changes.

Follow-up 3 of #9792. Lands after the Schedule D Tax Worksheet regular-tax fix (branch fix-dwks-regular-tax-lines, PR to come); the US hub sets the order. The only textual overlap is test_section_911_tax_stacking.py.

The law and the worksheets

  • 1(h)(4): "the term 28-percent rate gain means the excess (if any) of— (A) the sum of— (i) collectibles gain; and (ii) section 1202 gain, over (B) the sum of— (i) collectibles loss; (ii) the net short-term capital loss; and (iii) the amount of long-term capital loss carried under section 1212(b)(1)(B) to the taxable year."
  • 1(h)(6)(A): unrecaptured section 1250 gain is the excess of (i) the gain that would be ordinary income if section 1250 took all depreciation over (ii) "the excess (if any) of— (I) the amount described in paragraph (4)(B); over (II) the amount described in paragraph (4)(A)."
  • 28% Rate Gain Worksheet (2025 Instructions for Schedule D): lines 1, 3 and 4 collectibles gain or (loss), line 2 section 1202 gain, line 5 long-term carryovers (Schedule D line 14 and Schedule K-1 (Form 1041) box 11 code D), line 6 the Schedule D line 7 loss; line 7, if more than zero, is Schedule D line 18.
  • Unrecaptured Section 1250 Gain Worksheet: line 13 the gain before losses; lines 14 to 16 are the 28% worksheet's lines 1 to 4, the line 7 loss and the carryover; line 17 is their combination as a positive amount if a loss; line 18 = line 13 − line 17, if more than zero, is Schedule D line 19.
  • Form 2555 (2025 Form 1040 instructions, Foreign Earned Income Tax Worksheet footnote): modification 3 reduces Schedule D line 18 by the capital gain excess; modification 4 enters the excess as a loss on line 16 of the second worksheet.

The change

  • New inputs, before netting (all zero unless entered; memo items that long_term_capital_gains already includes; uprated with the other capital gain components):
    • collectibles_gain_or_loss (Person): 28% worksheet lines 1, 3 and 4, negative for a net loss;
    • section_1202_gain (Person): line 2;
    • unrecaptured_section_1250_gain_before_losses (TaxUnit, like the reported input): 1250 worksheet line 13;
    • long_term_capital_loss_carryover (Person): Schedule D line 14 plus K-1 (1041) box 11 code D, worksheet lines 5 and 16.
  • capital_gains_28_percent_rate_gain (Schedule D line 18) = the reported amounts + max(0, collectibles gain or loss + section 1202 gain − net short-term capital loss − carryover). The net short-term capital loss is the one net_capital_gain already subtracts, max(0, −sum of short_term_capital_gains).
  • New schedule_d_unrecaptured_section_1250_gain (Schedule D line 19) = the reported amount + max(0, gain before losses − line 17); line 17 is zero whenever there is a 28 percent rate gain. The five direct readers of the reported input read it: adjusted_net_capital_gain, dwks13, section_911_unrecaptured_section_1250_gain, schedule_d_tax_worksheet_after_capital_gain_excess (Form 6251 Part III) and amt_part_iii_required. The reforms reach it only through those.
  • The existing three inputs are documented as what they are: Schedule D lines 18 and 19 as reported, already netted, with a pointer to the new inputs. Enter one family or the other for a return.
  • Massachusetts is unchanged: its 50 percent collectibles deduction still reads long_term_capital_gains_on_collectibles, and collectibles_gain_or_loss is federal only. Its collectibles treatment has a separate defect (M.G.L. c.62 §2(b)(1)(C) puts long-term collectibles gain in Part A, the model has it in Part C, and the §2(c)(2) loss ordering before the §2(c)(3) deduction is not modeled), left to its own PR.
  • The section 911 formulas are unchanged. With lines 18 and 19 netted (or reported), reducing line 18 by the excess and line 19 by the part line 18 does not absorb equals the worksheets with the excess added to the losses (shown for both signs of lines 14 to 16, and tested).

Why not give the existing inputs the before-netting meaning: the datasets fill them with PUF E24518 and E24515, Schedule D lines 18 and 19 (Tax-Calculator records), next to short-term losses already netted against them. Netting them again would double-count: on the legacy enhanced CPS 2024 (local copy of the archived policyengine-us-data file), which is still loadable, 3,398 tax units have a Schedule D line 7 loss and a second netting would take $25.5M of line 18 and $1.27B of line 19, weighted. And not a formula on unrecaptured_section_1250_gain itself: policyengine-core uprates a dataset value only when a variable has no formula, so a formula there would replace uprated 2024 data with zero from 2025.

Invariants

Every existing dataset is unchanged. The datasets fill only the reported inputs; with the new inputs at zero, line 18 is the reported amount plus max(0, −losses) = 0, and line 19 the reported amount plus max(0, 0 − line 17) = 0, so every downstream amount is the same value (bit for bit, except that a stored −0 would read as +0). The default dataset has none of the new inputs (checked from the h5). The microsimulation below must show, and shows, zero differences.

Executed as Hypothesis properties (policyengine_us/tests/test_capital_gain_rate_group_netting.py) for random batches of single and joint returns, each entering one family. Properties 1 to 3 are for returns entering amounts before netting:

  1. Bounds: 0 ≤ line 18 ≤ the gains before netting (if positive); 0 ≤ line 19 ≤ the gain before losses.
  2. Conservation: line 18 + line 19 = max(0, gains + gain before losses − losses). Losses absorb the 28 percent rate gain first, then unrecaptured section 1250 gain, and nothing else.
  3. Order: losses reach line 19 only when line 18 is zero.
  4. Pass-through: reported lines 18 and 19 are unchanged whatever the losses; amounts before netting are unchanged without losses.
  5. Monotonicity: more short-term loss or carryover never raises line 18 or 19; more collectibles gain never lowers either; more section 1250 gain never lowers line 19 or changes line 18.
  6. Netting is on the return: moving amounts between spouses changes nothing.
  7. Identities: adjusted net capital gain = max(0, net capital gain − qualified dividends − lines 18 − 19) + qualified dividends (26 U.S.C. 1(h)(3); the test households have no dividends); worksheet line 13 = line 10 − min(line 9, line 18 + line 19).
  8. Results do not depend on batch order.

Differential: an independent line-by-line transcription of both 2025 worksheets, and of Form 2555 modifications 1 to 4, must equal capital_gains_28_percent_rate_gain, schedule_d_unrecaptured_section_1250_gain, section_911_28_percent_rate_gain, section_911_unrecaptured_section_1250_gain, and the worksheet helper's excess and lines 13 and 19 (the test builds the helper's taxable base and expected excess itself).

Mutation checks, each failing the tests: no short-term netting; no 1250 netting; reported amounts netted again; adjusted_net_capital_gain, dwks13, section_911_unrecaptured_section_1250_gain or the worksheet helper reading the reported input; the helper reporting no excess; the helper's line 13 skipping modification 3; the line 18 shortcut inverted (caught by YAML).

Tests

  • New YAML: capital_gains_28_percent_rate_gain.yaml (13 cases), schedule_d_unrecaptured_section_1250_gain.yaml (12), and five cases in capital_gains_tax.yaml worked by hand through the 2025 Schedule D Tax Worksheet (one for 2026). Two cases pin the pass-through: default-dataset tax unit 1053056 (2025), and reported lines 18 and 19 of 2,000 and 20,000 beside an 8,000 short-term loss.
  • Before (main) / after (branch): against main ea79c39fb7, 30 of the 36 cases in those three files fail and the 6 existing ones pass; on the branch all 36 pass. On main the before-netting inputs and Schedule D line 19 variable do not exist; entered through main's only inputs, the same amounts are never netted (the 28 percent rate gain stays 10,000 instead of 2,000, adjusted net capital gain 24,000 instead of 30,000, the gains tax 17,000 instead of 13,250). The property file fails on main for the same reason.
  • Worked examples, single filer in Texas, 2025, taxed at the rate schedule; "before" is the same amounts entered through the reported inputs, which are not netted: $300,000 wages, 50,000 long-term gain including 20,000 collectibles gain, 10,000 short-term loss: gains tax 8,600 → 7,300. $100,000 wages, 50,000 long-term gain including 10,000 collectibles gain, 8,000 short-term loss: tax 20,449 → 19,889. $100,000 wages, 50,000 long-term gain including 20,000 section 1250 gain, 6,000 short-term loss: 21,467 → 21,029. $300,000 wages, 100,000 long-term gain including 30,000 collectibles and 40,000 section 1250 gain, 35,000 short-term loss: gains tax 17,000 → 13,250.
  • Updated: test_section_911_tax_stacking.py compares the section 911 amounts with Schedule D line 19 (schedule_d_unrecaptured_section_1250_gain); test_uprating_series.py lists the new inputs.
  • Suites run, one process at a time, all passing: federal capital_gains (79), alternative_minimum_tax (88), before_credits (7), foreign_earned_income_exclusion (43) and the loose federal income files (31); contrib additional_tax_bracket (18), biden/budget_2025 (1), harris/capital_gains (5); Massachusetts income tax (116, unchanged); and the Python tests that touch these variables or all inputs (379, at this head: the new property file, Form 6251 Part III, section 911 stacking, the Form 4952 tests, uprating series, input-variable definitions, per-capita uprating, aggregate list integrity, code health).

Impact

Default dataset (populace_us_2024.h5@populace-us-2024-spm-20260909), this PR's base main ea79c39fb7 against its head f77ccfea40, 2025 and 2026, with the #9792 measurement scripts (measure.py, microsim_diff.py):

2025 2026
tax units (weighted) 79,729 (164.2M) 79,729 (165.4M)
units with 28% rate or unrecaptured 1250 gain (weighted) 784 (1.83M) 784 (1.84M)
tax units with any saved output changed 0 0
weighted income tax, main = branch $2,415.75B $2,589.50B
weighted AMT, main = branch $5.38B $10.31B

Saved and compared bit for bit for every tax unit: taxable_income, has_qdiv_or_ltcg, net_capital_gain, adjusted_net_capital_gain, unrecaptured_section_1250_gain, capital_gains_28_percent_rate_gain, dwks10, dwks13, dwks14, dwks19, capital_gains_excluded_from_taxable_income, income_tax_main_rates, capital_gains_tax, regular_tax_before_credits, amt_income_less_exemptions, amt_part_iii_required, amt_base_tax, amt_tax_including_cg, alternative_minimum_tax, income_tax_before_credits, income_tax, state_income_tax, and household household_net_income; all equal. On the branch, schedule_d_unrecaptured_section_1250_gain equals unrecaptured_section_1250_gain bit for bit for every unit. This is the invariant above: the default dataset fills only the reported inputs. The change affects households that enter the new before-netting inputs (household calculations, the API, and any future dataset that carries those components).

Axiom

axiom: 26 U.S.C. 1(h)(4), 1(h)(6)(A) — TheAxiomFoundation/rulespec-us#1499 queued (pe-parity; the signed encoder is the only path, and a billed dispatch is Max's approval)

CI cost

The new Python file runs in the remaining group. Measured locally at this head (macOS): 3 tests, 1.26 s of test calls and 4.5 s for the file with collection, after the import and system build the group already pays (18.4 s wall for the process); peak RSS 1.13 GB. No Linux CI measurement yet; the group's timing artifact will show it.

🤖 Generated with Claude Code

… gain

26 U.S.C. 1(h)(4) and 1(h)(6)(A) net collectibles loss, the net short-term
capital loss and the long-term capital loss carryover against collectibles
gain and section 1202 gain, and what they do not absorb against unrecaptured
section 1250 gain (2025 28% Rate Gain Worksheet and Unrecaptured Section 1250
Gain Worksheet). The model took only Schedule D lines 18 and 19, already
netted, as the microdata carry them from the PUF.

Add inputs for the amounts before netting (collectibles_gain_or_loss,
section_1202_gain, unrecaptured_section_1250_gain_before_losses,
long_term_capital_loss_carryover) and net them in
capital_gains_28_percent_rate_gain and the new
schedule_d_unrecaptured_section_1250_gain, which the section 1(h), Schedule D
Tax Worksheet, section 911 and Form 6251 Part III formulas read. The existing
inputs keep their meaning and pass through, so no existing dataset changes.

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

Copy link
Copy Markdown
Contributor Author

Hand-off to the US + core hub (from session 14937118, hub-dwks-netting).

  • Head: f77ccfea40 (one commit on main ea79c39fb7).
  • Independent review: GPT-6.1 Sol, five rounds; APPROVE at f77ccfea40 (r5).
    • r1 blocked the first design, which double-netted PUF-based datasets. That's why the existing inputs stay reported Schedule D lines 18/19 and four new before-netting inputs carry the netting.
    • r2 led to leaving Massachusetts unchanged.
    • r3 and r4 corrected description claims.
    • Reports: ~/reviews/us-hub/dwks-netting/review-r1.md … review-r5.md.
  • Passed locally at this head:
    • YAML, before/after on main: 30 of 36 fail on main, 36 pass here.
    • Hypothesis property and differential tests; 10 mutations, all caught.
    • The affected YAML folders and Python groups.
    • Default-dataset microsimulation, ea79c39fb7 vs f77ccfea40, 2025 and 2026: 0 of 79,729 tax units changed on any saved output, bit for bit.
  • Pending: CI (16 passed, 19 running at hand-off, none failed); merge order.
  • Depends on: the Schedule D Tax Worksheet regular-tax fix (branch fix-dwks-regular-tax-lines), which lands first by the hub's order. If it lands first, test_section_911_tax_stacking.py may need a trivial rebase. No other overlap: its differential test takes lines 18 and 19 as entered, which this PR keeps.
  • Axiom: Encode IRC §1(h)(4) and §1(h)(6)(A): derive 28-percent rate gain and unrecaptured section 1250 gain by netting losses (PE #9841 parity) TheAxiomFoundation/rulespec-us#1499 is queued. Decision d996 asks Max to approve the billed signed encode; it does not block this merge.
  • Follow-ups: Massachusetts' long-term collectibles treatment (Part A placement and §2(c)(2)–(3) loss ordering) is a separate task.
  • Build report: ~/reviews/us-hub/dwks-netting/build-report.md.

@MaxGhenis
MaxGhenis merged commit d3978df into main Oct 6, 2026
35 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged by the US + core hub on its merge gates. Audit:

  • Head: f77ccfea40, handed off by the netting session (14937118).
  • Independent review: GPT-6.1 Sol, rounds r1 to r5. r5 APPROVES this head (~/reviews/us-hub/dwks-netting/review-r5.md). r1 blocked a design that would have double-netted PUF-based data. So the existing inputs keep their reported Schedule D lines 18 and 19, and four new before-netting inputs carry the §1(h)(4)(B) and (h)(6) netting.
  • Tests: 30 of 36 YAML cases fail on main and all 36 pass here. The property and differential tests pass, and all 10 mutations are caught.
  • Impact: default dataset, 2025 and 2026: 0 of 79,729 tax units change, bit for bit, because the dataset has none of the new inputs. Households that enter them get the statutory netting.
  • Order: this lands before the Schedule D Tax Worksheet regular-tax PR, which is still being built and will take a trivial rebase of test_section_911_tax_stacking.py. d996, the Axiom encode, doesn't block this merge.

@MaxGhenis
MaxGhenis deleted the fix-dwks-28-1250-netting branch October 6, 2026 08:29
MaxGhenis added a commit that referenced this pull request Oct 6, 2026
Brings in #9841 (28 percent rate gain and unrecaptured section 1250 gain
netted against losses), #9801, #9790, #9779, #9768, #9741 and #9630. Only
test_section_911_tax_stacking.py changed on both sides, in different
functions, and git merged it without conflict. #9841 passes Schedule D
lines 18 and 19 entered already netted through unchanged, and this
branch's capital_gains_tax, reforms and tests read the section 911
amounts and Schedule D inputs that #9841 keeps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 6, 2026
Delta review r3 (Sol, 2ea9d6b): #9841 added long_term_capital_loss_carryover,
a memo amount that long_term_capital_gains already includes as a loss
(Schedule D line 15). ITR 12-1 item (7) bars a prior-year carryover from
reducing the year's gains for household income, so line D adds the
carryover back before the $1,500 member limit. Federal AGI keeps it.

Tests: three YAML cases (a carryover netting a gain, a carryover making the
whole net loss, a dependent's carryover); the property sample draws
carryovers with long_term_capital_gains net of them and the Form 140PTC
oracle adds them back. All fail on the previous formula (3 YAML, 4 property).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 6, 2026
- 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>
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>
MaxGhenis added a commit that referenced this pull request Oct 9, 2026
* Count capital gains once in Arizona property tax credit income

az_property_tax_credit_income added capital_gains_excluded_from_taxable_income
on top of federal AGI. That variable is the part of federal taxable income
taxed at the capital gains rates; when taxable income is zero it is the whole
net capital gain plus qualified dividends. Federal AGI already holds those
amounts, so they counted twice, mostly for the low-income seniors the credit
is for.

ARS 43-1072(H)(6)(b) adds "the amount of capital gains excluded from adjusted
gross income". A.A.C. R15-2C-502(C)(3), ITR 12-1 item (7) and the 2021-2025
Form 140PTC instructions (Part 1 line D) count each member's net gains and
losses from sales or exchanges of property, which federal AGI holds. The model
has no gain excluded from federal AGI, so the entry is removed.

Adds Form 140PTC line-by-line YAML tests and seeded property tests
(differential against a line A-J reference, counted once, independence from
the preferential-rate amount, credit monotone in gains).

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

* Count dependents' income in Arizona property tax credit income

Review r1b: federal AGI (irs_gross_income) leaves out every tax-unit
dependent's income. The removed preferential-rate amount summed all members'
gains and qualified dividends, so it had been counting a dependent's gains;
without it a claimant whose child had $3,000 of gains got $502 instead of $412.
A.A.C. R15-2C-502(A)(2) and (B) count every household member's income whether
or not the member is a dependent, so az_property_tax_credit_dependent_income
adds dependents' income from the same federal gross income sources, without
Social Security (ARS 43-1072(I)).

Also corrects the zero-taxable-income description: the preferential-rate
amount is then the adjusted net capital gain. Adds dependent YAML cases and
dependents to the sampled property tests.

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

* Apply Arizona's $1,500 member capital loss limit and allow a negative line J

A.A.C. R15-2C-502(C)(3), ITR 12-1 item (7) and the Form 140PTC line D
instructions (2021-2025) limit each household member's net capital loss
to $1,500. az_property_tax_credit_agi used federal AGI's capital gains
and losses instead: non-dependents' net gains less a capital loss limited
to $3,000 per return. It now swaps those for each non-dependent member's
line D amount (new az_property_tax_credit_capital_gains, parameter
capital_loss_limit). Dependents' line D amounts move into
az_property_tax_credit_dependent_income with the same limit, in place of
their gains floored at zero.

The line J note in the instructions lets household income go negative
and uses zero for the Schedule 1 and 2 amounts. az_property_tax_credit_agi
no longer floors at zero; az_property_tax_credit floors income at the
schedule lookup, where a single-amount scale would otherwise return 0
below its first threshold.

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

* Cite the line J note where it appears: 2023-2025 instructions, page 5

The 2021 and 2022 instructions have no negative household income note;
the floor at the schedule lookup applies in every year because the
schedules start at zero.

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

* Combine members' income before any floor in Arizona property tax credit income

Review r2: federal AGI deducts every member's losses, dependents' included,
but az_property_tax_credit_agi floored at zero before dependents' income was
added, so a loss counted only against the claimant's or spouse's own income.
A claimant with no income whose dependent had $3,000 of wages and a $1,000
capital loss got household income of $3,000 instead of $2,000.

az_property_tax_credit_agi is no longer floored. Form 140PTC line J can be
negative, and az_property_tax_credit uses zero for the Schedule 1 and 2
lookup (the same change as in #9770, so that PR rebases cleanly).

Adds regressions for a loss on the dependent, on the claimant, a rental loss
and a negative line J; the property sample now includes dependents' losses,
raises a dependent's gains, and states its actual domain. Notes that the
federal source list is not Arizona's (unemployment by paying state, estate
income, strike benefits, nontaxable alimony).

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

* Swap only the capital amounts federal AGI holds for Arizona line D

Review r1 of #9770 found that az_property_tax_credit_agi added back
limited_capital_loss even when federal AGI never deducted it (a reform that
drops loss_ald from the above-the-line list, or loss_ald set to zero),
manufacturing income. The swap now takes out only the positive capital gains
irs_gross_income puts in AGI (per gross income source list) and the capital
loss deduction loss_ald actually contains, then adds each non-dependent's
line D. Gains a reform leaves out of AGI still count, as ARS 43-1072(H)(6)(b)
adds them back.

Line D now combines capital gain distributions reported without Schedule D
with the member's other gains and losses before the $1,500 limit: they are
long-term capital gains (26 U.S.C. 852(b)(3)(B)), and R15-2C-502(C)(3) nets
each member's capital gains and losses. The dependent loop skips them so they
count once.

Tests: YAML cases for the two reforms, a zero loss_ald input, distributions
for a claimant and a dependent, the three r3 finding-1 households (losses
beyond $1,500 with tax-exempt income), and r3's estate/rental case, now right
on main since #9633. Property sample adds distributions and signed rental
income (dependents too) to the Form 140PTC oracle, uses only non-dependents'
losses in the federal coverage check (#9647), and compares the
preferential-rate mutation with an unmodified run (r1 nit). Corrects the
spouse-netting comment (r1 nit).

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

* Add back only loss_ald's capital part in Arizona household income

Review r1 of the fold (GPT-6.1 Sol, 21cb189) found that
min(limited_capital_loss, loss_ald) cannot tell loss_ald's capital part from
its business part: a reform or supplied loss_ald that holds only a rental
loss was reversed as a capital deduction ($2,500 / $323 instead of the
form's $1,500 / $502).

loss_ald's section 461(l) business part moves, unchanged, into a new
limited_business_loss variable, and loss_ald adds limited_business_loss and
limited_capital_loss (identical federal results). Arizona now adds back
loss_ald less limited_business_loss, clipped to [0, limited_capital_loss].

Tests: a loss_ald case pins both parts; Arizona cases for a rental and
capital loss together and for a supplied rental-only loss_ald; a pytest
with a Reform whose loss_ald holds only rental losses. Both Arizona tests
fail on 21cb189's formula.

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

* Add the dependent IRA household now that #9801 is on main

Delta review r2 asked for the r1 household as a regression once #9801 (keep
dependents' above-the-line deductions off the filer's AGI) was in this
branch. Claimant aged 70 with a 4,000 long-term gain; dependent with 1,600
wages and a 200 traditional IRA contribution: federal AGI 4,000, line J
5,600, no credit (Schedule 2 limit 5,501).

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

* Leave the prior-year long-term carryover out of Arizona line D

Delta review r3 (Sol, 2ea9d6b): #9841 added long_term_capital_loss_carryover,
a memo amount that long_term_capital_gains already includes as a loss
(Schedule D line 15). ITR 12-1 item (7) bars a prior-year carryover from
reducing the year's gains for household income, so line D adds the
carryover back before the $1,500 member limit. Federal AGI keeps it.

Tests: three YAML cases (a carryover netting a gain, a carryover making the
whole net loss, a dependent's carryover); the property sample draws
carryovers with long_term_capital_gains net of them and the Form 140PTC
oracle adds them back. All fail on the previous formula (3 YAML, 4 property).

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

* Cover dependent Arizona capital-gain changes (#9762)

Preserve all 80 original sampled households and their independent line-D
oracle. Add dependent gain and loss perturbations for the 26 households
with dependents in the same simulations, preserving member loss floors
and filer/dependent accounting.

Use the educator deduction variable introduced on main in the test
that removes loss_ald from the federal deduction list. Expected outputs
and public carryover inputs remain unchanged.

* Clarify Arizona capital input convention and consolidate release notes

* Test bounded whole-dollar parity of federal loss extraction

* Test bounded whole-dollar parity of federal loss extraction

* Pin d1107 terminating-trust carryover treatment for Arizona credit

---------

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