Repository navigation
Count capital gains once in Arizona property tax credit income - #9762
Conversation
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>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9762 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 4 5 +1
Lines 76 93 +17
Branches 2 5 +3
=========================================
+ Hits 76 93 +17
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:
|
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>
… 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>
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>
…it 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>
|
#9762 fails tests when merged with current main. While checking #9779 (Schedule 2 thresholds) against this PR, I found that this head (7491794) merged with current main (6b0e773) fails:
I bisected this to #9647 ("Keep dependents' losses off the filer's AGI", 4e78791). This head merged with 4e78791^ passes 16/16 and 3/3; merged with 4e78791 it fails as above. #9779 itself doesn't touch these files. #9770's head (0450a28) merged with #9779 passes all 651 Arizona YAML tests and both property test files. |
…ains fix Folds az-ptc-line-d-loss-limit (0450a28) into fix-az-ptc-capital-gains. Conflicts resolved as in the #9762 session's staged merge: #9770's income_sources comment, #9770's AGI capital-component swap, both sides' YAML cases and property tests, and dependents' sources added with their sign now that #9647 keeps dependents' losses out of loss_ald. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
… credit fix #9788 adds capital_losses_allowed_against_gains to loss_ald: federal AGI now nets a return's capital losses against its gains, distributions included, before the $3,000 limit. Resolution and follow-through: - loss_ald adds limited_business_loss (unchanged 461(l) body, identical to main's), capital_losses_allowed_against_gains and limited_capital_loss, with main's label and 1211(b) reference. - Arizona adds back loss_ald less limited_business_loss, clipped to the two capital parts, so line D still replaces every capital amount in AGI. - Two YAML comments and one expected federal AGI follow #9788's netting (distributions case: 1,000, not 2,000); Arizona expectations unchanged. - Property test's federal coverage helper follows the new netting. Delta review r2 (Sol) fixes in the same commit: the reform test applies its Reform to an existing Simulation (sim.apply_reform) instead of rebuilding the country model (78 s call phase), and its loss_ald builds on limited_business_loss; the add-back comment states the contract for a replacement loss_ald. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
Preserve the folded #9770 loss-limit work and current federal loss tests. The merge is conflict-free; existing carryover input semantics remain unchanged.
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.
Preserve the verified dependent mutation coverage and folded #9770. Include main's supplied-role handling and California/New York changes without conflicts or policy changes in the repair.
|
US + core hub merge audit, us#9762 at
|
Arizona Form 140PTC household income now counts capital gains and qualified dividends once, includes dependents' signed income, applies the $1,500 capital loss limit separately to each member, and uses zero when looking up the credit schedules for negative household income. #9770 is folded into this PR. The PR remains draft.
Methodology ruling: terminating estates and trusts
Max's 2026-10-09 ruling d1107 resolves the sole P2: keep as carryover. A terminating trust's loss passed to a beneficiary through Form 1041 K-1 box 11 code D remains in
long_term_capital_loss_carryoverand is added back when calculating Arizona line D. Reg. 1.642(h)-1(a) transfers the excess as a capital loss carryover; no cited Arizona source provides a different treatment. This round records the ruling and pins the existing calculation without changing model formulas.Form 1041 instructions, box 11 codes C/D use the carryover classification. Arizona ITR 12-1, items (5) and (7) counts current-year K-1 income and excludes prior-year capital losses. R15-2C-502(C)(3) and the 140PTC line D instructions do not expressly distinguish terminating-trust carryovers from a beneficiary's own carryovers.
The ruled regression represents a 70-year-old Arizona renter paying $5,000 rent, with $4,000 personal gains and a $3,000 terminating-trust loss already netted into federal long-term gains of $1,000. The $3,000 memo is added back: line D and household income are $4,000, and the credit is $0. The previous review's alternate $1,000-income/$502-credit expectation is replaced with this ruled contract, with a comment citing Reg. 1.642(h)-1(a) and d1107. No deliberately failing or xfailed alternate remains.
Separate follow-up, tracked in #10021: split
long_term_capital_loss_carryoverinto own-carryover and trust-passthrough leaves. The current memo cannot distinguish those origins. That input refinement is outside this ruling round and does not alter the carryover treatment adopted here.Design and sources
capital_gains,non_sch_d_capital_gainsand the positivelong_term_capital_loss_carryovermemo, then floors the result at minus the member's $1,500 limit. Long-term inputs already net the memo. Capital gain distributions are combined with sale gains/losses by inference from 26 USC 852(b)(3)(B).loss_ald - limited_business_lossbetween zero and the two capital deduction components. Reform guards remain intact.max(income, 0)as the line J instructions require.limited_business_lossfrom federalloss_ald, which then adds that component and its two capital components. The d1107 round does not change these formulas.Delta review P3 work and remaining precision limitation
The previous repair consolidated the two release fragments into one, preserving the capital loss limit, dependent income/loss and negative-income release notes. It also documented the Arizona input convention: short-term amounts contain the current year's net sale gains/losses and exclude Schedule D line 6 carryovers. The form includes those carryovers in line 7; that net amount cannot be supplied unchanged for Arizona. No short-term carryover memo exists; adding one remains outside this PR.
The federal extraction differential uses production variable classes in one minimal system and fresh vectorized simulations for 2021, 2025 and 2026. An independent sections 461(l)/1211(b) reference casts the complete deduction once, as in the unextracted main formula after #9788. Each year covers 120 seeded units and 15 all-status threshold cases, including dependents and opposite-signed capital sources. Exact whole-dollar parity is explicitly bounded to every intermediate total below
2**24.Federal precision P3 remains open: the extraction affects federal AGI and does not guarantee universal whole-dollar or fractional-dollar parity. Above float32's exact-integer range, sequential component storage/addition can produce dollar differences. Business loss $3, capital losses $16,777,218 and offsetting distributions $16,777,216 produce a once-cast unextracted-main reference result of $16,777,220 and an extracted result of $16,777,222. This comparison uses the main formula after #9788, rather than the earlier PR predecessor that lacked its against-gains component. Another example with business losses totaling $16,777,219 shows why changing only the addition dtype cannot restore universal parity. A wider redesign remains open; the bounded differential does not establish parity outside its stated domain.
Validation
This d1107 round
All nine requested single-file foreground processes exited successfully at
3603ddc030e5d0bae632930ade0f1a28fd7150b6: 224 YAML cases and 10 Python cases passed. The federal differential covers 405 tax units across 2021, 2025 and 2026.policyengine_us/tests/core/test_loss_ald_extraction_parity.pypolicyengine_us/tests/policy/baseline/gov/states/az/tax/income/credits/az_property_tax_credit_income.yamlpolicyengine_us/tests/test_az_property_tax_credit_income.pypolicyengine_us/tests/policy/baseline/gov/states/az/tax/income/credits/az_property_tax_credit_capital_gains.yamlpolicyengine_us/tests/policy/baseline/gov/states/az/tax/income/az_property_tax_credit_agi.yamlpolicyengine_us/tests/policy/baseline/gov/states/az/tax/income/credits/az_property_tax_credit.yamlpolicyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/loss_ald.yamlpolicyengine_us/tests/policy/baseline/gov/states/az/tax/income/credits/az_property_tax_credit_eligible.yamlpolicyengine_us/tests/policy/baseline/gov/states/az/tax/income/credits/az_property_tax_credit_schedules.yamlmake formatpassed before commit3603ddc030e5d0bae632930ade0f1a28fd7150b6: 7,039 files unchanged and Ruff checks passed. Formatting used Python 3.13 with--no-sync, despite the.python-version3.14 warning. Git whitespace checks passed for both the committed change fromc6ad076aaca4507ba288071155295ffbffb44d51and the staged diff.Current verification environment: macOS, the user-provided Python 3.13.9 interpreter, policyengine-core 3.32.15 and pytest 9.1.1.
Current-source provenance: the untracked source-read cache serves the committed Git archive at
3603ddc030e5d0bae632930ade0f1a28fd7150b6(SHA2566a07b309a859513efaef88a505fb476b9204f31ac1f577909bfc2c12291e5b45) without altering model source or calculations. The first two processes used the verified five-package dependency cache. The remaining seven used its verified 44-package extension, containing 10,355 cached entries. Cached wheel bytes were checked against installed RECORD hashes; three entries with different RECORD hashes were omitted from the extension and were not overridden. This does not claim fresh byte comparisons against every installed file. Installed dependency files and native extensions were unchanged.Each test file ran separately in the foreground. No new microsimulation, full-suite result, CI pass, or performance benchmark is claimed.
Each YAML file is invoked separately with
python -m policyengine_core.scripts.policyengine_command test <file> -c policyengine_us; each Python file is invoked separately withpython -m pytest -q <file>. This round runs every PR-changed test file and the Arizona property tax credit YAMLs. No folder suite, full suite or new microsimulation is run. Existing Arizona property/differential coverage is preserved. No partner contract test is edited.Previous repair at c6ad076
The preceding round reported 108 YAML cases and 10 Python cases passing, plus two upper-range precision evidence cases. These are previous results, not new d1107 verification:
make formatpassed before each change commit; Git whitespace checks passedThe federal differential passed against unchanged production calculations at
57eceac99d6fb0561daad75638a341c30e868b76; adding that test was the only tree difference fromc6ad076aaca4507ba288071155295ffbffb44d51. Its source matched the committed test byte-for-byte (SHA2569cffe62437b81e7cb119f74c9cb02d5f31fd8dc7b85d3bdc8eeb708979d00f6a). Remaining preceding-round verification used the final-head source archive (SHA256c2059444156c9dad955d75babbd3904823477c45ceba7a4e371e537fa8764568). The original Arizona property module was preserved byte-for-byte (SHA25693391bf1641b21c78d99f85f4246fb61dd54a2ffd1094e74281b8726216e543f).The preceding environment was macOS, Python 3.13.9 and policyengine-core 3.32.15. Stalled filesystem reads required an untracked source-read facade serving the exact committed Git archive with matching directory inventories and frozen source introspection. A dependency cache served pinned wheel bytes matching all 6,181 installed RECORD hashes, with zero mismatches; that does not claim fresh byte comparisons against every installed file. It changed source delivery, not calculations. Later process starts reused compiled code for immutable archived source while executing fresh module globals and classes, and disabled pytest disk-cache bookkeeping. Interrupted imports and a diagnostic-timeout crash were infrastructure evidence, not policy test passes or failures. The historical terminal-trust assertion completed after those startup problems were resolved.
Previous local test-cost measurements included setup and source-cache initialization. Collection of the new federal module took 32.51 seconds, with peak RSS 1,279,049,728 bytes; executing its three minimal-system cases took 60.55 seconds, with peak RSS 1,287,880,704 bytes. This is a collection-versus-execution comparison, not a CI-group benchmark or reliable estimate of incremental CI cost. The original Arizona property module took 67.29 seconds, with peak RSS 1,446,739,968 bytes. The income YAML's 37 assertions took 356.64 pytest seconds, 1,081.05 full-process seconds and 817.71 facade seconds, with peak RSS 5,913,198,592 bytes. The capital-gains YAML's six assertions took 37.87 pytest seconds, 219.11 full-process seconds and 201.79 facade seconds, with peak RSS 2,449,096,704 bytes. Facade timing started before cache initialization and stopped during atexit, so it did not measure the full process lifetime. Different cache settings prevent inference of incremental test cost. These isolated macOS measurements do not establish Linux CI group memory or timing. The new module routes to the existing rest-python core group, constructs one minimal read-only system and uses fresh simulations per year; no CI jobs or runner budgets change.
Invariants
The existing seeded Arizona population and every original property assertion remain unchanged. Arizona comparisons allow the original numerical tolerances; the bounded federal differential requires exact array equality:
2**24, with dependent exclusions, filing-status limits and source offsets preserved. It does not claim parity outside that domain.Previously measured hub microsimulation impact
The hub ran a real microsimulation on the default dataset comparing main at merge base
7b956eb4014e3a189075c79f9b1f0a8f1d3b02abwith PR headc6ad076aaca4507ba288071155295ffbffb44d51, for 2025 and 2026. Runs proceeded one at a time under the shared heavy-job lock. Sums are weighted. These are measurements of those exact heads; no new microsimulation is run in the d1107 round, which changes tests and documentation without changing model formulas.az_property_tax_creditaz_income_taxstate_income_taxincome_taxhousehold_net_incomehousehold_benefitsHub comparison artifacts are retained separately. These zero changes do not establish universal float32 parity or exercise supplied terminating-trust K-1 losses. This round does not obtain a new partner-output comparison, full CI result or Linux CI performance measurement.
Earlier author-reported microsimulations compared branch
2ea9d6bcedwith maind3978dfc31usingpopulace_us_2024.h5@populace-us-2024-spm-20260909, policyengine-core 3.32.16:Those earlier results describe their stated historical heads, separately from the subsequent hub comparison above. The reported earlier sample contained no capital losses, and a later carryover audit found no carryover column in its examined cached snapshots. Neither audit establishes general carryover equivalence or tests supplied terminating-trust K-1 losses.
Remaining scope and review status
The terminal-trust P2 is resolved by d1107. Splitting the carryover memo into own-carryover and trust-passthrough leaves is tracked separately in #10021; the federal float32 precision P3 remains open and disclosed above. Prior repaired findings and coverage for #9647, #9779, #9788, #9801, #9841 and #9633 remain in the branch. This round does not merge main or resolve unrelated core #570/#572, #9859 d1009 or #9621 partner-gate holds. No independent approval or green-CI claim is made.
Existing limitations remain: unemployment has no paying-state input; nontaxable strike benefits and federally nontaxable alimony are omitted; dependent above-the-line deductions are not subtracted; members outside the tax unit are not combined.
axiom: us-az:statutes/43-1072 household income (H)(4)-(6), (I) TheAxiomFoundation/rulespec-us#1483 queued (existing companion tests A-M; d1107 adopted in this round).