From 4f52a819a44637b9955165f8f666f98bcab0a150 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 8 Apr 2026 19:55:58 -0400 Subject: [PATCH 1/4] Add Minnesota renter's credit --- changelog.d/add-mn-renters-credit.fixed.md | 1 + .../household/state_property_tax_credits.yaml | 20 ++ .../mn/tax/income/credits/refundable.yaml | 5 + .../credits/renters/claimant_share.yaml | 129 ++++++++ .../income/credits/renters/max_credit.yaml | 289 ++++++++++++++++++ .../credits/renters/percent_of_income.yaml | 140 +++++++++ .../income/credits/renters/rent_fraction.yaml | 14 + .../mn_rent_constituting_property_taxes.yaml | 8 + .../tax/income/credits/mn_renters_credit.yaml | 55 ++++ .../mn_renters_credit_household_income.yaml | 48 +++ .../states/mn/tax/income/mn_integration.yaml | 30 ++ .../mn_rent_constituting_property_taxes.py | 20 ++ .../tax/income/credits/mn_renters_credit.py | 48 +++ .../mn_renters_credit_crp_line_a_amount.py | 12 + .../credits/mn_renters_credit_eligible.py | 33 ++ .../mn_renters_credit_household_income.py | 54 ++++ .../mn_renters_credit_nonresident_income.py | 12 + ...renters_credit_seiu_stipend_subtraction.py | 12 + .../credits/mn_renters_credit_spouse_agi.py | 12 + 19 files changed, 942 insertions(+) create mode 100644 changelog.d/add-mn-renters-credit.fixed.md create mode 100644 policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/claimant_share.yaml create mode 100644 policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/max_credit.yaml create mode 100644 policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/percent_of_income.yaml create mode 100644 policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/rent_fraction.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_crp_line_a_amount.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_eligible.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_nonresident_income.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_spouse_agi.py diff --git a/changelog.d/add-mn-renters-credit.fixed.md b/changelog.d/add-mn-renters-credit.fixed.md new file mode 100644 index 00000000000..26b7e0df4ae --- /dev/null +++ b/changelog.d/add-mn-renters-credit.fixed.md @@ -0,0 +1 @@ +Implemented Minnesota's renter's credit under Minn. Stat. ยง290.0693 for tax year 2024 onward, including household-income adjustments, rent constituting property taxes, refundable credit integration, and TAXSIM state property tax credit coverage. diff --git a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml index b5c719c31cf..b0346611bd8 100644 --- a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml +++ b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml @@ -114,6 +114,26 @@ values: - wi_homestead_credit - wi_property_tax_credit - wv_homestead_excess_property_tax_credit + 2024-01-01: + - az_property_tax_credit + - ct_property_tax_credit + - dc_ptc + - il_property_tax_credit + - ma_senior_circuit_breaker + - me_property_tax_fairness_credit + - mi_homestead_property_tax_credit + - mn_renters_credit + - mo_property_tax_credit + - mt_elderly_homeowner_or_renter_credit + - mt_property_tax_rebate + - nj_property_tax_credit + - nm_property_tax_rebate + - ny_real_property_tax_credit + - ok_ptc + - ri_property_tax_credit + - wi_homestead_credit + - wi_property_tax_credit + - wv_homestead_excess_property_tax_credit metadata: unit: list diff --git a/policyengine_us/parameters/gov/states/mn/tax/income/credits/refundable.yaml b/policyengine_us/parameters/gov/states/mn/tax/income/credits/refundable.yaml index 5d545b0d81b..40f6ff555e6 100644 --- a/policyengine_us/parameters/gov/states/mn/tax/income/credits/refundable.yaml +++ b/policyengine_us/parameters/gov/states/mn/tax/income/credits/refundable.yaml @@ -9,6 +9,11 @@ values: - mn_cdcc - mn_child_and_working_families_credits # Minnesota child and working families tax credit - mn_k12_education_credit + 2024-01-01: + - mn_cdcc + - mn_child_and_working_families_credits + - mn_k12_education_credit + - mn_renters_credit metadata: unit: list diff --git a/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/claimant_share.yaml b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/claimant_share.yaml new file mode 100644 index 00000000000..63ed7642519 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/claimant_share.yaml @@ -0,0 +1,129 @@ +description: Minnesota renter's credit claimant share of excess rent constituting property taxes by household income. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + period: year + label: Minnesota renter's credit claimant share + reference: + - title: Minnesota Statutes 290.0693, Subd. 3 + href: https://www.revisor.mn.gov/statutes/cite/290.0693/pdf + - title: 2025 Schedule M1RENT, Renter's Credit + href: https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf + +brackets: + - threshold: + 2024-01-01: 0 + amount: + 2024-01-01: 0.05 + - threshold: + values: + 2024-01-01: 6_480 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.10 + - threshold: + values: + 2024-01-01: 15_090 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.15 + - threshold: + values: + 2024-01-01: 21_540 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.20 + - threshold: + values: + 2024-01-01: 30_160 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.25 + - threshold: + values: + 2024-01-01: 36_630 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.30 + - threshold: + values: + 2024-01-01: 45_230 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.35 + - threshold: + values: + 2024-01-01: 51_690 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.40 + - threshold: + values: + 2024-01-01: 60_320 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.45 + - threshold: + values: + 2024-01-01: 66_790 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.50 + - threshold: + values: + 2024-01-01: 75_390 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 1.0 + diff --git a/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/max_credit.yaml b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/max_credit.yaml new file mode 100644 index 00000000000..89dd496b0d5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/max_credit.yaml @@ -0,0 +1,289 @@ +description: Minnesota renter's credit maximum amount by household income. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: currency-USD + period: year + label: Minnesota renter's credit maximum amount + reference: + - title: Minnesota Statutes 290.0693, Subd. 3 + href: https://www.revisor.mn.gov/statutes/cite/290.0693/pdf + - title: 2025 Schedule M1RENT, Renter's Credit + href: https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf + +brackets: + - threshold: + 2024-01-01: 0 + amount: + values: + 2024-01-01: 2_640 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 8_610 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 2_570 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 10_760 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 2_510 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 15_090 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 2_430 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 19_400 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 2_370 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 21_540 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 2_310 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 23_680 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 2_240 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 28_010 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 2_180 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 60_320 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 1_980 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 62_460 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 1_780 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 64_620 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 1_510 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 66_790 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 1_320 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 68_930 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 1_190 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 71_090 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 660 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 73_240 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + values: + 2024-01-01: 260 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + - threshold: + values: + 2024-01-01: 75_390 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0 + diff --git a/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/percent_of_income.yaml b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/percent_of_income.yaml new file mode 100644 index 00000000000..8d8dedf66b0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/percent_of_income.yaml @@ -0,0 +1,140 @@ +description: Minnesota renter's credit household-income percentage by household income. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + period: year + label: Minnesota renter's credit percent of income + reference: + - title: Minnesota Statutes 290.0693, Subd. 3 + href: https://www.revisor.mn.gov/statutes/cite/290.0693/pdf + - title: 2025 Schedule M1RENT, Renter's Credit + href: https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf + +brackets: + - threshold: + 2024-01-01: 0 + amount: + 2024-01-01: 0.010 + - threshold: + values: + 2024-01-01: 8_610 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.011 + - threshold: + values: + 2024-01-01: 10_760 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.012 + - threshold: + values: + 2024-01-01: 15_090 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.013 + - threshold: + values: + 2024-01-01: 19_400 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.014 + - threshold: + values: + 2024-01-01: 23_680 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.015 + - threshold: + values: + 2024-01-01: 28_010 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.016 + - threshold: + values: + 2024-01-01: 30_160 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.017 + - threshold: + values: + 2024-01-01: 32_310 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.018 + - threshold: + values: + 2024-01-01: 36_630 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.019 + - threshold: + values: + 2024-01-01: 38_770 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0.020 + - threshold: + values: + 2024-01-01: 75_390 + metadata: + uprating: + parameter: gov.irs.uprating + rounding: + type: nearest + interval: 10 + amount: + 2024-01-01: 0 + diff --git a/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/rent_fraction.yaml b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/rent_fraction.yaml new file mode 100644 index 00000000000..4ac479f3d44 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/rent_fraction.yaml @@ -0,0 +1,14 @@ +description: Minnesota treats this fraction of gross rent as rent constituting property taxes for the renter's credit. +values: + 2024-01-01: 0.17 + +metadata: + period: year + unit: /1 + label: Minnesota renter's credit rent fraction + reference: + - title: Minnesota Statutes 290.0693, Subd. 1(j) + href: https://www.revisor.mn.gov/statutes/cite/290.0693 + - title: 2025 Schedule M1RENT, Renter's Credit + href: https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf + diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.yaml new file mode 100644 index 00000000000..77740d11a19 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.yaml @@ -0,0 +1,8 @@ +- name: Rent constituting property taxes equals 17 percent of gross rent + period: 2025 + input: + state_code: MN + rent: 10_000 + output: + mn_rent_constituting_property_taxes: 1_700 + diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml new file mode 100644 index 00000000000..e9996ff4938 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml @@ -0,0 +1,55 @@ +- name: Standard Minnesota renter's credit case + absolute_error_margin: 10 + period: 2025 + input: + people: + person1: + age: 40 + employment_income: 50_000 + rent: 10_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + premium_tax_credit: 0 + families: + family: + members: [person1] + spm_units: + spm_unit: + members: [person1] + snap: 0 + tanf: 0 + households: + household: + members: [person1] + state_fips: 27 + output: + mn_renters_credit: 455 + +- name: CRP line A amount prorates the renter's credit + absolute_error_margin: 1 + period: 2025 + input: + people: + person1: + age: 40 + employment_income: 20_000 + rent: 10_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + mn_renters_credit_crp_line_a_amount: 5_000 + families: + family: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_renters_credit: 965.60004 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml new file mode 100644 index 00000000000..300d4867203 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml @@ -0,0 +1,48 @@ +- name: Household income starts from Minnesota AGI and subtracts renter credit adjustments + period: 2025 + input: + people: + person1: + age: 66 + is_tax_unit_head: true + dependent1: + is_tax_unit_dependent: true + dependent2: + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, dependent1, dependent2] + adjusted_gross_income: 50_000 + mn_additions: 1_000 + mn_subtractions: 500 + households: + household: + members: [person1, dependent1, dependent2] + state_code: MN + output: + mn_renters_credit_household_income: 31_260 + +- name: Part-year and MFS adjustments reduce household income + period: 2025 + input: + people: + person1: + is_tax_unit_head: true + dependent1: + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, dependent1] + adjusted_gross_income: 40_000 + mn_additions: 0 + mn_subtractions: 0 + mn_renters_credit_spouse_agi: 20_000 + mn_renters_credit_nonresident_income: 15_000 + mn_renters_credit_seiu_stipend_subtraction: 1_000 + households: + household: + members: [person1, dependent1] + state_code: MN + output: + mn_renters_credit_household_income: 36_720 + diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/mn_integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/mn_integration.yaml index e444521a059..afe2a734204 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/mn_integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/mn_integration.yaml @@ -121,3 +121,33 @@ state_fips: 27 output: mn_income_tax: -2_119 + +- name: Minnesota renters credit integrates into refundable credits + absolute_error_margin: 10 + period: 2025 + input: + people: + person1: + age: 40 + employment_income: 50_000 + rent: 10_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + premium_tax_credit: 0 + families: + family: + members: [person1] + spm_units: + spm_unit: + members: [person1] + snap: 0 + tanf: 0 + households: + household: + members: [person1] + state_fips: 27 + output: + mn_renters_credit: 455 + mn_refundable_credits: 455 diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.py new file mode 100644 index 00000000000..05f2ce3bc97 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class mn_rent_constituting_property_taxes(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota rent constituting property taxes" + unit = USD + definition_period = YEAR + reference = ( + "https://www.revisor.mn.gov/statutes/cite/290.0693", + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf", + ) + defined_for = StateCode.MN + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.mn.tax.income.credits.renters + rent = add(tax_unit, period, ["rent"]) + return rent * p.rent_fraction + diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py new file mode 100644 index 00000000000..71c7910f50a --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py @@ -0,0 +1,48 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota renter's credit" + unit = USD + definition_period = YEAR + reference = ( + "https://www.revisor.mn.gov/statutes/cite/290.0693", + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf", + "https://www.revenue.state.mn.us/sites/default/files/2025-12/m1ref-25.pdf", + ) + defined_for = StateCode.MN + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.mn.tax.income.credits.renters + household_income = tax_unit("mn_renters_credit_household_income", period) + rent_constituting_property_taxes = tax_unit( + "mn_rent_constituting_property_taxes", period + ) + eligible = tax_unit("mn_renters_credit_eligible", period) + + percent_of_income = p.percent_of_income.calc(household_income) + claimant_share = p.claimant_share.calc(household_income) + max_credit = p.max_credit.calc(household_income) + + excess_rent = max_( + 0, rent_constituting_property_taxes - percent_of_income * household_income + ) + credit_before_line_a = min_(max_credit, excess_rent * (1 - claimant_share)) + + crp_line_a_amount = tax_unit("mn_renters_credit_crp_line_a_amount", period) + total_household_basis = household_income + crp_line_a_amount + mask = total_household_basis != 0 + ratio = np.divide( + household_income, + total_household_basis, + out=np.zeros_like(total_household_basis), + where=mask, + ) + adjusted_credit = where( + crp_line_a_amount > 0, + credit_before_line_a * ratio, + credit_before_line_a, + ) + return eligible * adjusted_credit diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_crp_line_a_amount.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_crp_line_a_amount.py new file mode 100644 index 00000000000..3f3c7e748d9 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_crp_line_a_amount.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_crp_line_a_amount(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota renter's credit CRP line A amount" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.MN + diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_eligible.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_eligible.py new file mode 100644 index 00000000000..a9d9bafcbc7 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_eligible.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_eligible(Variable): + value_type = bool + entity = TaxUnit + label = "Eligible for the Minnesota renter's credit" + definition_period = YEAR + reference = ( + "https://www.revisor.mn.gov/statutes/cite/290.0693", + "https://www.revenue.state.mn.us/sites/default/files/2025-12/m1ref-25.pdf", + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf", + ) + defined_for = StateCode.MN + + def formula(tax_unit, period, parameters): + household_income = tax_unit("mn_renters_credit_household_income", period) + rent_constituting_property_taxes = tax_unit( + "mn_rent_constituting_property_taxes", period + ) + p = parameters(period).gov.states.mn.tax.income.credits.renters + + claimants = tax_unit.members("is_tax_unit_head_or_spouse", period) + claimant_is_dependent = tax_unit.any( + claimants & tax_unit.members("is_tax_unit_dependent", period) + ) + + return ( + (rent_constituting_property_taxes > 0) + & ~claimant_is_dependent + & (p.max_credit.calc(household_income) > 0) + ) + diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py new file mode 100644 index 00000000000..2b5e3f2476a --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py @@ -0,0 +1,54 @@ +from policyengine_us.model_api import * + + +DEPENDENT_SUBTRACTION_MULTIPLIERS = np.array([0.0, 1.4, 2.7, 3.9, 5.0, 6.0]) + + +class mn_renters_credit_household_income(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota renter's credit household income" + unit = USD + definition_period = YEAR + reference = ( + "https://www.revisor.mn.gov/statutes/cite/290.0693", + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf", + ) + defined_for = StateCode.MN + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.mn.tax.income + mn_agi = ( + tax_unit("adjusted_gross_income", period) + + tax_unit("mn_additions", period) + - tax_unit("mn_subtractions", period) + ) + spouse_agi = tax_unit("mn_renters_credit_spouse_agi", period) + nonresident_income = tax_unit("mn_renters_credit_nonresident_income", period) + exemption_amount = p.exemptions.amount + + people = tax_unit.members + claimant = people("is_tax_unit_head_or_spouse", period) + is_age_eligible = people("age", period) >= 65 + is_disabled = people("is_permanently_and_totally_disabled", period) + age_or_disability_subtraction = tax_unit.any( + claimant & (is_age_eligible | is_disabled) + ) * exemption_amount + + dependent_count = tax_unit("tax_unit_dependents", period) + capped_dependent_count = min_(dependent_count, 5).astype(int) + dependent_subtraction = exemption_amount * DEPENDENT_SUBTRACTION_MULTIPLIERS[ + capped_dependent_count + ] + + seiu_subtraction = tax_unit( + "mn_renters_credit_seiu_stipend_subtraction", period + ) + subtractions = ( + nonresident_income + + age_or_disability_subtraction + + dependent_subtraction + + seiu_subtraction + ) + return max_(0, mn_agi + spouse_agi - subtractions) + diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_nonresident_income.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_nonresident_income.py new file mode 100644 index 00000000000..56c71fc224d --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_nonresident_income.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_nonresident_income(Variable): + value_type = float + entity = TaxUnit + label = "Income received while a nonresident of Minnesota for the renter's credit" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.MN + diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py new file mode 100644 index 00000000000..da336a3d79f --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_seiu_stipend_subtraction(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota renter's credit SEIU stipend subtraction" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.MN + diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_spouse_agi.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_spouse_agi.py new file mode 100644 index 00000000000..edd65dbb39b --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_spouse_agi.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_spouse_agi(Variable): + value_type = float + entity = TaxUnit + label = "Spouse AGI for Minnesota renter's credit married-filing-separately cases" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.MN + From 0c256371378aebd06c607078108db46e23c6b7f9 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 8 Apr 2026 20:03:24 -0400 Subject: [PATCH 2/4] Narrow Minnesota renter's credit scope --- .../dependent_subtraction_multiplier.yaml | 36 +++++++++++++++++++ .../tax/income/credits/mn_renters_credit.yaml | 27 -------------- .../mn_renters_credit_household_income.yaml | 25 ------------- .../tax/income/credits/mn_renters_credit.py | 19 ++-------- .../mn_renters_credit_crp_line_a_amount.py | 12 ------- .../mn_renters_credit_household_income.py | 24 ++++--------- .../mn_renters_credit_nonresident_income.py | 12 ------- ...renters_credit_seiu_stipend_subtraction.py | 12 ------- .../credits/mn_renters_credit_spouse_agi.py | 12 ------- 9 files changed, 44 insertions(+), 135 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/dependent_subtraction_multiplier.yaml delete mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_crp_line_a_amount.py delete mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_nonresident_income.py delete mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py delete mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_spouse_agi.py diff --git a/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/dependent_subtraction_multiplier.yaml b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/dependent_subtraction_multiplier.yaml new file mode 100644 index 00000000000..7062ada1297 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/dependent_subtraction_multiplier.yaml @@ -0,0 +1,36 @@ +description: Minnesota renter's credit dependent subtraction multiplier by number of dependents. +metadata: + label: Minnesota renter's credit dependent subtraction multiplier + type: single_amount + threshold_unit: person + amount_unit: /1 + period: year + reference: + - title: 2025 Schedule M1RENT, Household Income section + href: https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf + +brackets: + - threshold: + 2024-01-01: 0 + amount: + 2024-01-01: 0.0 + - threshold: + 2024-01-01: 1 + amount: + 2024-01-01: 1.4 + - threshold: + 2024-01-01: 2 + amount: + 2024-01-01: 2.7 + - threshold: + 2024-01-01: 3 + amount: + 2024-01-01: 3.9 + - threshold: + 2024-01-01: 4 + amount: + 2024-01-01: 5.0 + - threshold: + 2024-01-01: 5 + amount: + 2024-01-01: 6.0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml index e9996ff4938..8cd4e5388cb 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml @@ -26,30 +26,3 @@ state_fips: 27 output: mn_renters_credit: 455 - -- name: CRP line A amount prorates the renter's credit - absolute_error_margin: 1 - period: 2025 - input: - people: - person1: - age: 40 - employment_income: 20_000 - rent: 10_000 - is_tax_unit_head: true - tax_units: - tax_unit: - members: [person1] - mn_renters_credit_crp_line_a_amount: 5_000 - families: - family: - members: [person1] - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: MN - output: - mn_renters_credit: 965.60004 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml index 300d4867203..65534265bcd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml @@ -21,28 +21,3 @@ state_code: MN output: mn_renters_credit_household_income: 31_260 - -- name: Part-year and MFS adjustments reduce household income - period: 2025 - input: - people: - person1: - is_tax_unit_head: true - dependent1: - is_tax_unit_dependent: true - tax_units: - tax_unit: - members: [person1, dependent1] - adjusted_gross_income: 40_000 - mn_additions: 0 - mn_subtractions: 0 - mn_renters_credit_spouse_agi: 20_000 - mn_renters_credit_nonresident_income: 15_000 - mn_renters_credit_seiu_stipend_subtraction: 1_000 - households: - household: - members: [person1, dependent1] - state_code: MN - output: - mn_renters_credit_household_income: 36_720 - diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py index 71c7910f50a..0765ee6e2a2 100644 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py @@ -29,20 +29,5 @@ def formula(tax_unit, period, parameters): excess_rent = max_( 0, rent_constituting_property_taxes - percent_of_income * household_income ) - credit_before_line_a = min_(max_credit, excess_rent * (1 - claimant_share)) - - crp_line_a_amount = tax_unit("mn_renters_credit_crp_line_a_amount", period) - total_household_basis = household_income + crp_line_a_amount - mask = total_household_basis != 0 - ratio = np.divide( - household_income, - total_household_basis, - out=np.zeros_like(total_household_basis), - where=mask, - ) - adjusted_credit = where( - crp_line_a_amount > 0, - credit_before_line_a * ratio, - credit_before_line_a, - ) - return eligible * adjusted_credit + credit = min_(max_credit, excess_rent * (1 - claimant_share)) + return eligible * credit diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_crp_line_a_amount.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_crp_line_a_amount.py deleted file mode 100644 index 3f3c7e748d9..00000000000 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_crp_line_a_amount.py +++ /dev/null @@ -1,12 +0,0 @@ -from policyengine_us.model_api import * - - -class mn_renters_credit_crp_line_a_amount(Variable): - value_type = float - entity = TaxUnit - label = "Minnesota renter's credit CRP line A amount" - unit = USD - definition_period = YEAR - default_value = 0 - defined_for = StateCode.MN - diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py index 2b5e3f2476a..e762f7ef2fb 100644 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py @@ -1,9 +1,6 @@ from policyengine_us.model_api import * -DEPENDENT_SUBTRACTION_MULTIPLIERS = np.array([0.0, 1.4, 2.7, 3.9, 5.0, 6.0]) - - class mn_renters_credit_household_income(Variable): value_type = float entity = TaxUnit @@ -23,8 +20,6 @@ def formula(tax_unit, period, parameters): + tax_unit("mn_additions", period) - tax_unit("mn_subtractions", period) ) - spouse_agi = tax_unit("mn_renters_credit_spouse_agi", period) - nonresident_income = tax_unit("mn_renters_credit_nonresident_income", period) exemption_amount = p.exemptions.amount people = tax_unit.members @@ -36,19 +31,12 @@ def formula(tax_unit, period, parameters): ) * exemption_amount dependent_count = tax_unit("tax_unit_dependents", period) - capped_dependent_count = min_(dependent_count, 5).astype(int) - dependent_subtraction = exemption_amount * DEPENDENT_SUBTRACTION_MULTIPLIERS[ - capped_dependent_count - ] - - seiu_subtraction = tax_unit( - "mn_renters_credit_seiu_stipend_subtraction", period + dependent_subtraction_multiplier = p.credits.renters.dependent_subtraction_multiplier.calc( + dependent_count ) - subtractions = ( - nonresident_income - + age_or_disability_subtraction - + dependent_subtraction - + seiu_subtraction + dependent_subtraction = ( + exemption_amount * dependent_subtraction_multiplier ) - return max_(0, mn_agi + spouse_agi - subtractions) + subtractions = age_or_disability_subtraction + dependent_subtraction + return max_(0, mn_agi - subtractions) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_nonresident_income.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_nonresident_income.py deleted file mode 100644 index 56c71fc224d..00000000000 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_nonresident_income.py +++ /dev/null @@ -1,12 +0,0 @@ -from policyengine_us.model_api import * - - -class mn_renters_credit_nonresident_income(Variable): - value_type = float - entity = TaxUnit - label = "Income received while a nonresident of Minnesota for the renter's credit" - unit = USD - definition_period = YEAR - default_value = 0 - defined_for = StateCode.MN - diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py deleted file mode 100644 index da336a3d79f..00000000000 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py +++ /dev/null @@ -1,12 +0,0 @@ -from policyengine_us.model_api import * - - -class mn_renters_credit_seiu_stipend_subtraction(Variable): - value_type = float - entity = TaxUnit - label = "Minnesota renter's credit SEIU stipend subtraction" - unit = USD - definition_period = YEAR - default_value = 0 - defined_for = StateCode.MN - diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_spouse_agi.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_spouse_agi.py deleted file mode 100644 index edd65dbb39b..00000000000 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_spouse_agi.py +++ /dev/null @@ -1,12 +0,0 @@ -from policyengine_us.model_api import * - - -class mn_renters_credit_spouse_agi(Variable): - value_type = float - entity = TaxUnit - label = "Spouse AGI for Minnesota renter's credit married-filing-separately cases" - unit = USD - definition_period = YEAR - default_value = 0 - defined_for = StateCode.MN - From 3c0e615f3fdfb6ce948feaff729ad244eacd560e Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 8 Apr 2026 20:06:53 -0400 Subject: [PATCH 3/4] Refine Minnesota renter's credit eligibility --- .../mn/tax/income/credits/renters/age_threshold.yaml | 11 +++++++++++ .../states/mn/tax/income/credits/mn_renters_credit.py | 7 ++----- .../credits/mn_renters_credit_household_income.py | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/age_threshold.yaml diff --git a/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/age_threshold.yaml b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/age_threshold.yaml new file mode 100644 index 00000000000..21b3d83a81f --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/income/credits/renters/age_threshold.yaml @@ -0,0 +1,11 @@ +description: Minnesota renter's credit minimum age for the age-based household income subtraction. +values: + 2024-01-01: 65 + +metadata: + period: year + unit: year + label: Minnesota renter's credit age threshold + reference: + - title: 2025 Schedule M1RENT, Household Income section + href: https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py index 0765ee6e2a2..8abebad1f54 100644 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py @@ -12,7 +12,7 @@ class mn_renters_credit(Variable): "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf", "https://www.revenue.state.mn.us/sites/default/files/2025-12/m1ref-25.pdf", ) - defined_for = StateCode.MN + defined_for = "mn_renters_credit_eligible" def formula(tax_unit, period, parameters): p = parameters(period).gov.states.mn.tax.income.credits.renters @@ -20,8 +20,6 @@ def formula(tax_unit, period, parameters): rent_constituting_property_taxes = tax_unit( "mn_rent_constituting_property_taxes", period ) - eligible = tax_unit("mn_renters_credit_eligible", period) - percent_of_income = p.percent_of_income.calc(household_income) claimant_share = p.claimant_share.calc(household_income) max_credit = p.max_credit.calc(household_income) @@ -29,5 +27,4 @@ def formula(tax_unit, period, parameters): excess_rent = max_( 0, rent_constituting_property_taxes - percent_of_income * household_income ) - credit = min_(max_credit, excess_rent * (1 - claimant_share)) - return eligible * credit + return min_(max_credit, excess_rent * (1 - claimant_share)) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py index e762f7ef2fb..4638946f457 100644 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py @@ -15,6 +15,7 @@ class mn_renters_credit_household_income(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.states.mn.tax.income + minimum_age = p.credits.renters.age_threshold mn_agi = ( tax_unit("adjusted_gross_income", period) + tax_unit("mn_additions", period) @@ -24,7 +25,7 @@ def formula(tax_unit, period, parameters): people = tax_unit.members claimant = people("is_tax_unit_head_or_spouse", period) - is_age_eligible = people("age", period) >= 65 + is_age_eligible = people("age", period) >= minimum_age is_disabled = people("is_permanently_and_totally_disabled", period) age_or_disability_subtraction = tax_unit.any( claimant & (is_age_eligible | is_disabled) From e9579bd33d6053fdd41a851724e3923f0002b9ad Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 8 Apr 2026 20:31:57 -0400 Subject: [PATCH 4/4] Align Minnesota renter's credit with M1RENT --- .../mn_rent_constituting_property_taxes.yaml | 19 ++++++-- .../tax/income/credits/mn_renters_credit.yaml | 47 ++++++++++++++++++- .../mn_renters_credit_household_income.yaml | 23 ++++++++- .../states/mn/tax/income/mn_integration.yaml | 3 +- .../mn_rent_constituting_property_taxes.py | 5 +- .../tax/income/credits/mn_renters_credit.py | 18 ++++++- .../mn_renters_credit_assistance_rent_paid.py | 14 ++++++ .../credits/mn_renters_credit_eligible.py | 17 ++++++- .../mn_renters_credit_household_income.py | 32 ++++++++----- .../mn_renters_credit_property_tax_exempt.py | 14 ++++++ .../mn_renters_credit_qualifying_crp.py | 15 ++++++ ...renters_credit_seiu_stipend_subtraction.py | 14 ++++++ .../mn_renters_credit_shared_rent_fraction.py | 14 ++++++ .../mn_renters_credit_total_rent_from_crps.py | 23 +++++++++ 14 files changed, 230 insertions(+), 28 deletions(-) create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_assistance_rent_paid.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_property_tax_exempt.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_qualifying_crp.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_shared_rent_fraction.py create mode 100644 policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_total_rent_from_crps.py diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.yaml index 77740d11a19..b60cb4cfdb5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.yaml @@ -1,8 +1,17 @@ -- name: Rent constituting property taxes equals 17 percent of gross rent +- name: Rent constituting property taxes equals 17 percent of shared CRP rent period: 2025 input: - state_code: MN - rent: 10_000 + people: + person1: + is_tax_unit_head: true + pre_subsidy_rent: 10_000 + tax_units: + tax_unit: + members: [person1] + mn_renters_credit_shared_rent_fraction: 0.5 + households: + household: + members: [person1] + state_code: MN output: - mn_rent_constituting_property_taxes: 1_700 - + mn_rent_constituting_property_taxes: 850 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml index 8cd4e5388cb..612e3c7767a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit.yaml @@ -6,12 +6,13 @@ person1: age: 40 employment_income: 50_000 - rent: 10_000 + pre_subsidy_rent: 10_000 is_tax_unit_head: true tax_units: tax_unit: members: [person1] premium_tax_credit: 0 + mn_renters_credit_qualifying_crp: true families: family: members: [person1] @@ -26,3 +27,47 @@ state_fips: 27 output: mn_renters_credit: 455 + +- name: Assistance-paid rent prorates the renter's credit + absolute_error_margin: 1 + period: 2025 + input: + people: + person1: + age: 40 + employment_income: 20_000 + pre_subsidy_rent: 10_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + mn_renters_credit_qualifying_crp: true + mn_renters_credit_assistance_rent_paid: 5_000 + households: + household: + members: [person1] + state_code: MN + output: + mn_renters_credit: 966 + +- name: Property-tax-exempt residence is ineligible + period: 2025 + input: + people: + person1: + age: 40 + employment_income: 20_000 + pre_subsidy_rent: 10_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + mn_renters_credit_qualifying_crp: true + mn_renters_credit_property_tax_exempt: true + households: + household: + members: [person1] + state_code: MN + output: + mn_renters_credit_eligible: false + mn_renters_credit: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml index 65534265bcd..4e22af89369 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.yaml @@ -1,4 +1,4 @@ -- name: Household income starts from Minnesota AGI and subtracts renter credit adjustments +- name: Household income starts from federal AGI and subtracts renter credit adjustments period: 2025 input: people: @@ -15,9 +15,28 @@ adjusted_gross_income: 50_000 mn_additions: 1_000 mn_subtractions: 500 + mn_renters_credit_seiu_stipend_subtraction: 1_000 households: household: members: [person1, dependent1, dependent2] state_code: MN output: - mn_renters_credit_household_income: 31_260 + mn_renters_credit_household_income: 29_760 + +- name: Separate filer household income includes spouse separate AGI proxy + period: 2025 + input: + people: + person1: + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + filing_status: SEPARATE + adjusted_gross_income: 40_000 + households: + household: + members: [person1] + state_code: MN + output: + mn_renters_credit_household_income: 80_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/mn_integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/mn_integration.yaml index afe2a734204..c5baa9452f6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/mn_integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/income/mn_integration.yaml @@ -130,12 +130,13 @@ person1: age: 40 employment_income: 50_000 - rent: 10_000 + pre_subsidy_rent: 10_000 is_tax_unit_head: true tax_units: tax_unit: members: [person1] premium_tax_credit: 0 + mn_renters_credit_qualifying_crp: true families: family: members: [person1] diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.py index 05f2ce3bc97..ef0fb87e061 100644 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.py +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_rent_constituting_property_taxes.py @@ -15,6 +15,5 @@ class mn_rent_constituting_property_taxes(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.states.mn.tax.income.credits.renters - rent = add(tax_unit, period, ["rent"]) - return rent * p.rent_fraction - + gross_rent = tax_unit("mn_renters_credit_total_rent_from_crps", period) + return round_(gross_rent * p.rent_fraction) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py index 8abebad1f54..187b2829a0d 100644 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit.py @@ -20,6 +20,9 @@ def formula(tax_unit, period, parameters): rent_constituting_property_taxes = tax_unit( "mn_rent_constituting_property_taxes", period ) + assistance_rent_paid = tax_unit( + "mn_renters_credit_assistance_rent_paid", period + ) percent_of_income = p.percent_of_income.calc(household_income) claimant_share = p.claimant_share.calc(household_income) max_credit = p.max_credit.calc(household_income) @@ -27,4 +30,17 @@ def formula(tax_unit, period, parameters): excess_rent = max_( 0, rent_constituting_property_taxes - percent_of_income * household_income ) - return min_(max_credit, excess_rent * (1 - claimant_share)) + line_13_amount = round_(min_(max_credit, excess_rent * (1 - claimant_share))) + proration_denominator = household_income + assistance_rent_paid + proration_ratio = where( + proration_denominator > 0, + round_(household_income / proration_denominator, 5), + 0, + ) + return round_( + where( + assistance_rent_paid > 0, + line_13_amount * proration_ratio, + line_13_amount, + ) + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_assistance_rent_paid.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_assistance_rent_paid.py new file mode 100644 index 00000000000..4c6adbec791 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_assistance_rent_paid.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_assistance_rent_paid(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota renter's credit assistance-paid rent amount" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.MN + reference = ( + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf" + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_eligible.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_eligible.py index a9d9bafcbc7..e6e26f16198 100644 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_eligible.py +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_eligible.py @@ -18,16 +18,29 @@ def formula(tax_unit, period, parameters): rent_constituting_property_taxes = tax_unit( "mn_rent_constituting_property_taxes", period ) + total_rent_from_crps = tax_unit( + "mn_renters_credit_total_rent_from_crps", period + ) + qualifying_crp = tax_unit("mn_renters_credit_qualifying_crp", period) + property_tax_exempt = tax_unit("mn_renters_credit_property_tax_exempt", period) + assistance_rent_paid = tax_unit( + "mn_renters_credit_assistance_rent_paid", period + ) p = parameters(period).gov.states.mn.tax.income.credits.renters claimants = tax_unit.members("is_tax_unit_head_or_spouse", period) claimant_is_dependent = tax_unit.any( claimants & tax_unit.members("is_tax_unit_dependent", period) ) + all_rent_paid_by_assistance = (assistance_rent_paid > 0) & ( + assistance_rent_paid >= total_rent_from_crps + ) return ( - (rent_constituting_property_taxes > 0) + qualifying_crp + & (rent_constituting_property_taxes > 0) & ~claimant_is_dependent + & ~property_tax_exempt + & ~all_rent_paid_by_assistance & (p.max_credit.calc(household_income) > 0) ) - diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py index 4638946f457..33cee08b3fa 100644 --- a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_household_income.py @@ -16,10 +16,13 @@ class mn_renters_credit_household_income(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.states.mn.tax.income minimum_age = p.credits.renters.age_threshold - mn_agi = ( - tax_unit("adjusted_gross_income", period) - + tax_unit("mn_additions", period) - - tax_unit("mn_subtractions", period) + household_agi = add( + tax_unit, + period, + [ + "adjusted_gross_income", + "spouse_separate_adjusted_gross_income", + ], ) exemption_amount = p.exemptions.amount @@ -27,17 +30,20 @@ def formula(tax_unit, period, parameters): claimant = people("is_tax_unit_head_or_spouse", period) is_age_eligible = people("age", period) >= minimum_age is_disabled = people("is_permanently_and_totally_disabled", period) - age_or_disability_subtraction = tax_unit.any( - claimant & (is_age_eligible | is_disabled) - ) * exemption_amount + age_or_disability_subtraction = ( + tax_unit.any(claimant & (is_age_eligible | is_disabled)) * exemption_amount + ) dependent_count = tax_unit("tax_unit_dependents", period) - dependent_subtraction_multiplier = p.credits.renters.dependent_subtraction_multiplier.calc( - dependent_count + dependent_subtraction_multiplier = ( + p.credits.renters.dependent_subtraction_multiplier.calc(dependent_count) ) - dependent_subtraction = ( - exemption_amount * dependent_subtraction_multiplier + dependent_subtraction = exemption_amount * dependent_subtraction_multiplier + seiu_subtraction = tax_unit( + "mn_renters_credit_seiu_stipend_subtraction", period ) - subtractions = age_or_disability_subtraction + dependent_subtraction - return max_(0, mn_agi - subtractions) + subtractions = ( + age_or_disability_subtraction + dependent_subtraction + seiu_subtraction + ) + return max_(0, household_agi - subtractions) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_property_tax_exempt.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_property_tax_exempt.py new file mode 100644 index 00000000000..965c621dedb --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_property_tax_exempt.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_property_tax_exempt(Variable): + value_type = bool + entity = TaxUnit + label = "Minnesota renter's credit property is exempt from property tax" + definition_period = YEAR + default_value = False + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/290.0693", + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf", + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_qualifying_crp.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_qualifying_crp.py new file mode 100644 index 00000000000..2ddb998745a --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_qualifying_crp.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_qualifying_crp(Variable): + value_type = bool + entity = TaxUnit + label = "Has a qualifying Minnesota renter's credit CRP" + definition_period = YEAR + default_value = False + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/290.0693", + "https://www.revenue.state.mn.us/crp-instructions", + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf", + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py new file mode 100644 index 00000000000..ca0194114bc --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_seiu_stipend_subtraction.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_seiu_stipend_subtraction(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota renter's credit SEIU stipend subtraction" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.MN + reference = ( + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf" + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_shared_rent_fraction.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_shared_rent_fraction.py new file mode 100644 index 00000000000..e3c3ba67b7a --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_shared_rent_fraction.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_shared_rent_fraction(Variable): + value_type = float + entity = TaxUnit + label = "Claimant share of Minnesota renter's credit CRP rent" + unit = "/1" + definition_period = YEAR + default_value = 1 + defined_for = StateCode.MN + reference = ( + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf" + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_total_rent_from_crps.py b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_total_rent_from_crps.py new file mode 100644 index 00000000000..a737aa7ef7d --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/income/credits/mn_renters_credit_total_rent_from_crps.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class mn_renters_credit_total_rent_from_crps(Variable): + value_type = float + entity = TaxUnit + label = "Minnesota renter's credit total rent from CRPs" + unit = USD + definition_period = YEAR + defined_for = StateCode.MN + reference = ( + "https://www.revenue.state.mn.us/sites/default/files/2026-03/m1rent-25.pdf" + ) + + def formula(tax_unit, period, parameters): + gross_rent = max_( + add(tax_unit, period, ["pre_subsidy_rent"]), + add(tax_unit, period, ["rent"]), + ) + shared_rent_fraction = tax_unit( + "mn_renters_credit_shared_rent_fraction", period + ) + return gross_rent * shared_rent_fraction