Skip to content

Fix Montana disability exclusion repeal, elderly credit receipt timing and occupancy tests - #10331

Open
MaxGhenis wants to merge 2 commits into
mainfrom
statute-bugs-mt-disability-ehrc-elderly
Open

MaxGhenis wants to merge 2 commits into
mainfrom
statute-bugs-mt-disability-ehrc-elderly

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Statute-first fixes for three verified Montana model bugs. Plan: failing YAML tests first, then the fix, sources cited in parameter and variable metadata; run the affected test files one per process; the hub runs the impact (no microsimulation here). Local test results are under Tests.

axiom: TheAxiomFoundation/rulespec-us#1741 queued, extended with a comment (2024 repeal controls; historical corpus ingestion and re-pin); TheAxiomFoundation/rulespec-us#1864 queued (receipt timing; ARM corpus ingestion and re-pin); TheAxiomFoundation/rulespec-us#1512 queued, extended with a comment (residence and occupancy companions; historical sources, table restoration and re-pin).

1. us-mt-disability-exclusion-after-repeal (2024+): fixed

  • Source. 2021 Mont. Laws ch. 503 (SB 399), section 65 repeals 15-30-2110, MCA, the section that held the disability income exclusion (session laws vol. III, PDF p. 68). Section 70(1) makes the act apply to "income tax years beginning after December 31, 2023"; section 65 is not among the earlier-effective sections in 70(2) (PDF p. 70). The 2024 Form 2 instructions, p. 5 list the "partial retirement disability deduction for taxpayers under age 65" among repealed deductions.
  • Change. mt_disability_income_exclusion_eligible_person and mt_disability_income_exclusion_person get formula_2024 returning false and 0 (the person formula too, so an eligibility input cannot restore it). The 2024 and 2025 entries of subtractions.yaml drop mt_disability_income_exclusion_person. Historical formulas, including Count taxable employment disability benefits in federal gross income (IRC 105(a)) #10185's taxable-benefit base, are unchanged.
  • Witness. A 60-year-old retired on total disability with $5,200 of disability benefits: 2023 exclusion $5,200 (unchanged); 2024 and 2025 exclusion $0 and mt_subtractions $0 (main: $5,200). At 5.9% that is up to $306.80 of 2024 tax per affected filer.
  • Years. 2024 onward.

2. us-mt-ehrc-gross-household-income-omissions (receipt timing 2017+): fixed in part; the 2009-2016 inclusion is left as is

  • Source. MCA 15-30-2337(4): gross household income is "all income received by all individuals of a household" (current). ARM 42.4.301(2)(b) (from 11/10/2017) counts "federal refundable tax credits received"; the 2023 instructions, line 7 say "Combine all the refundable credits received by the members of the household in 2023".

  • Change (receipt timing). mt_elderly_homeowner_or_renter_credit_federal_refundable_credits is now an actual-receipt input (federal refundable credit cash the person received during the year, default 0), like the existing mt_elderly_homeowner_or_renter_credit_received and ..._property_tax_rebate_received inputs. The formula that put the current return's income_tax_refundable_credits on the head is removed: those credits are paid after the year ends. Household summation counts each supplied receipt once.

  • Left as is: federal refundable credits before 2017. The spec asked to add the variable to the 2009 source list, deduced from 15-30-2337(9)(a)'s "all nontaxable income"; it noted that no pre-2017 ARM text could be fetched. I fetched it: ARM 42.4.301(2)(b) as in effect 8/20/2004 to 11/9/2017 "further defined" gross household income to include "federal refunds received during the tax year to the extent that the amount recovered reduced the claimant's Montana income tax in a prior year" (rules.mt.gov). The 2016 Form 2EC instructions list "Federal income tax refunds taxable in Montana" and no refundable credit. Two readings are defensible:

    • (A) A refundable credit is "nontaxable income" under (9)(a) from 2009, and the old ARM item reaches only recoveries of tax paid. That would count refundable credits received from 2009, as the spec proposed.
    • (B) A refundable credit paid in excess of tax is refunded as an overpayment, so it is a "federal refund" that the pre-2017 rule counted only to the extent of a prior Montana tax benefit, which is none. The 2017 amendment then added refundable credits. That is main's current behaviour.

    Choosing between them also turns on how far a Montana administrative rule binds against the statute. RULINGS P2 leaves that open for state regulations ("raise it with Max if a case turns on it"). So the 2009 list is unchanged. The existing "do not count before 2017" case now supplies a receipt, so it still pins main's behaviour.

  • Witness. 2024: a 70-year-old with a $20,000 pension whose return has $5,000 of federal refundable credits: gross household income $20,000 (main: $25,000). A parent's 2024 EITC of $3,400 and refundable CTC of $1,125 are not 2024 receipts: the variable is 0 (main: $4,525).

  • Years. 2017 onward (the variable enters the source list in 2017; the input applies in every year it is listed).

3. us-mt:elderly-credit-rent-free-occupants (2009+): fixed

  • Source. MCA 15-30-2338(1): to claim, "an individual: (a) must have reached age 62 or older ...; (b) must have resided in Montana for at least 9 months of that period; (c) must have occupied one or more dwellings in Montana as an owner, renter, or lessee for at least 6 months of the claim period" (current; 2009, unamended since). The 2025 instructions, p. 44 carry the same attestations. ARM 42.4.302(2)(b) lets an eligible claimant use another's property tax bill as rent; it does not supply eligibility.

  • Change. New parameters minimum_occupancy_months (6) and minimum_residency_months (9) from 2009. New Person inputs mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months and mt_elderly_homeowner_or_renter_credit_mt_residency_months (0-12). mt_elderly_homeowner_or_renter_credit_eligible now requires one head or spouse to meet age, residence and occupancy, and projects the result to the return's members. Defaults, so missing data does not establish eligibility:

    • Occupancy is 12 months for the head and spouse of a tax unit that pays rent or is billed property tax (Schedule 2EC lines 23-24 are the return's), and 0 otherwise. Another tax unit's bill never sets it.
    • Residence is 12 months for a Montana household, which the model treats as a full-year resident.

    A rent-free lessee or owner without either amount is recorded through the input. The gross_rent formula is unchanged; its comment now notes that the substitution reaches the credit only through an eligible claimant.

  • Witness. 2024: a parent, 80, paying no rent and billed nothing, in the home of a 45-year-old child billed $4,000. Both are ineligible and both credits are $0 (main: the parent gets $341). The same parent recorded as a 12-month lessee still gets $341. Thresholds: 6 occupancy and 9 residence months qualify; 5 or 8 do not.

  • Years. 2009 onward.

  • Updated regressions. The automatic rent-free-parent cases from Count property tax billed in another household member's name as rent in Montana's elderly homeowner/renter credit (ARM 42.4.302(2)(b)) #9945 now record the parent as a lessee where they test the bill-as-rent arithmetic. The siblings case's non-owner sibling is now ineligible (pre-limit credit 0, was 41; the paid credit is unchanged). New cases cover the parent without status.

Invariants

  • Disability exclusion: for every input in 2024 and later, mt_disability_income_exclusion_person is 0 and mt_disability_income_exclusion_eligible_person is false, even with eligibility supplied as an input; 2023 and earlier are unchanged.
  • Gross household income: a supplied federal receipt r raises gross household income by exactly r, counted once on the person who received it. The current return's income_tax_refundable_credits adds nothing. More receipts never raise the credit. Property-tested in test_mt_elderly_credit_refundable_credits.py (rewritten, Hypothesis).
  • Eligibility: a tax unit is eligible only if one head or spouse is at least 62 with 9+ residence months and 6+ qualifying-occupancy months. Another tax unit's bill never changes a unit's eligibility. The one-claimant property test (test_mt_elderly_credit_one_claimant.py) now checks the model against a reference that includes the occupancy rule, with lessee and non-lessee rent-free parents as explicit examples.

Tests

The shared host ran at load 95-120, so each policyengine-core test process took about 45 minutes. All runs were one file per process.

  • mt_elderly_homeowner_or_renter_credit.yaml at 11aec73: 50 passed, 1 failed. The failure was the 2021 TAXSIM case, which relied on this year's EITC and Economic Impact Payment flowing in. 4e74b36 fixed it by supplying the payment received in 2021: expected 63.33, was 59.24.

  • At 4e74b36, every affected YAML file passes, each in its own process:

    • mt_elderly_homeowner_or_renter_credit.yaml: 51 passed
    • ..._eligible.yaml: 11 passed
    • ..._federal_refundable_credits.yaml: 5 passed
    • ..._pre_one_claimant.yaml: 4 passed
    • ..._disability_and_unemployment.yaml: 13 passed
    • ..._unemployment_compensation_addback.yaml: 9 passed
    • ..._gross_household_income.yaml: 33 passed
    • subtractions/mt_disability_income_exclusion_person.yaml: 8 passed
    • subtractions/mt_disability_income_exclusion_eligible_person.yaml: 3 passed
  • Python worked examples pass:

    • test_mt_elderly_credit_refundable_credits.py::test_worked_example
    • test_mt_elderly_credit_one_claimant.py: the worked example, the lessee and non-lessee parent examples, and the newly-billed example (4 passed)
  • An in-session Opus review read the whole diff, core's projector and formula_YYYY semantics, and every MT elderly-credit YAML and Python test. It found five more cases that would break: disability_and_unemployment Cases 7-9, unemployment_compensation_addback Case 7, a business-loss case in gross_household_income, and test_mt_elderly_credit_nontaxable_income.py's worked example. All are fixed in 4e74b36. It found no circular dependency.

  • Not run locally:

    • the unchanged files in elderly_homeowner_or_renter/: gross_rent, selected_claimant, net_household_income, property_tax_billed, property_tax_rebate_received and dependent_deductions. The review traced their cases; it found that they either input eligibility or have a claimant billed property tax.
    • the full Hypothesis runs of the test_mt_elderly_credit_*.py files.

    CI covers both once this is ready for review.

  • The failing-first run on unmodified main was cancelled after 23 minutes because the host was CPU-starved. On main, the new 2024 disability case gives an exclusion of 5,200, the rent-free parent gets 341, and the current-return credit adds 5,000 to gross household income. Each of those follows directly from main's formulas, which this PR replaces.

Interaction with open PRs

Follow-ups (not in this PR)

  • policyengine-us-data: impute or carry federal refundable credits received during the year, and tenure facts for rent-free occupants, if the hub wants microdata to populate these inputs.
  • The Montana refundable credits in the same source list (mt_refundable_credits_before_renter_credit) are also this year's return, not receipts; the same timing question applies.

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 20, 2026 20:29
…occupancy tests

- End the disability income exclusion from 2024: 2021 Mont. Laws ch. 503
  section 65 repeals 15-30-2110, MCA, for tax years after 2023 (section
  70(1)). Drop it from the 2024 and 2025 subtraction lists.
- Make the elderly homeowner/renter credit's federal refundable credits an
  actual-receipt input (MCA 15-30-2337(4), "all income received"; ARM
  42.4.301(2)(b), "received") instead of this year's return entitlement.
- Require a head or spouse who is 62, a Montana resident for 9 months and an
  owner, renter or lessee for 6 months (MCA 15-30-2338(1)(a)-(c)); another
  household member's bill no longer makes a rent-free occupant eligible.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…derly credit tests

Cases that relied on this year's recovery rebate credit or EITC flowing into
gross household income now record the payment received during the year. A
business-loss case inputs eligibility, since its couple has no rent or
property tax. Found in review; the 2021 TAXSIM case now counts the 1,400
Economic Impact Payment received in 2021 but not the 2021 EITC paid in 2022.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 21, 2026 02:57
@MaxGhenis MaxGhenis closed this Oct 21, 2026
@MaxGhenis MaxGhenis reopened this Oct 21, 2026
@DTrim99

DTrim99 commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Fix Montana disability exclusion repeal, elderly credit receipt timing and occupancy tests

PR #10331 (author: MaxGhenis), head 4e74b36c75. This is a first review. The PR makes three model changes:

  • Disability income exclusion. mt_disability_income_exclusion_eligible_person and mt_disability_income_exclusion_person get a formula_2024 returning false and 0. The 2024 and 2025 subtraction lists drop the exclusion.
  • Receipt timing in gross household income. mt_elderly_homeowner_or_renter_credit_federal_refundable_credits loses its formula. It used to put the current return's income_tax_refundable_credits on the head. It is now an input, defaulting to 0, for federal refundable credit cash received during the year.
  • Occupancy and residence tests. New parameters set 6 months of occupancy and 9 months of residence from 2009. Two new Person variables record the months:
    • Occupancy months default to 12 for the head and spouse of a tax unit that pays rent or is billed property tax, and 0 otherwise.
    • Residence months default to 12.
    • Eligibility. mt_elderly_homeowner_or_renter_credit_eligible now requires one head or spouse to meet the age, residence and occupancy tests, and projects the result to the whole return.
  • Tests. It edits nine YAML files and three Python test files, and adds a changelog fragment.

The PR has no comments or reviews yet. It touches no partner test file.

Path prefixes:

  • V/ = policyengine_us/variables/gov/states/mt/tax/income/credits/mt_elderly_homeowner_or_renter/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/
  • S/ = policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/

Sources read for this review (all fetched 2026-10-21):

Summary

What is right.

  • 1. The disability exclusion ends in 2024.
    • Where it was. The exclusion was former §15-30-2110(10) (2019 MCA): a taxpayer under 65 "who has retired as permanently and totally disabled may exclude from adjusted gross income up to $100 a week". That is $5,200 a year.
    • The repeal. Ch. 503 §65 ("Repealer", file page 68) lists "15-30-2110. Adjusted gross income." §70(1) (file page 70) says "[this act] is effective January 1, 2024, and applies to income tax years beginning after December 31, 2023". §70(2), the list of sections that take effect early, doesn't include §65.
    • Confirmation. The 2023 MCA reads "15-30-2110. Repealed. Secs. 65, 70(1), Ch. 503, L. 2021." The current §15-30-2120 has no disability item. The 2024 instructions (file page 5) list "Partial retirement disability deduction for taxpayers under age 65" under "Repealed deductions".
    • The model. main still subtracted up to $5,200 in 2024 and 2025. The PR's 2024 start is right, and 2023 and earlier are unchanged.
  • 2. Credits count in gross household income in the year they are received.
    • The statute. §15-30-2337(4): gross household income "means all income received by all individuals of a household while they are members of the household".
    • The rule. ARM 42.4.301(2)(b) counts "federal refundable tax credits received".
    • The forms. The 2021, 2022 and 2023 schedules read "7 Refundable credits received, including the elderly homeowner/renter credit received in [year]". The 2024 Schedule 2EC line 8 reads "Refundable credits received ...". The 2024 instructions (file page 47) say "Combine all the refundable credits received by all household members in 2024".
    • Why the old formula was wrong. A credit on this year's return is paid next year, so the old formula counted the wrong year's credit. The 2016 Form 2EC lists only "Federal income tax refunds taxable in Montana", which supports leaving the pre-2017 list alone.
    • Rent and property tax use the claim year, which matches the model:
      • §15-30-2337(5) defines gross rent as rent "actually paid during the claim period".
      • §15-30-2337(10) defines property tax billed as "taxes levied against the homestead ... during the claim period".
      • The 2025 instructions require "a copy of your 2025 property tax bill".
  • 3. The occupancy and residence tests.
    • The statute. §15-30-2338(1): "an individual: (a) must have reached age 62 or older ...; (b) must have resided in Montana for at least 9 months of that period; (c) must have occupied one or more dwellings in Montana as an owner, renter, or lessee for at least 6 months of the claim period". Subsection (2) allows a change of residence "provided that the person occupies one or more dwellings in Montana as an owner, renter, or lessee for at least 6 months".
    • Unchanged since 2009. The 2009 text is identical, and the history ends "amd. Sec. 5, Ch. 147, L. 2009".
    • The forms agree in every year checked:
      • 2016 Form 2EC: "Six-Month Test ... occupied one or more residences as an owner and/or renter for six months or more" and "Nine-Month Test ... lived in Montana for nine months or more".
      • 2021-2023 schedules: "You have lived in Montana for at least nine months" and "You occupied a Montana residence as a renter, owner, or lessee for at least six months".
      • 2024 and 2025: the 2024 schedule and the 2025 instructions (file page 44) carry the same two tests.
    • The thresholds. Residence is the nine-month test and occupancy the six-month test, and the parameters have it that way round.
    • The rent-free reading. ARM 42.4.302(2) starts "To calculate the credit, an eligible claimant may use property taxes billed: ... (b) as rent if the property occupied by the claimant is in a name other than the claimant." That supports the PR's reading: another member's bill is a measure of rent for someone who already qualifies. It doesn't make that person qualify.
  • Tests. I hand-checked 18 cases (about 50 expectations), listed under Verified correct. CI passed every changed file.
  • Batch checks.

There are no critical findings and four should-address items:

There are also five suggestions: Montana refundable-credit timing, test additions and trimming, pre-existing gaps, formula_2024 versus a parameter, and the stale PR body.

Status.

Critical (must fix)

None.

Should address

S1. The Axiom line axiom: pending: hub files parity is not a valid form

  • Where: line 3 of the PR body.
  • The rule (CLAUDE.md, "Axiom Parity"): a PR that adds, updates or fixes policy needs one of encoded-correct, <rulespec PR> encoded, <rulespec issue> queued or n/a: <reason>. pending is not one of them. We flagged the same form on Fix the 2021 CTC split and surviving-spouse phaseout threshold #10306 and Fix pre-2018 AMT child exemption and income base #10308 today.
  • Why n/a doesn't fit. All three provisions are statutory: §15-30-2110(10) with ch. 503 §§65 and 70, §15-30-2337(4) with ARM 42.4.301(2)(b), and §15-30-2338(1)(b)-(c). The PR changes 2009+ eligibility, 2017+ gross household income and 2024+ subtractions.
  • What rulespec-us has (main 5796861e58):
    • us-mt/statutes/ holds only 15-30-2318 (the EITC).
    • The TY2026 pipeline. us-mt/policies/income_tax/resident_core_liability_pipeline.yaml cites §§2337, 2338, 2340 and 2341. It treats the elderly credit as a typed hold through not mt_pit_2026_has_elderly_property_tax_credit, so nothing about the credit is encoded.
    • Its subtractions. mt_pit_2026_profile_candidate_subtractions follows §15-30-2120 and so has no disability exclusion. It covers TY2026 only, not the claimed 2024-2025.
    • So encoded-correct isn't available for any of the three provisions in the claimed years.
  • Existing issues:
    • Revise starting point of pa_total_taxable_income calculations #1741 (open, pe-parity, updated 2026-10-13), "Encode Montana's historical partial retirement-disability exclusion and end it in 2024":
      • What it holds. It has the module target (us-mt/statutes/15-30-2110/10.yaml), the corpus citation, the verbatim §2110(10), required outputs and companion cases. One of them is "Repeat baseline in TY2024 -> 0 under repeal".
      • Blocker. It records the corpus gap: the pinned citation holds only the repeal note.
      • Match. It matches this head for 2024 and later. It can be cited as queued for provision 1.
    • Correct MA income tax Part A AGI calculation #1512 (open, pe-parity, updated 2026-10-18):
      • What it holds. It targets us-mt/statutes/15-30-2338.yaml and quotes §2338(1)(a)-(d). Required output 8 is "Eligibility judgments covering §2338".
      • What it lacks. Its companion cases never exercise the (1)(b)-(c) months or a rent-free occupant.
      • Receipt timing. It doesn't cover ARM 42.4.301(2)(b) receipt timing.
  • Severity: should. An invalid Axiom line is a merge blocker, not a model error.
  • Fix: change the line to axiom: TheAxiomFoundation/rulespec-us#1741 queued; TheAxiomFoundation/rulespec-us#1512 queued; TheAxiomFoundation/rulespec-us#<n> queued. Alternatively, run the signed encoder and cite the PR as encoded. Before relying on Correct MA income tax Part A AGI calculation #1512 and the new issue:
    • Correct MA income tax Part A AGI calculation #1512: comment with these §2338(1)(b)-(c) companion cases, from §2338 and the 2024/2025 attestations rather than PolicyEngine output. All are 2024, age 80, renting at $6,000:
      • 6 months of occupancy and 9 of residence: eligible.
      • 5 months of occupancy: ineligible.
      • 8 months of residence: ineligible.
      • Rent-free parent. A parent aged 80 who pays no rent and is billed nothing, living in a home whose bill is in a 45-year-old child's name, is ineligible.
    • New issue <n>, modelled on Add AMT parameters for 2020-2023 #1467:
      • Target: the gross household income definition (us-mt/statutes/15-30-2337.yaml, or a module for ARM 42.4.301).
      • Corpus citations: us-mt/statute/15-30-2337 and ARM 42.4.301(2)(b).
      • Verbatim law: §2337(4), ARM 42.4.301(2)(b) and the 2021-2025 schedule captions, all quoted above.
      • Required output: federal refundable credits received in the claim period.
      • Companion cases from Schedule 2EC:
        • 2024, a refund received. The claimant has a $20,000 pension; a member received a $632 federal EITC refund in 2024 for the 2023 return. Line 8 includes the $632.
        • 2024, credits not yet paid. A member's 2024-return EITC of $3,400 and refundable CTC of $1,125 are paid in 2025, so they are not in the 2024 line 8.
        • 2021. A $20,000 pension plus a $1,400 Economic Impact Payment received in 2021 gives line 10 of $21,400.
      • Why queued: the blocker, such as corpus scope, the signed release or approval for a billed run.

S2. The source-conflict candidates for these exact questions are now stale, and the pre-2017 question isn't recorded

  • Where: source_conflicts/candidates.yaml:3524 and :3550 (unchanged by the PR).
  • us-mt:elderly-credit-rent-free-occupants:
    • The entry. It asks "Can a rent-free occupant qualify by treating another member's property tax as rent when the statute requires occupancy as owner, renter or lessee?". It records pe_us.follows: conflicting-source and state: open. Its example is the $341 credit, and its note says "the statute-first rule requires a model change if the regulation expands rather than interprets statutory eligibility".
    • What the PR does. It makes that change: the occupant is ineligible, and the $341 is now $0. The PR body even uses this id as the heading of its section 3.
    • The entry is wrong after merge. It still says PE-US follows the conflicting source.
  • us-mt:elderly-credit-refundable-credit-timing (2021-2023):
    • The entry. It records follows: unknown and the note "PE-US uses current-return credits as a proxy". Its "other" reading is "The schedule directs use of amounts reported on the current Form 2."
    • That reading isn't supported. The 2021, 2022 and 2023 schedules themselves say "Refundable credits received, including the elderly homeowner/renter credit received in [year]". So statute, rule and form agree, and after this PR the model follows them.
  • Sibling Point the IN-MT source-conflict candidates at their code on main #10351 (same author, open) rewrites both notes to describe the behaviour this PR removes:
    • rent-free: "PE-US follows the regulation and instructions ... so a rent-free occupant can qualify";
    • timing: "PE-US uses the current return's federal and other Montana refundable credits as a proxy".
    • The two PRs merge cleanly as text, but whichever lands second leaves a wrong record.
  • Not recorded: the pre-2017 question. The PR body sets out two readings for 2009-2016:
    • Reading (A). §2337(9)(a)'s "all nontaxable income" would count refundable credits from 2009.
    • Reading (B). The 2004-2017 ARM counted federal refunds only "to the extent that the amount recovered reduced the claimant's Montana income tax in a prior year".
    • Status. It keeps main's behaviour pending a decision. That is a statute-versus-rule question that is open, but it isn't in the backlog.
  • Severity: should. The batch rules require such conflicts to be recorded under the source-conflict process. These records now misstate what PE-US does, in a file shared with Axiom.
  • Fix: in this PR, coordinated with Point the IN-MT source-conflict candidates at their code on main #10351:
    • Rent-free entry. Set pe_us.follows: statute and state: ruled. List the code (V/..._eligible.py, V/..._qualifying_occupancy_months.py, V/..._gross_rent.py), add this PR, and update the example and note. Alternatively, delete the entry with a reason, if you treat ARM 42.4.302(2)'s "eligible claimant" as removing the conflict.
    • Timing entry. Delete it, citing the schedule captions above. Or mark it ruled, extend its years to start in 2017, and list V/..._federal_refundable_credits.py and gross_income_sources.yaml.
    • New entry. Add a candidate for the 2009-2016 question (for example us-mt:elderly-credit-federal-refundable-credits-before-2017) with state: open. Cite §2337(9)(a), the 2004-2017 ARM 42.4.301(2)(b) and the 2016 Form 2EC worksheet.

S3. The zero default drops the 2020 and 2021 Economic Impact Payments, which were paid within the claim year

  • Where: V/mt_elderly_homeowner_or_renter_credit_federal_refundable_credits.py:34-39, which has no formula.
  • The payments fall inside the claim year. The Economic Impact Payments were advance refunds of each year's own recovery rebate credit, and the statute set the deadlines:
    • §6428(f)(3) (CARES): "No refund or credit shall be made or allowed under this subsection after December 31, 2020".
    • §6428A(f)(3) (CAA): "...after January 15, 2021".
    • §6428B(g)(3) (ARPA): "...after December 31, 2021".
    • The forms list them. The 2021 instructions, which the PR's own test quotes, say "Refundable credits include ... Economic Impact Payments".
  • What changes.
    • Before the PR. income_tax_refundable_credits, which includes recovery_rebate_credit = rrc_cares + rrc_caa + rrc_arpa, put these amounts in gross household income for 2020 and 2021.
    • After. They count only if a user supplies them. So every 2020 and 2021 claimant's gross household income is understated by $1,200-$1,800 per adult (2020) or $1,400 per person (2021).
    • The effect. The line 14 contribution falls by 5% of that, which raises the credit.
  • The PR's own tests show it:
    • Hand-supplied payments. Seven YAML cases now supply the payments by hand: the 2021 TAXSIM case, four in ..._disability_and_unemployment.yaml, Case 7 of ..._unemployment_compensation_addback.yaml, and Case 4 of ..._federal_refundable_credits.yaml.
    • The 2020 Python worked example. In test_mt_elderly_credit_nontaxable_income.py the credit moves from 135 to 315 because no payment is supplied: 2 × 1,800 × 5% = 180.
  • The PR body's cost argument doesn't apply here. It says reading last year's return would rerun the prior-year federal computation. These are same-year amounts the model already computes.
  • Severity: should (a period error in a default, limited to 2020-2021).
  • Fix:
    • A formula for those years. Give the variable a formula that returns the same-year payment amounts on the tax-unit head:
      • 2020: rrc_cares, plus rrc_caa as the PR's 2020 tests already assume;
      • 2021: rrc_arpa, and the 2021 advance child tax credit under §7527A if you model it;
      • other years: 0.
    • Supplied amounts still win. A supplied receipt should still override the formula.
    • The tests. Then drop the hand-supplied inputs from the 2020 and 2021 cases.
    • Other years. File the policyengine-us-data issue the PR body lists as a follow-up and link it.

S4. Recording one occupant as a lessee resets everyone else's occupancy to zero

  • Where:
    • V/mt_elderly_homeowner_or_renter_credit_qualifying_occupancy_months.py:8-13 (the documentation) and :29-46 (the formula);
    • the PR body, section 3: "A rent-free lessee or owner without either amount is recorded through the input."
  • How core handles a partial input. When a situation supplies a variable for some people, policyengine-core's SimulationBuilder.add_variable_value fills variable.default_array(...) for everyone else. finalize_variables_init then calls holder.set_input for the whole population. So the others get 0, not the formula.
  • The PR knows this. Its tests say so ("An input for one person gives the others the input default, not the formula, so record everyone's months") and supply everyone's months. A user following the documented workflow won't know to.
  • A wrong result. Take the PR's siblings case (T/mt_elderly_homeowner_or_renter_credit.yaml:1479):
    • The household. person1, aged 66 and rent-free, is recorded as a lessee with 12 months. Nothing is supplied for person2, aged 70 and billed $2,000.
    • The model. person2's months become 0, so person2 is ineligible. person1 is the only candidate, with line 24 = 2,000, line 25 = 300 and line 27 = 300 − 259 = 41. The model pays [41, 0].
    • The law. person2 owns the home and meets §2338(1)(c), so the household's one claim (§2341(1)) is person2's $1,150.
    • The documentation is also wrong. It says the variable "Defaults to 12 for the head and spouse of a tax unit that pays rent or is billed property tax". That stops being true once anyone in the simulation has the input.
  • Severity: should (an input design that gives wrong results under the PR's own documented use).
  • Fix:
    • Split the input from the formula. Add an input-only variable, for example a bool mt_elderly_homeowner_or_renter_credit_occupies_as_lessee (default false) or ..._lessee_months (default 0). Make the months formula return 12 when rent or a bill shows the status, and otherwise the lessee input.
    • Add a case. Add the siblings case with only person1 marked as a lessee, expecting mt_elderly_homeowner_or_renter_credit: [0, 1_150].

Suggestions

G1. Montana refundable credits still use the current return

  • Where: the same line 8 still counts mt_refundable_credits_before_renter_credit, which comes from this year's Montana return.
  • The inconsistency. The 2021 TAXSIM case (T/mt_elderly_homeowner_or_renter_credit.yaml:210) excludes the 2021 federal EITC (81.76) as "paid in 2022". Yet it counts the Montana EITC on the same 2021 return (2.45). The 2024 cases do the same with the 10% Montana EITC.
  • The PR body lists this as a follow-up.
  • Fix (optional): file the issue and link it from gross_income_sources.yaml and the variable documentation. That keeps the inconsistency documented in the code.

G2. Tests

  • A spouse-only claimant. No case has a head who fails while the spouse qualifies. In T/..._eligible.yaml:33 the qualifying 70-year-old is the head, because the head is the oldest adult. Add one, for example a head aged 75 with occupancy input 0 and a spouse aged 65 with 12 months. Assert eligibility for both and the credit on the head (..._pre_one_claimant).
  • The rewritten property test. policyengine_us/tests/test_mt_elderly_credit_refundable_credits.py now mainly checks that a supplied input passes through to gross household income. That duplicates YAML Case 3 (T/..._federal_refundable_credits.yaml:50). It cost 7.99 s plus 1.58 s in the Rest (Python, shard-1) job. Consider trimming it to the worked example, or saying in the PR body which failure only it catches (CLAUDE.md, "Test design and CI cost").

G3. Pre-existing gaps the new cases rely on

  • Bona fide lessees are outside the household. §2337(7)(b) says the household "does not include bona fide lessees, tenants, or roomers and boarders on contract".
    • The new lessee examples. T/mt_elderly_homeowner_or_renter_credit.yaml:1354 and the lessee examples in T/..._eligible.yaml:87 and T/..._pre_one_claimant.yaml count the owner's income in the lessee's gross household income. That gives 20,000 and a credit of 341.
    • Under the statute the case is either a lessee outside the household (gross household income 14,000, line 22 = 0, credit 600) or not a lessee (ineligible).
    • The cause. The model doesn't implement (7)(b), which predates this PR.
    • Note it in the variable documentation or the test comments.
  • The former disability exclusion. Its pre-2024 version omits the "$100 a week" actual-weeks limit and the $15,000 adjusted gross income phase-out in §2110(10). rulespec-us#1741 tracks both. None of the PR's 2023 cases reaches the phase-out.

G4. A parameter instead of formula_2024

  • Where: policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/.
  • Already handled. Dropping the exclusion from the 2024 and 2025 subtraction lists already ends it in mt_subtractions.
  • The alternative. The two formula_2024 blocks put the repeal date in code. An in_effect parameter under subtractions/disability_income/, false from 2024-01-01 and citing ch. 503 §§65 and 70, would keep the date in the parameter tree.
  • Fix (optional).

G5. The PR body is stale

  • Local-run narrative. It describes local runs at load 95-120 and says "CI covers both once this is ready for review". CI has since run all of them (see CI status).
  • Fix (optional): replace the Tests section with the CI result, fix the Axiom line (S1), and turn the follow-ups into filed issues.

Verified correct

  • Hand-checks (18 cases, about 50 expectations). Each is Montana.
    • Provision 1, the disability exclusion:
      1. S/mt_disability_income_exclusion_person.yaml:40 (2023), age 60, retired on total disability, benefits 5,200. Eligible (60 < 65, head). The exclusion is min(5,200 cap, 5,200 taxable) = 5,200. Adjusted gross income is below the former $15,000 phase-out start.
      2. Same file, :51 (2024). Eligibility false, the person and tax-unit exclusions 0, and mt_subtractions 0.
        • The subtraction list: interest exemption 0, tuition 0, old-age subtraction 0 (60 < 65), SALT refund 0, and on the merged tree mt_other_subtractions 0.
        • Main gave 5,200.
      3. Same file, :69 (2025). 0, and mt_subtractions 0. The OBBBA subtraction is 0 at age 60 with no tips, overtime or car-loan interest.
      4. Same file, :80 (2024), eligibility input true, benefits 15,000. formula_2024 gives 0.
      5. S/mt_disability_income_exclusion_eligible_person.yaml (2024), head aged 64, retired. False.
    • Provision 2, receipt timing:
      6. T/..._federal_refundable_credits.yaml:1 (2024), wages 10,000, one child.
      • EITC is 34% × 10,000 = 3,400, below the $12,390 earned-income amount.
      • Refundable CTC is min(1,700, 15% × 7,500) = 1,125.
      • The variable is [0, 0].
      1. Same file, :30, pension 20,000 with a tax-unit income_tax_refundable_credits input of 5,000. The variable is 0 and gross household income 20,000.
      2. Same file, :50. A 632 receipt on the member gives [20,000, 632].
      3. Same file, :75 (2021). 20,000 + 1,400 = 21,400.
      4. T/mt_elderly_homeowner_or_renter_credit.yaml:210 (2021), wages 20,892.60, property tax 863.08, payment received 1,400.
        • Federal EITC (not counted). 1,502 − 15.3% × 9,282.60 = 81.76.
        • Montana EITC (counted). 3% gives 2.45.
        • Computation. Line 10 = 22,295.05, and 22,295.05 − 6,300 = 15,995.05. Times 0.05 that is 799.75, and 863.08 − 799.75 = 63.33.
      5. Same file, :1113 (2024), two renters.
        • Gross household income is [10,580, 15,420], 26,000 in all, so line 22 = 13,400 × 0.05 = 670.
        • Rent equivalents are [720, 1,080], so the claims are [50, 410]. person2 is selected for 410.
      6. T/..._gross_household_income.yaml, the 2017 and 2016 cases.
        • 2017: 10,383.01. The EITC is 510 − 7.65% × 1,660 = 383.01 (Rev. Proc. 2016-55).
        • 2016: 10,000. The variable is not in the 2009 list.
    • Provision 3, occupancy and residence:
      13. T/..._eligible.yaml:116, :129 and :140. 6 and 9 months qualify, 5 months of occupancy fails, and 8 months of residence fails.
      14. Same file, :33.
      - Roles. The head is the oldest adult (70) and the spouse is 60.
      - Months. Tax-unit rent of 6,000 gives both 12 months and the child 0: [12, 12, 0].
      - Result. The 70-year-old qualifies, so the return is [true, true, true].
      15. Same file, :175. The head, 70, has occupancy input 0 and the spouse is 60, so [false, false].
      16. Same file, :58, and T/mt_elderly_homeowner_or_renter_credit.yaml:1312 and :1354.
      - Non-lessee parent. Months are [0, 12], both are ineligible, and the credits are 0.
      - Lessee parent. Gross household income is 20,000. 20,000 − 12,600 = 7,400 at 0.035 gives 259. Line 24 = 4,000 gives 600, and the credit is 341.
      17. T/mt_elderly_homeowner_or_renter_credit.yaml:1479, siblings. person1 is ineligible. person2 gets 2,000 − 259 = 1,741, capped at 1,150, so [0, 1,150].
      18. T/..._pre_one_claimant.yaml, Cases 3 and 4.
      - Case 3. Gross household income is 12,000, so line 20 is negative and the contribution 0. The lessee gets 2,500 × 15% = 375.
      - Case 4. [0, 0].
  • Parameters. minimum_occupancy_months (6) and minimum_residency_months (9) from 2009 match §2338(1)(b)-(c) and every form checked (2016 and 2021-2025). The labels, units and descriptions are fine.
  • References.
    • Session laws. File page 68 holds §65 and file page 70 holds §70. subtractions.yaml uses a quoted title ending "#page 68,70". The variables use a # PDF pages 68, 70 comment, as CLAUDE.md asks.
    • Instructions: 2024 #page=5 (repealed deductions), 2025 #page=44 (the attestations), 2023 #page=51 (line 7 "received") and 2024 #page=47 (line 8).
    • ARM 42.4.302. The quotations of ARM 42.4.302(2) in V/..._eligible.py and V/..._gross_rent.py are accurate.
  • Callers at the head:
    • The receipt variable. ..._federal_refundable_credits is read only through gross_income_sources.yaml (the 2017 and 2023 lists).
    • The month variables are read only by ..._eligible.
    • Eligibility feeds ..._credit, ..._pre_one_claimant and ..._net_household_income (through defined_for) and ..._selected_claimant.
    • The disability variables are read only through subtractions.yaml (the 2010 and 2021 lists) and the tax-unit sum.
  • Vectorization.
    • Eligibility uses person.tax_unit.any(...), which core projects back to persons.
    • Occupancy uses where.
    • Scalars. The formula_2024 scalars are broadcast by core's formula-result cast.
    • Microdata. The Microsimulation job passed.
  • Changelog. changelog.d/statute-bugs-mt-disability-ehrc-elderly.fixed.md is a top-level fragment, and fixed is the right type.
  • Batch lessons:

Axiom line assessment

Invalid: axiom: pending: hub files parity (S1).

  • Recommended form: axiom: TheAxiomFoundation/rulespec-us#1741 queued; TheAxiomFoundation/rulespec-us#1512 queued; TheAxiomFoundation/rulespec-us#<n> queued. Alternatively, cite an encoder PR as encoded.
  • Not n/a. These are statutory provisions with changed results in claimed years.
  • Not encoded-correct. rulespec-us holds the elderly credit as a typed hold. Its TY2026 subtractions don't reach 2024-2025.

CI status

27 pass, 3 skipping, 0 pending, 0 failed. I re-checked gh pr checks 10331 at the end of this review, and the head is still 4e74b36c75.

  • The green run. Run 39608417408 (pull_request, created 2026-10-21 13:29 UTC) tested merge commit f44c0a19, which merges the head into f45d36a7d1.
  • Where the changed tests ran.
    • Quick Feedback deferred all of them ("12 files > 8").
    • Montana YAML. The Baseline states-shard-4 job (Montana batch, exit 0) passed every changed file:
      • the credit file 51, ..._eligible 11, ..._federal_refundable_credits 5 and ..._gross_household_income 33;
      • ..._pre_one_claimant 4, ..._disability_and_unemployment 13 and ..._unemployment_compensation_addback 9;
      • the disability files 3 and 8.
    • Python. The Rest (Python, shard-1) job passed every test_mt_elderly_credit_* test.
    • Full suites. Microsimulation and Household API Partners also passed.
  • Locally: I ran no tests or model probes. CI is green at the current head. I checked every expectation and the S3 and S4 traces by hand from the code, the parameters, the sources and policyengine-core's SimulationBuilder.

Branch status

0 critical, 4 should and 5 suggestions are open at this head.

Verdict: REQUEST_CHANGES

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The law checks out: the SB 399 repeal is effective after 2023, s.2337(4) counts income received, and s.2338(1) requires 9 months of residence and 6 of occupancy. Four should-address items: (1) the 'pending: hub files parity' axiom line is invalid (use #1741 and #1512 queued, plus a new issue for receipt timing); (2) two candidates.yaml entries go stale; (3) the zero default drops the 2020-21 Economic Impact Payments, which were received in-year; (4) recording one occupant as a lessee zeroes everyone else's occupancy months (the owner's $1,150 claim becomes $41). Five suggestions. Full report in the comment above.

This branch has not been deployed

No deployments
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.

2 participants