Repository navigation
Conversation
…in Montana elderly credit income Gross household income is federal AGI "without regard to loss" (MCA 15-30-2337(9)(a)); 2024 Schedule 2EC line 7 says "do not include any capital losses". The loss add-back restores only loss_ald, which holds the capital loss deducted in AGI. A filer's short-term loss netted against their own long-term gain never reaches it, so a member on their own return with a $10,000 long-term gain and a $4,000 short-term loss counted $6,000; as a dependent the same person counted $10,000. Restore the netted loss for everyone who is not a tax unit dependent, as dependent_gross_income does. The untaxed Social Security add-back subtracted both taxable_social_security and dependent_taxable_social_security. A person input as a dependent who is also the head (every adult in the unit input as a dependent) has neither counted, so part of their benefits dropped out. Subtract only the taxable part that irs_gross_income or dependent_gross_income actually counted. Review findings S1 (DTrim99) and P2 (GPT-6.1 Sol) on #9882, whose changes landed in #9915. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…apping roles Four cases fail on main (a filer's and a claimant's netted capital loss, Social Security for a person input as both dependent and head, and the credit-level netting case); five guard behavior main already has (the dependent gate for a minor alone in a tax unit, a business loss on another member's return, cross-spouse netting on a joint return, and a dependent in another member's tax unit). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 12, 2026
… elderly credit income long_term_capital_gains already includes the prior-year long-term capital loss carryover as a loss (Schedule D line 15; long_term_capital_loss_carryover is a memo). A carryover is a loss, so it must not reduce gross household income (MCA 15-30-2337(9)(a); 2024 Schedule 2EC line 7, "do not include any capital losses"). Add it back to get the year's own long-term gain, as az_property_tax_credit_capital_gains does, and restore only the gain it hid, on both income paths. Restoration applies where an income path counts the person, so a person input as both a dependent and the head stays excluded from both, as before. New cases: a carryover smaller than, larger than and equal to the year's gain; a dependent's carryover; a long-term loss netted against a short-term gain; losses exceeding the gain; and Social Security for a spouse also input as a dependent. Review finding P2 (GPT-6.1 Sol) on #10139. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… shows; add capital gains property tests When capital_gains is supplied directly as a net amount, the long-term and short-term parts default to zero, so adding the carryover to the long-term part invented a gain: a direct -5,000 net with a 5,000 carryover counted 5,000 (review round 2 on #10139). Compute gains without losses as the year's net, max(0, capital_gains + carryover), plus the netting between the year's long-term and short-term amounts, max(0, a) + max(0, b) - max(0, a + b). With parts supplied this is the floored parts; with a direct net it is the net alone. test_mt_elderly_credit_capital_gains.py checks, for random long-term and short-term amounts or a direct net, a carryover and distributions, that a household member's gains count without losses whether they are a dependent, file their own return or are the claimant, against a reference written from Schedule 2EC line 7, and that the credit is the same either way. It is derandomized (20 examples, 11 s of test time locally); a 300-example random local run passed, and it fails on main and on the previous head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gains; test every sign region in one simulation Once capital_gains is an input for anyone in a simulation, everyone without one holds its default of zero, not the sum of their parts. The previous identity started from capital_gains, so a dependent with only a 10,000 long-term gain, beside a claimant whose capital_gains was supplied as 0, counted nothing (review round 3 on #10139). The parts now decide the gains whenever either is nonzero, max(0, long-term + carryover) + max(0, short-term); without parts, capital_gains is a net supplied directly and counts as max(0, net + carryover). The restoration replaces whatever the income path counted, so an inconsistent capital_gains input yields to the parts. test_mt_elderly_credit_capital_gains.py now builds one simulation from a grid covering every sign region of the long-term amount plus carryover, the short-term amount and a direct net, with and without distributions, in three input styles (parts with their net, parts with the net left to default, a net alone) and three placements (dependent, own return, claimant). It replaces 20 Hypothesis-built simulations: 3.1 s of test time locally, peak footprint 1.25 GB against 1.24 GB for importing the model and building a one-person simulation, so about 8 MB for the test itself. It fails on main and on the previous two heads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
October 12, 2026 12:53
Contributor
Author
|
Hand-off to the US + core hub. Head
Artifacts: |
This branch has not been deployed
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
This PR fixes two gaps in Montana's elderly homeowner/renter credit gross household income, both found in the reviews of #9882. #9882's changes landed on main in #9915, and this PR fixes what remained.
loss_ald, which holds only the capital loss deducted in AGI. A short-term loss netted against the same person's long-term gain never reachesloss_ald. So a household member on their own return with a $10,000 long-term gain and a $4,000 short-term loss counted $6,000, but $10,000 as a dependent (dependent_gross_incomecounts gains without losses). The claimant's own return had the same gap.long_term_capital_gainsalready includeslong_term_capital_loss_carryoveras a loss, as Schedule D line 15 does. A $10,000 gain this year with a $4,000 carryover counted $6,000, on both the filer and the dependent path.max(0, LTCG + carryover) + max(0, STCG). Without parts,capital_gainsis a net amount supplied directly, and the gain ismax(0, net + carryover).capital_gainscan disagree with them. Once it is an input for anyone in a simulation, everyone without one holds its default of zero, not the sum of their parts (review round 3).az_property_tax_credit_capital_gains.irs_gross_incomefloors the net;dependent_gross_incomefloors each part) with these gains. Only the gain a loss hid comes back, and an unused loss never counts as income.loss_ald, so it is not counted twice.head_or_spouse_candidateskeeps the adults, so one becomes the head while staying a dependent. Then neitherirs_gross_income(people who are not dependents) nordependent_gross_income(people who are not head or spouse) counts their taxable Social Security.taxable_social_security + dependent_taxable_social_security. In the test case that left $57,500 of $60,000, against §2337(9)(a)(viii), which counts "all payments received under federal social security".The trailing comment in
gross_income_sources.yamlnow describes the three items the formula adds outside the list.Example (2024 Schedule 2EC)
The claimant is 70, with a $20,000 pension and $2,000 of property tax billed. Their 30-year-old household member files their own return and has a $10,000 long-term gain and a $4,000 short-term loss.
Tests
24 new YAML cases, appended to the existing files. 13 fail on main and pass here; I reverted the formula in place and confirmed the revert before each run.
[20_000, 10_000][20_000, 6_000][20_000, 60_000][20_000, 57_500][870, 0][670, 0][20_000, 10_000][20_000, 6_000][20_000, 60_000, 60_000][20_000, 34_500, 34_500]11 cases pass on main and guard behavior that a future change could break:
capital_gainsis supplied (so the dependent's defaults to 0):[20_000, 10_000], and a credit of 1,130. The previous head of this PR gave[20_000, 0]and 1,150.[20_000, 10_000]) and at the credit level (1,130). The previous head of this PR gave 35,000 and 352.is_tax_unit_dependent: false, at the gross household income level ([20_000, 10_000]) and the credit level (1,130). DTrim99's S2 asked for this; only the randomized property test reached it before. Counting the minor twice would give a credit of 189.[15_000, 35_502.81, 0, 3_000].Every expectation is worked line by line in the YAML comments.
Invariant test.
policyengine_us/tests/test_mt_elderly_credit_capital_gains.pyis a new file.remaininggroup. In run 38184073570 that group took 28:32.67 end to end (26:25 JUnit time) for 2,248 tests, and the round-3 review read a 13.96 GiB peak from that run's resource report.test_mt_elderly_credit_household_members.py, so this file stays separate.Local runs:
ca9c11bc41, every file in the elderly credit test folder passes (81/81), and so dotest_mt_elderly_credit_household_members.py(2/2) and the new invariant test (3/3).The heavy-lock sweep at
88e09fef0dpasses: the wholemt/folder (664 cases),contrib/states/mt(75) and the state rollupsgov/states/tax/incomeplus two other Montana tax files (118).Invariants
Not changed
Householdentity stays the proxy.derandomize=Trueand short-term gain draws intest_mt_elderly_credit_household_members.pyare requested on Limit the Montana elderly homeowner/renter credit to one claimant per household (MCA 15-30-2341(1)) #9900, which is rewriting that file. The credit's §2340/§2338 citations are requested there too.axiom: TheAxiomFoundation/rulespec-us#1512 queued (output 6 and its addendum cover gains without losses and all Social Security once; companion cases added in this comment)
🤖 Generated with Claude Code
Hub microsimulation impact (current head)
A real microsimulation on the default dataset, main at the merge base
de3815f4ccagainst this PR's headc6ee13d99a, for 2024 and 2026. The runs went one at a time under the shared heavy-job lock. Sums are weighted.mt_elderly_homeowner_or_renter_creditmt_elderly_homeowner_or_renter_credit_gross_household_incomemt_income_taxstate_income_taxincome_taxhousehold_net_incomehousehold_benefitsRe-measured after the main merge with #9900's one-claimant rule. No record in the default dataset changes in either year, including the credit's gross household income.
Comparison files are in
fixes/10139-impact/on the hub host.