From bdcd44ff7bdd646dddd8744d9095f8197d0d403d Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 8 Jul 2026 15:39:08 -0400 Subject: [PATCH 1/2] Cap MT 2021 income tax rebate at liability per MCA 15-30-2191(2)(b) The variable returned the flat filing-status amount (1,250/2,500) for every MT filer in every year >= 2021, ignoring the statutory cap (lesser of the amount or the taxpayer's income tax liability) and the rebate's 2021-only scope. Montana income tax results are unchanged - the credit application already floored the applied amount - but the variable's reported value was wrong for low-liability filers and for 2022+ (it produced phantom amounts in the TAXSIM-comparison srebate work). Cap at the smaller of the joint and separate-column pre-credit bases (the filing election itself is post-credit and would create a computation cycle), zero-scope the amounts from 2022, and replace the period-2023 no-income unit tests that encoded the uncapped values. Fixes #8958. Co-Authored-By: Claude Opus 4.8 --- ...t-income-tax-rebate-liability-cap.fixed.md | 1 + .../mt/tax/income/credits/rebate/amount.yaml | 7 +- .../credits/rebate/mt_income_tax_rebate.yaml | 99 ++++++++++++++++--- .../credits/rebate/mt_income_tax_rebate.py | 20 +++- 4 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 changelog.d/mt-income-tax-rebate-liability-cap.fixed.md diff --git a/changelog.d/mt-income-tax-rebate-liability-cap.fixed.md b/changelog.d/mt-income-tax-rebate-liability-cap.fixed.md new file mode 100644 index 00000000000..27e423f3929 --- /dev/null +++ b/changelog.d/mt-income-tax-rebate-liability-cap.fixed.md @@ -0,0 +1 @@ +Cap the Montana 2021 income tax rebate at the taxpayer's pre-credit liability per MCA 15-30-2191(2)(b) and zero the amounts from 2022, fixing the variable's reported value; Montana income tax results are unchanged because the credit application already floored the applied amount. diff --git a/policyengine_us/parameters/gov/states/mt/tax/income/credits/rebate/amount.yaml b/policyengine_us/parameters/gov/states/mt/tax/income/credits/rebate/amount.yaml index 323de1b3ef6..21df70439f9 100644 --- a/policyengine_us/parameters/gov/states/mt/tax/income/credits/rebate/amount.yaml +++ b/policyengine_us/parameters/gov/states/mt/tax/income/credits/rebate/amount.yaml @@ -11,11 +11,16 @@ metadata: SINGLE: 2021-01-01: 1_250 + 2022-01-01: 0 HEAD_OF_HOUSEHOLD: 2021-01-01: 1_250 + 2022-01-01: 0 JOINT: 2021-01-01: 2_500 + 2022-01-01: 0 SURVIVING_SPOUSE: 2021-01-01: 2_500 + 2022-01-01: 0 SEPARATE: - 2021-01-01: 1_250 + 2021-01-01: 1_250 + 2022-01-01: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.yaml index f8b22b4ca3f..ca636239855 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.yaml @@ -1,23 +1,98 @@ -- name: Single filer - period: 2023 +- name: Single filer with liability above the rebate amount + period: 2021 input: - filing_status: SINGLE - state_code: MT + people: + person1: + age: 45 + employment_income: 50_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MT output: mt_income_tax_rebate: 1_250 -- name: Joint filers - period: 2023 +- name: Joint filers with liability above the rebate amount + period: 2021 input: - filing_status: JOINT - state_code: MT + people: + person1: + age: 45 + employment_income: 60_000 + person2: + age: 45 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT output: mt_income_tax_rebate: 2_500 -- name: Not in Montana - period: 2023 +- name: Rebate is capped at the income tax liability (MCA 15-30-2191(2)(b)) + absolute_error_margin: 1 + period: 2021 input: - filing_status: JOINT - state_code: AR + people: + person1: + age: 45 + employment_income: 20_000 + person2: + age: 45 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MT + output: + # Lesser of $2,500 or the pre-credit liability, not the flat amount. + # (Montana's credit application already floors the applied credit, so + # this fixes the variable's reported value, not the tax outcome.) + mt_income_tax_rebate: 252.40 + +- name: No rebate outside Montana + period: 2021 + input: + people: + person1: + age: 45 + employment_income: 50_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AR + output: + mt_income_tax_rebate: 0 + +- name: No rebate in 2022 + period: 2022 + input: + people: + person1: + age: 45 + employment_income: 50_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MT output: mt_income_tax_rebate: 0 diff --git a/policyengine_us/variables/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.py b/policyengine_us/variables/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.py index 031e5cd790f..33351f4caac 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.py @@ -10,8 +10,24 @@ class mt_income_tax_rebate(Variable): reference = "https://archive.legmt.gov/bills/mca/title_0150/chapter_0300/part_0210/section_0910/0150-0300-0210-0910.html" defined_for = StateCode.MT - # The rebate is based on 2021 income tax liability, but provided in 2023 + # The rebate is based on 2021 income tax liability, but provided in 2023. + # MCA 15-30-2191(2)(b): the rebate is the LESSER of the filing-status + # amount or the taxpayer's income tax liability, so it can not drive the + # liability negative. Montana elects the lower of the joint and + # separate-column computations, but that election + # (mt_files_separately) depends on post-credit liability and would + # create a computation cycle here, so cap at the smaller of the two + # pre-credit bases — never larger than the elected one. def formula(tax_unit, period, parameters): p = parameters(period).gov.states.mt.tax.income.credits.rebate filing_status = tax_unit("filing_status", period) - return p.amount[filing_status] + liability_indiv = add( + tax_unit, + period, + ["mt_income_tax_before_non_refundable_credits_indiv"], + ) + liability_joint = tax_unit( + "mt_income_tax_before_non_refundable_credits_joint", period + ) + liability = min_(liability_indiv, liability_joint) + return min_(p.amount[filing_status], max_(liability, 0)) From dd53545ab924a237c1f95614cc985b2bfaf09ee3 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Thu, 27 Aug 2026 01:17:10 +0200 Subject: [PATCH 2/2] Correct the 2022 guard's rationale: the fix is the reported value, not the tax The earlier comment claimed the leaked $1,250 would cut 2022 Montana tax from $2,246 to $996. That is wrong, and verified so by counterfactual: credits/non_refundable.yaml already drops mt_income_tax_rebate from the list at 2022-01-01, so removing the amount.yaml sunset leaves mt_non_refundable_credits at 0 and mt_income_tax at 2,246 unchanged - only mt_income_tax_rebate itself moves, 0 -> 1,250. The discriminating assertion is therefore the rebate variable alone; the tax and credit-aggregate pins are unchanged controls, and the changelog now scopes the fix to the reported value that mis-feeds consumers such as the TAXSIM srebate comparison. Co-Authored-By: Claude Opus 5 --- changelog.d/fix-mt-rebate-wiring.fixed.md | 2 +- .../income/credits/rebate/mt_income_tax_rebate.yaml | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/changelog.d/fix-mt-rebate-wiring.fixed.md b/changelog.d/fix-mt-rebate-wiring.fixed.md index 6b3c25ddcb7..76f6ec3aa65 100644 --- a/changelog.d/fix-mt-rebate-wiring.fixed.md +++ b/changelog.d/fix-mt-rebate-wiring.fixed.md @@ -1 +1 @@ -Scope the Montana 2021 income tax rebate to its eligibility year, removing the phantom rebate credit that applied in 2022 and later. +Correct the Montana 2021 income tax rebate's reported value outside its eligibility year: without the 2022 sunset the amount backdates forward, so the variable reported a phantom rebate in 2022 and later. Montana income tax is unaffected, as the non-refundable credit list already excludes the rebate from 2022. diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.yaml index ba481ac23c2..738e667816b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/rebate/mt_income_tax_rebate.yaml @@ -95,7 +95,7 @@ output: mt_income_tax_rebate: [0] -- name: No rebate in 2022, and no phantom credit against 2022 tax +- name: No phantom rebate value in 2022 period: 2022 absolute_error_margin: 0.01 input: @@ -111,9 +111,16 @@ members: [person1] state_code: MT output: + # This is the discriminating assertion: without amount.yaml's 2022 + # zeroing, backdating fills the 2021 amount forward and this reads + # 1_250. Montana tax is NOT affected either way, because + # credits/non_refundable.yaml already drops mt_income_tax_rebate from + # the list at 2022-01-01 - so the defect is the variable's reported + # value, which mis-feeds consumers such as the TAXSIM srebate + # comparison, not the tax outcome. mt_income_tax and + # mt_non_refundable_credits are pinned here as unchanged controls. mt_income_tax_rebate: [0] mt_non_refundable_credits: [0] - # Without the 2022 zeroing the leaked $1,250 would cut this to 996.00 mt_income_tax: 2_246.00 - name: No rebate in 2023, the year the rebate was actually paid out