Skip to content

Deduct Montana's 2021–2023 medical and long-term care insurance premiums in full (Itemized Deductions Schedule lines 2–3) - #9947

Merged
MaxGhenis merged 52 commits into
mainfrom
fix-mt-medical-premiums-in-full
Oct 19, 2026
Merged

MaxGhenis merged 52 commits into
mainfrom
fix-mt-medical-premiums-in-full

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #9930. Builds on #9903 (merged as 51487d5) and #10055 (merged as 3d908a6), which nets the self-employed health insurance deduction out of federal Schedule A premiums. The diff is against main.

Summary

For TY2021–2023, Montana's Itemized Deductions Schedule (Form 2 page 7) splits medical costs across three lines:

  • line 1 reduces medical and dental expenses other than insurance premiums by 7.5% of Montana AGI;
  • line 2 deducts medical insurance premiums in full;
  • line 3 deducts long-term care insurance premiums in full.

Lines 2 and 3 cover payments made by the taxpayer and exclude premiums already deducted in Montana AGI. PolicyEngine floored everything together: mt_medical_expense_deduction_joint and mt_medical_expense_deduction_indiv put the premiums (including modeled Medicare Part B) under the 7.5% floor and left out long-term care premiums.

What the law and forms say

Former MCA § 15-30-2131(1) (MCA 2021; repealed effective January 1, 2024):

  • (1)(a) allows the IRC § 161 and § 211 items, which bring in the § 213 medical deduction and its floor. It excludes "(iii) premium payments for medical care as provided in subsection (1)(g)(i)" and "(iv) long-term care insurance premium payments as provided in subsection (1)(g)(ii)".
  • (1)(g) allows "the entire amount of premium payments made by the taxpayer, except premiums deducted in determining Montana adjusted gross income", for (i) medical care insurance as defined in 26 U.S.C. 213(d) and (ii) insurance for qualified long-term care services, as defined in 26 U.S.C. 7702B(c) (qualified contracts themselves are defined in 7702B(b)). The coverage must be for the taxpayer, dependents, parents and grandparents.

Form 2 page 7 (2022, PDF p. 7; 2021 and 2023 have the same lines):

  • line 2, "Medical insurance premiums not deducted elsewhere on your return";
  • line 3, "Long-term care insurance premiums not deducted elsewhere on your return";
  • neither line has a floor.

Form 2 instructions (2022, PDF pp. 32–33; 2021 PDF pp. 31–32 and 2023 PDF p. 36 say the same):

  • Line 1 excludes premiums claimed on lines 2 and 3.
  • Line 2 makes Medicare Part B and Part D premiums 100% deductible. To qualify, premiums cannot be:
    • paid through an HSA or a Montana medical care savings account;
    • paid pre-tax through an employer cafeteria plan;
    • deducted as the self-employed health insurance deduction (Schedule 1, line 17) or on the Montana Subtractions Schedule, line 11.
  • Line 3 deducts long-term care premiums "without regard to the federal limitation" when they were not deducted in determining Montana AGI. The 2021 instructions also exclude premiums claimed for the Elderly Care Credit (former MCA § 15-30-2366, repealed effective 2022).

26 U.S.C. 162(l)(2)(C) (govinfo) lets eligible long-term care premiums into the self-employed health insurance deduction. So line 3 must also net that deduction, not only line 2.

From 2024 the 2024 instructions (PDF p. 8) list the Itemized Deductions Schedule (and filing status 2a's schedules) as discontinued. Montana then takes federal itemized deductions, where premiums stay under the federal floor. That treatment is unchanged here.

Changes

  • mt_premium_deduction_joint (new, tax unit; lines 2 and 3 of a joint return):
    • The head's and spouse's medical and long-term care premiums, less the return's self-employed health insurance deduction (self_employed_health_insurance_ald, supplied or summed from the head's and spouse's amounts).
    • The deduction comes off medical premiums first, using Exclude SE health insurance deductions from Schedule A medical expenses #10055's itemized_medical_expenses_excluded_premiums (the bounded exclusion the computed federal subtotal uses), and the rest off long-term care premiums.
    • Only premiums attributed to the head or spouse count. Premium inputs identify the payer, so premiums a filer pays for dependent coverage belong on that filer's input; a dependent's own payments do not become the filers' deduction.
    • So a deduction supplied only for the return is honored.
  • mt_eligible_medical_insurance_premiums (new, person; line 2 amounts used for the head and spouse on separate returns) = medical_expense_health_insurance_premiums − Exclude SE health insurance deductions from Schedule A medical expenses #10055's self_employed_health_insurance_ald_excluded_premiums (the person's self-employed deduction, capped at their premiums).
    • medical_expense_health_insurance_premiums includes modeled Medicare Part B.
    • It never reads pre_tax_health_insurance_premiums, a separate input that reduces wages through pre_tax_contributions. So pre-tax premiums stay off line 2.
  • mt_eligible_long_term_care_insurance_premiums (new, person; line 3 amounts used for the head and spouse on separate returns) = max(0, long_term_health_insurance_premiums − the part of the person's self-employed deduction not used by line 2).
    • Lines 2 and 3 together equal max(0, premiums + long-term care premiums − deduction). The deduction is netted once, and the order of allocation doesn't change the total.
  • mt_medical_expense_deduction_joint:
    • 2021–2023 (state_specific_deduction_applies): line 1 = max(0, base − 7.5% × mt_agi_joint), plus mt_premium_deduction_joint, held by the head.
    • The line 1 base is max(0, itemized_medical_expenses − medical premiums still in it − itemized_medical_expenses_long_term_care_premiums).
      • Medical premiums still in it = every member's medical insurance premiums − min(the head's and spouse's medical premiums, max(0, itemized_medical_expenses_applied_exclusion)).
      • The bound keeps any long-term care part of a supplied exclusion from being taken off line 1, or off dependents' premiums.
      • For a computed subtotal this is Σ other_medical_expenses, so the self-employed deduction is netted once, on lines 2–3.
      • A supplied subtotal is kept and used as given. By default it is the medical costs paid, as North Dakota and New Mexico use it after Exclude SE health insurance deductions from Schedule A medical expenses #10055. Medical premiums leave line 1, and only the filers' payer-attributed premiums enter lines 2–3. A net Schedule A subtotal comes with the excluded amount in itemized_medical_expenses_applied_exclusion, so only the premiums still inside it leave line 1 (contract documented on both federal variables).
    • From 2024 it is the federal medical_expense_deduction, unchanged.
  • itemized_medical_expenses_long_term_care_premiums (new, tax unit; a pure input, default 0): the long-term care premiums a supplied itemized_medical_expenses includes, such as eligible premiums counted on Schedule A line 1 and not taken as the self-employed deduction.
    • The computed subtotal counts none, so the default is right for it and for a supplied subtotal with the computed contents.
    • The contract is documented on itemized_medical_expenses.
    • An input rather than a formula, because PE can't tell how much of a supplied subtotal is long-term care. The amount depends on the insured's age, which payer-attributed premium inputs don't carry, and on how much the self-employed deduction took.
  • mt_medical_expense_deduction_indiv: the same three lines per filer on their own mt_agi_indiv, while the schedule applies. Its existing head-or-spouse restriction excludes dependents' own payments. If a reform allows separate filing after 2023 (enable_mt_mfss_2024_reform), it keeps Exclude SE health insurance deductions from Schedule A medical expenses #10055's treatment: premiums net of the self-employed deduction, under the floor with the other expenses.
  • Stack updates:
  • References use the official MCA 2021 page instead of the Justia URL, which returns 403.
  • Fixed the existing separate-filing case "Not head or spouse ineligible", which had set is_tax_unit_head_or_spouse: true.

Household effects (historical runs)

These runs compared main 5ec60b2 with the PR at 39a5e66, both on policyengine-core 3.33.4. They predate the payer-restriction fix at 715ac2c. The hub reruns the impact at the new head; the figures below remain historical evidence pending that run.

Household Montana medical deduction Montana income tax
2022 couple: wages $80k, $6k after-tax premiums, $3k other medical, $8k property tax $3,000 → $6,000 $3,278.68 → $3,076.18
2023 single, 70: $40k pension, Medicare Part B $1,978.80 + $3k Medigap, $2k other medical, $5k property tax $3,978.80 → $4,978.80 $511.35 → $445.31
2021 couple: wages $120k, $5k long-term care premiums, $6k property tax $0 → $5,000 $3,720.76 → $3,375.76
2022 self-employed single: Schedule C $50k, $6k premiums taken as the self-employed deduction $0 → $0 $1,511.70 → $1,511.70
2023 self-employed single, 40: Schedule C $60k; $3k medical and $2k long-term care premiums. The self-employed deduction takes the $3k plus the $480 of long-term care premiums eligible at that age (Rev. Proc. 2022-38 §3.28); $2k other medical $0 → $1,520 (line 3: 2,000 − 480) $2,168.99 → $2,066.39

All five itemize before and after.

The self-employed rows show the deduction netted once:

Script and outputs: ~/reviews/mt-medical-premiums-2026-10-06/household_examples.py, household_base_r3.json, household_pr_r3.json.

Hub microsimulation impact (current head)

A real microsimulation on the default dataset, main at the merge base 83e03a92f6 against this PR's head 715ac2cd77, for 2024. The runs went one at a time under the shared heavy-job lock. Sums are weighted.

Output 2024 change 2024 records changed (weighted)
mt_income_tax +0 0 (0)
mt_itemized_deductions +0 0 (0)
mt_medical_expense_deduction_joint +0 0 (0)
mt_medical_expense_deduction_indiv +0 0 (0)
nm_medical_expense_credit +0 0 (0)
state_income_tax +0 0 (0)
income_tax +0 0 (0)
household_net_income +0 0 (0)
household_benefits +0 0 (0)

Current law at this head 715ac2cd77 against main 83e03a92f6: no change in any compared variable, because the branches this PR changes are off from 2024 (SB 399 repealed § 15-30-2131). The 2024 counterfactual above predates the payer fix and is historical.

Comparison files are in fixes/9947-impact/ on the hub host.

Microsim impact (historical runs)

The saved impact files identify PR heads 39a5e66 and 96d2f72. They do not establish results at 715ac2c. The hub reruns the impact at the new head.

2024 counterfactual sensitivity: legacy Montana medical and standard deduction branches enabled on both sides. The change applies to TY2021–2023 only, and the default dataset (populace_us_2024) holds 2024 records only (a 2021–2023 run reads zero inputs). So both sides run 2024 with gov.states.mt.tax.income.deductions.itemized.state_specific_deduction_applies and ...standard.state_specific_deduction_applies switched on (impact/reform_2023_deductions_on_2024.json). Income, rates and other 2024 law stay as they are. This sizes the change; it is not a TY2021–2023 revenue estimate.

Variable (2024 counterfactual) Base (main 5ec60b2) Historical PR run Change Weighted tax units changed
mt_medical_expense_deduction_joint $1,213.5M $2,184.6M +$971.1M 270,800 up
mt_itemized_deductions_joint $3,733.7M $4,704.7M +$971.1M 270,800 up
mt_taxable_income_joint $48,107.2M $47,598.8M −$508.4M 94,100 down
mt_income_tax $2,548.7M $2,519.1M −$29.6M 94,100 down (largest: $2,384.54)
income_tax (federal), household_benefits $0 0

The PR side ran at 39a5e66. The inspected dataset supplies no itemized_medical_expenses, but later production changes include the payer restriction, so these figures are not presented as results at the new head.

Current law, 2024, historical run (base main 5ec60b2; PR side 96d2f72): zero change in mt_income_tax, mt_medical_expense_deduction_joint, mt_itemized_deductions_joint, mt_standard_deduction_joint, mt_taxable_income_joint, state_income_tax, income_tax, household_net_income and household_benefits. No record changed. Output: the hub's fixes/9947-impact/compare.2024.json, copied to impact/current-law-2024/.

The change affects TY2021–2023 only. From 2024:

The unchanged 2024+ branches retain current-law treatment. The hub reruns the impact at the new head.

Tests

Hub shell-review response runs use Python 3.13.9, policyengine-core 3.33.2 and Hypothesis 6.168.5, one file per process in the foreground, with all five numerical thread limits set to 4 and OMP_WAIT_POLICY=PASSIVE. At 715ac2c: mt_medical_expense_deduction_joint.yaml 29 passed; mt_medical_expense_deduction_indiv.yaml 10 passed; nm_medical_expense_credit.yaml 24 passed; test_mt_medical_premium_deduction_invariants.py 5 passed; federal medical_expense_deduction.yaml 11 passed; additionally, the modified mt_premium_deduction_joint.yaml 6 passed. make format and git diff --check passed.

The owner runs below are historical. They used one file per process through the shared heavy lock (~/reviews/us-hub/scripts/heavy_run.sh) on policyengine-core 3.33.4.

  • This PR's own files (historical run at f9204be): mt_eligible_medical_insurance_premiums.yaml, mt_eligible_long_term_care_insurance_premiums.yaml, mt_premium_deduction_joint.yaml, mt_medical_expense_deduction_joint.yaml, mt_medical_expense_deduction_indiv.yaml, test_mt_medical_premium_deduction_invariants.py and test_mt_joint_agi_deductions_properties.py (Floor Montana's joint-return medical and standard deductions on the return's Montana AGI, and on federal AGI from 2024 #9903's, 15 tests). All pass.
  • Neighbours (at 96d2f72): mt_medical_expense_deduction_joint.yaml (26 cases), mt_itemized_deductions_joint/indiv.yaml, both federal-itemization files, mt_standard_deduction_joint.yaml, mt/tax/income/integration.yaml, mt_taxable_income_joint.yaml, mt_income_tax*.yaml, mt_deductions_indiv.yaml, mt_tax_unit_itemizes.yaml, state_itemized_deductions.yaml, salt_refund_integration.yaml, the federal medical_expense_deduction.yaml, nd_renters_refund_income.yaml (15), nm_medical_expense_exemption.yaml (13) and nm_medical_expense_credit.yaml (23). All pass. The code-health reference tests: 119 passed.
  • At the reviewed head (historical): bf1661d: mt_medical_expense_deduction_joint.yaml 28 passed; nm_medical_expense_credit.yaml 24 passed; test_mt_medical_premium_deduction_invariants.py 5 passed, with property 9 running in the three seeded state years.
  • Fails on main: the same files on main 5ec60b2, core 3.33.4:

Invariants

tests/unit/test_mt_medical_premium_deduction_invariants.py uses Hypothesis batches plus a seeded population of 120 returns, over 2021–2024. Each batch runs as one vectorized simulation that holds each return, a twin with higher premiums, and a twin without pre-tax premiums. Each batch takes the self-employed deduction one way: derived from self-employment income, supplied for every person, or supplied for every return. Mixing them in one batch is not possible, because core treats a formula variable supplied for some members as an input for all, filling the rest with 0. The seeded population covers each mode in a different state year.

The 7.5% rate comes from Form 2 line 1c. Montana AGI and the self-employed deductions are read from the model; they are inputs to the properties, not derived independently. The properties use payer-attributed premium inputs: only the head's and spouse's payments enter the filers' premium deduction. A filer's payments for dependent coverage belong on the filer's input; a dependent's own payments are excluded.

  1. Accounting (2021–2023).
    • Joint = max(0, other expenses − 7.5% × Montana AGI) + mt_premium_deduction_joint, held by the head.
    • Separate = max(0, own other expenses − 7.5% × own Montana AGI) + own lines 2 and 3 for the head and spouse; dependents hold 0.
  2. Premium conservation against closed forms, with premiums computed from the raw inputs (direct, decomposed, or with Medicare Part B):
    • per-person helpers: line 2 + line 3 = max(0, premiums + long-term care premiums − own deduction), and line 2 = premiums − min(premiums, own deduction);
    • joint: lines 2 and 3 = max(0, filers' premiums + filers' long-term care premiums − the return's deduction). Dependent-paid premiums do not enter this amount.
    • Supplied deductions range up to 20,000, often above the premiums. Each is netted once.
  3. Bounds: lines 2 + 3 ≤ deduction ≤ lines 2 + 3 + other expenses.
  4. Slope of one for filers: raising the head's or spouse's after-tax or long-term care premiums that no deduction can absorb raises the deduction by exactly the increase. Filers of a return where any filer may have a deduction are skipped, because the return's deduction is pooled. Dependent-paid premium increases do not raise the filers' premium deduction. Montana AGI is unchanged (asserted).
  5. Pre-tax premiums never change lines 2 or 3.
  6. Line 1 base, computed subtotals (where the exclusion is already bounded by the filers' medical premiums) = federal itemized_medical_expenses + Exclude SE health insurance deductions from Schedule A medical expenses #10055's itemized_medical_expenses_applied_exclusion − premiums. The long-term care input is asserted to be 0. This fails if the federal aggregate gains a component.
  7. Differential: for single filers whose deduction is recorded per person, the joint and separate variants agree.
  8. From 2024: joint = federal medical_expense_deduction, and the separate variant is 0.

Non-vacuity (seeded population) checks that the population includes:

  • returns deducting premiums while line 1 is under the floor;
  • returns with line 1 positive too;
  • people whose deduction exceeds their medical premiums and reduces line 3;
  • returns whose return-level deduction reduces lines 2 and 3;
  • single and joint returns;
  • dependent-only premium increases that leave the filers' deduction unchanged.
  1. Differential (seeded, 2021–2023): re-running the population with a net Schedule A subtotal, its exclusion (medical first, then long-term care) and the long-term care still inside supplied for every return gives the same Montana deduction as the computed path.

Why Python: YAML can't generate populations, compare twin returns, or re-run a population with supplied subtotals. Cost: test_mt_medical_premium_deduction_invariants.py is new in this PR. In the owner's earlier measurement (macOS, Python 3.14, core 3.33.4) it takes 21.8 s wall time including interpreter start and model build (6.1 s of test time), with 1.13 GB peak RSS. It builds up to 13 simulations: up to 6 Hypothesis examples, 4 seeded years, and 3 net-subtotal twins. #9903's updated property file took 21.4 s and 2.42 GB; the change adds two variables to one test. Both files run in Rest shard 1's remaining group. On run 38945181819 (2026-10-16, Linux) that group took 16:40 wall time at 8.09 GB peak RSS. That figure is the existing group's, not a measurement of this addition, and no new job or worker was added.

The hub shell rerun uses macOS, Python 3.13.9 and core 3.33.2: 5 passed in 48.47 s, 104.68 s wall including interpreter startup. Peak RSS is unavailable because the sandbox rejects the timing wrapper's kernel resource query; the wrapper exited 1 after pytest passed. There is no comparable before measurement in this environment. The payer correction adds assertions to the existing batches and creates no additional simulations.

Not modeled (no PE inputs)

  • Premiums paid from an HSA or a Montana medical care savings account.
  • The Montana Subtractions Schedule line 11.
  • Part D premiums, beyond what a user puts in health_insurance_premiums.
  • The 2021-only exclusion for premiums claimed under the Elderly Care Credit, which PE doesn't model.
  • Dependents' medical expenses on returns filed separately on the same form. _indiv counts each spouse's own amounts, as before.
  • The insured's identity and age are not separately represented by the payer-attributed premium inputs. Coverage paid by a parent belongs on the paying parent's input; dependents' own payments do not enter the filers' lines 2–3.

Follow-ups (outside this PR)

Reviews

  • Round 1 (Opus, at 664331b): REQUEST CHANGES (five P2s, two P3s), answered in round 2.
  • Round 2 (GPT-6.1 Sol, at 595cd1e): REQUEST CHANGES, answered here.
    • Tax-unit-only self-employed deduction lost on joint returns: fixed by mt_premium_deduction_joint.
    • Household 5 put an age-ineligible long-term care amount in the deduction: corrected.
    • Invariants docstring lacked the dependent qualification: added.
    • The report confirmed all 29 YAML expectations against the form lines and the round-1 fixes.
  • Round 3 (GPT-6.1 Sol, at b320855): REQUEST CHANGES, answered here.
    • A supplied itemized_medical_expenses subtotal was dropped from line 1 (R3-1, P2): fixed, with two YAML cases.
    • Two claims in mt_premium_deduction_joint's documentation were narrowed (R3-2, P3).
    • The report confirmed the round-2 fixes and all 36 YAML expectations.
  • Round 4 (GPT-6.1 Sol, at f5e977b): REQUEST CHANGES.
    • A supplied subtotal that includes long-term care premiums had them deducted again on line 3 (R4-1).
    • Draft wording (R4-2).
  • Round 5 (GPT-6.1 Sol, at 7fdca0c): REQUEST CHANGES on that round's fix.
    • Inferring the long-term care premiums inside a supplied subtotal from the premium input fails when the self-employed deduction took them (R5-1).
    • The age-based limit used the payer's age rather than the insured's (R5-2).
    • The supplied-subtotal contract was undocumented (R5-3).
    • All answered here by the explicit input and the documentation on itemized_medical_expenses.
  • Round 6 (at f9204be): REQUEST CHANGES. A net Schedule A subtotal had its self-employed premiums removed twice (R6-1). Fixed by documenting the override of itemized_medical_expenses_applied_exclusion.
  • Round 7 (at e63e73a): REQUEST CHANGES. That override couldn't serve North Dakota, New Mexico and Montana at once when the deduction covered long-term care too (R7-1). Fixed: Montana removes only the medical premiums still in the subtotal.
  • Round 8 (at 96d2f72): REQUEST CHANGES. A supplied exclusion above the filers' medical premiums was taken from dependents' premiums (F1). Fixed by bounding it by the filers' premiums. Documentation and cases were added (F2–F5), plus differential property 9.
  • Round 9 (at 1b0a771): REQUEST CHANGES. The seeded test referenced an undefined units, so property 9 never ran (P1). Fixed in bf1661d; the reviewer found no remaining policy blocker. The live body was stale (P3); refreshed here.
  • Round 10: GPT-6.1 Sol at bf1661d: APPROVE WITH NITS, with no code or policy blocker. The nit was this body's line 1 formula, now corrected. Reports are in ~/reviews/mt-medical-premiums-2026-10-06/review-r*.md.

Review (hub shell review): response

The GPT-6.1 Sol shell review at bf1661d identified a P2 payer-attribution error: the joint formula added dependents' own premiums to the filers' deduction. Former MCA § 15-30-2131(1)(g) allows payments made by the taxpayer. The fix at 715ac2c counts only the head's and spouse's payer-attributed premiums. The separate formula already restricts claims to the head and spouse and needs no production change.

  • The new 2022 regression has a dependent personally paying $1,000 of qualified long-term-care premiums, no filer premiums and no self-employed deduction. Before the fix, the joint deduction returned $1,000 instead of $0; the joint file reported 1 failed, 28 passed. The regression checks the joint deduction, joint premium helper and separate deduction.
  • Corrected the older dependent-premium YAML expectations: joint $4,200 → $3,000; supplied-exclusion joint $8,000 → $7,000 and premium helper $1,000 → $0; the joint premium helper case $3,100 → $3,000. Updated the invariant closed forms and premium-increase expectations to exclude dependent-paid premiums.
  • Federal itemized_medical_expenses, New Mexico's medical expense credit and exemption, and North Dakota's renters-refund income reader formulas are unchanged against both the original base 5ec60b2 and current main 83e03a9; the AST audit passed.
  • Merged current gh/main 83e03a9 cleanly in 9119ab8 before applying the payer fix.
  • Foreground file results at 715ac2c (Python 3.13.9, core 3.33.2, Hypothesis 6.168.5; one file per process, all five thread caps at 4): mt_medical_expense_deduction_joint.yaml 29 passed; mt_medical_expense_deduction_indiv.yaml 10 passed; nm_medical_expense_credit.yaml 24 passed; test_mt_medical_premium_deduction_invariants.py 5 passed; federal medical_expense_deduction.yaml 11 passed; additionally, the modified mt_premium_deduction_joint.yaml 6 passed. make format and git diff --check passed.
  • Draft Count eligible long-term care premiums in Schedule A medical expenses #10265 must update invariant properties 6 and 9 and reconcile payer versus insured attribution when it lands after this PR. The hub reruns impact at the new head because the saved impact files name older heads.

axiom: TheAxiomFoundation/rulespec-us#1528 queued (former MCA § 15-30-2131(1)(g), Itemized Deductions Schedule lines 2–3, TY2021–2023; the signed encoder is blocked because the pinned corpus has § 15-30-2131 only as a repeal marker and no 2021–2023 Form 2 scope; sibling of #1520, which covers line 1)

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 6, 2026 11:06
…eturn's Montana AGI

The 2021-2023 Form 2 Itemized Deductions Schedule (line 1b) and Standard
Deduction Worksheet (line 1) take Montana AGI from page 1, line 14. Single,
head of household and joint returns report that line in one column, so a
joint return pools both spouses' income before flooring at zero. Both
joint-path variables instead summed each spouse's mt_agi_indiv, which floors
each spouse at zero first, so a spouse's loss never offset the other's
income. They now use mt_agi_joint.

From 2024 mt_agi_indiv is switched off (Montana repealed filing separately
on the same form), so the joint medical floor fell to zero and the full
medical expense was deducted. From 2024 Form 2 line 2 takes federal
itemized deductions (Worksheet A), so the variable now carries the federal
medical expense deduction (7.5% of federal AGI). A new parameter,
gov.states.mt.tax.income.deductions.itemized.state_specific_deduction_applies,
marks the switch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s in full

For TY2021-2023 the Form 2 Itemized Deductions Schedule floors only line 1,
medical and dental expenses other than premiums, at 7.5% of Montana AGI.
Line 2 deducts medical insurance premiums in full, except premiums already
deducted in Montana AGI (the self-employed health insurance deduction) and
pre-tax premiums; line 3 deducts long-term care insurance premiums in full
(former MCA 15-30-2131(1)(a)(iii)-(iv) and (1)(g)).

- New mt_eligible_medical_insurance_premiums (person): federal medical
  expense premiums, including Medicare Part B, less the person's
  self-employed health insurance deduction.
- mt_medical_expense_deduction_joint (2021-2023) and _indiv: line 1 floored
  on Montana AGI, plus lines 2 and 3 in full. From 2024 the joint variant
  keeps the federal medical expense deduction.

Fixes #9930. Stacked on #9903.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 6, 2026 18:41
The 2021-2023 property now expects max(0, other expenses - 7.5% of Montana
AGI) plus line 2 and 3 premiums. The grid's age-70 single filers carry
modeled Medicare Part B premiums, which the schedule deducts in full.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 7 commits October 11, 2026 06:25
…iums-in-full

# Conflicts:
#	policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_medical_expense_deduction_joint.yaml
#	policyengine_us/tests/unit/test_mt_joint_agi_deductions_properties.py
#	policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/medical/mt_medical_expense_deduction_joint.py
…nto fix-mt-medical-premiums-in-full

# Conflicts:
#	policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_medical_expense_deduction_indiv.yaml
#	policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_medical_expense_deduction_joint.yaml
#	policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/medical/mt_medical_expense_deduction_indiv.py
- Line 2 reuses #10055's per-person excluded premiums; the new line 3
  variable nets the remainder of the self-employed deduction from
  long-term care premiums (26 U.S.C. 162(l)(2)(C) lets those premiums
  into that deduction).
- The separate-filing variant applies lines 2 and 3 only while the
  Itemized Deductions Schedule applies; a reform that allows separate
  filing after 2023 keeps premiums under the floor.
- Tests: supply the self-employed deduction where its earnings limit
  matters, a below-floor dependent case, #10055's Montana cases moved to
  lines 1-3, and invariants for premium conservation and #10055's
  applied exclusion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 12 commits October 18, 2026 12:29
…iums-in-full

# Conflicts:
#	policyengine_us/tests/core/test_medical_expense_premium_conservation.py
#	policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_medical_expense_deduction_joint.yaml
#	policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_medical_expense_deduction_indiv.yaml
#	policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/deductions/itemized/mt_medical_expense_deduction_joint.yaml
#	policyengine_us/tests/policy/baseline/gov/states/nc/tax/income/deductions/nc_itemized_deductions.yaml
#	policyengine_us/tests/policy/baseline/gov/states/nd/tax/property/renters_refund/nd_renters_refund_income.yaml
#	policyengine_us/tests/policy/baseline/gov/states/nj/tax/income/deductions/nj_medical_expense_deduction.yaml
#	policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_medical_expense_credit.yaml
#	policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.yaml
#	policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/medical/mt_medical_expense_deduction_indiv.py
#	policyengine_us/variables/gov/states/nd/tax/property/renters_refund/nd_renters_refund_income.py
#	policyengine_us/variables/gov/states/nj/tax/income/deductions/nj_medical_expense_deduction.py
#	policyengine_us/variables/gov/states/nm/tax/income/credits/nm_medical_expense_credit.py
#	policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The r2 review found the joint 2021-2023 path read only person-level
self-employed health insurance deductions, so a deduction supplied for
the return (as #10055's federal Schedule A exclusion honors) was lost.
New mt_premium_deduction_joint nets the return's deduction from the
head's and spouse's premiums, medical premiums first (the same exclusion
as Schedule A) and the rest from long-term care premiums; dependents net
their own deductions. Invariants now check the pooled closed form, draw
return-level deductions, and qualify the dependent payer boundary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A bare state_code in a situation is not applied to the run year, so every
generated return fell back to the default state and the Montana outputs
were zero. Key it by year and assert every return is in Montana.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core treats a formula variable supplied for some members as an input for
all of them and fills the rest with 0, so mixing supplied and derived
deductions in one batch zeroed the return deduction of returns that did
not supply one. Each batch now derives the deduction, supplies it for
every person, or supplies it for every return; slope twins, the
single-filer differential and the seeded non-vacuity checks follow the
mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The r3 review found the joint 2021-2023 line 1 read only primitive other
medical expenses, so a supplied itemized_medical_expenses subtotal was
lost ($10,000 at $40,000 AGI gave $0, not $7,000). Line 1 now starts from
the federal subtotal, restores the exclusion its formula applied (zero
for a supplied subtotal, as North Dakota and New Mexico use it after
#10055), and takes out every member's premiums; for a computed subtotal
that is the members' other medical expenses. Also narrow two claims in
mt_premium_deduction_joint's documentation.

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

The r4 review found a supplied itemized_medical_expenses subtotal that
legally includes eligible long-term care premiums (26 U.S.C.
213(d)(1)(D), (d)(10)) had them deducted again on Montana line 3.
- New parameter gov.irs.deductions.itemized.medical.long_term_care_premium_limit:
  the 213(d)(10) age-based limits for 2021-2026 from Rev. Procs. 2020-45,
  2021-45, 2022-38, 2023-34, 2024-40 and 2025-32 (band tops, right=True).
- New eligible_long_term_care_premiums (person) = min(premiums, limit).
- New itemized_medical_expenses_long_term_care_premiums (tax unit): the
  eligible premiums inside the subtotal, zero for the computed subtotal
  (which counts none yet) and the members' eligible premiums for a
  supplied one.
- Montana's line 1 base subtracts it, so line 3 deducts those premiums
  once, in full.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The r5 review found that inferring the long-term care premiums inside a
supplied itemized_medical_expenses from the premium input fails when the
self-employed deduction took them (162(l)(2)(C), (l)(3)) and uses the
payer's age rather than the insured's. Replace the inference with a pure
input, itemized_medical_expenses_long_term_care_premiums (default 0: a
supplied subtotal has the computed subtotal's contents), and document the
supplied-subtotal contract on itemized_medical_expenses. Remove the
213(d)(10) parameter and eligible_long_term_care_premiums, which nothing
uses now; the federal long-term care follow-up adds them with insured-age
attribution.

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

The r6 review found a supplied Schedule A subtotal that already leaves
out self-employed premiums had them removed again from Montana line 1.
A supplied subtotal is taken as medical costs paid by default (as North
Dakota and New Mexico use it); a net Schedule A amount now comes with
its excluded premiums in itemized_medical_expenses_applied_exclusion,
which every consumer (federal, ND, NM, MT) then reads consistently.
Document this on itemized_medical_expenses and the applied exclusion,
and add net-subtotal YAML cases with person- and return-level
deductions beside the gross-cost case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The r7 review found the applied-exclusion override could not serve every
consumer when the self-employed deduction also covered long-term care
premiums: North Dakota and New Mexico restore the full exclusion to get
costs paid, while Montana must not treat the long-term care part as
other expenses. Montana's line 1 base now removes only the medical
premiums still in the subtotal, max(0, premiums - exclusion), with the
exclusion taken from medical premiums first as the computed formula
does. A supplied override is all premiums the self-employed deduction
took. Document this on the federal variables and on the North Dakota and
New Mexico consumers, and test the same net composition in all three.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The r8 review found that a supplied exclusion above the head's and
spouse's medical premiums (its long-term care part) was taken from
dependents' premiums too, so Montana line 1 kept them while line 2
deducted them. Take only min(filer premiums, exclusion) off the members'
premiums, matching the federal bound; computed subtotals are unchanged.
Also document that the long-term care input follows the same medical-first
split, qualify itemized_medical_expenses_excluded_premiums, add the
regression, partial-deduction and New Mexico credit cases, and add a
differential invariant: a net Schedule A subtotal supplied with its
exclusion gives the computed path's Montana deduction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 18, 2026 18:28
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Hand-off to the US + core hub (owner session local_117896e0 / 7ed8a0f9).

@MaxGhenis
MaxGhenis merged commit 8ddd925 into main Oct 19, 2026
27 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#9947 at 715ac2cd7757206426651ec0cd27cd571b1f5eee (squash): Deduct Montana's 2021–2023 medical and long-term care insurance premiums in full (Itemized Deductions Schedule lines 2–3).

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.

Deduct Montana 2021–2023 medical and long-term care insurance premiums in full (Itemized Deductions Schedule lines 2–3)

1 participant