Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/ca-mn-investment-interest.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
California's high-income itemized limitation now leaves out the FTB 3526 investment interest deduction instead of the interest paid; Minnesota leaves investment interest out of its itemized deduction reduction, and its AMT subtracts investment interest and miscellaneous deductions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ values:
# California's own casualty and theft loss (Schedule CA line 15), which
# replaces the federal one in the pre-limitation total.
- ca_casualty_loss_deduction
- non_mortgage_interest
# California's FTB 3526 investment interest, the amount that
# ca_itemized_deductions_pre_limitation holds in place of the federal one.
# 26 U.S.C. 68(c)(2), adopted by R&TC 17077, leaves out the deduction
# allowed for investment interest.
- ca_investment_interest_expense_deduction

metadata:
unit: list
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""Invariants of the California and Minnesota high-income itemized limitations.

California (R&TC 17077, adopting 26 U.S.C. 68) and Minnesota (Minn. Stat.
290.0122, subd. 2(d)) reduce itemized deductions of high-income filers, but
leave medical expenses, investment interest and casualty and theft losses out
of the deductions the reduction is computed on.

Every tax unit in a grid of states, filing statuses, incomes and deductions
shares one simulation per year. Each unit has twins that differ only in their
investment interest, and one that differs only in having no income. With the
deduction inputs set directly, income changes only the reduction, so the
no-income twin carries the pre-limitation total. For every unit:

1. The deduction lies between 0 and its pre-limitation total.
2. The reduction (pre-limitation total less the deduction) does not change
with investment interest, since investment interest is never reduced.
"""

from itertools import product

import numpy as np
import pytest

from policyengine_us import Simulation

YEARS = (2024, 2026)
STATES = ("CA", "MN")
FILING_STATUSES = ("SINGLE", "JOINT")
AGIS = (0, 150_000, 300_000, 600_000, 2_000_000)
CHARITY = (0, 10_000)
MEDICAL = (0, 4_000)
# (investment interest paid, investment expenses). With expenses, California's
# FTB 3526 deduction is below the interest paid, so the federal and
# California amounts differ.
INVESTMENT = ((0, 0), (10_000, 0), (10_000, 4_000), (5_000, 20_000))

UNITS = list(product(STATES, FILING_STATUSES, AGIS, CHARITY, MEDICAL, INVESTMENT))


def _simulation(year):
period = str(year)
people, tax_units, households = {}, {}, {}
for i, (state, status, agi, charity, medical, investment) in enumerate(UNITS):
interest, expenses = investment
person = f"p{i}"
people[person] = {
"age": {period: 50},
"investment_interest_expense": {period: interest},
"investment_expenses": {period: expenses},
}
tax_units[f"t{i}"] = {
"members": [person],
"filing_status": {period: status},
"adjusted_gross_income": {period: agi},
"charitable_deduction": {period: charity},
"ca_charitable_deduction": {period: charity},
"medical_expense_deduction": {period: medical},
}
households[f"h{i}"] = {"members": [person], "state_code": {period: state}}
return Simulation(
situation={"people": people, "tax_units": tax_units, "households": households}
)


def _index(state, status, agi, charity, medical, investment):
return UNITS.index((state, status, agi, charity, medical, investment))


@pytest.mark.parametrize("year", YEARS)
def test_itemized_limitation_invariants(year):
period = str(year)
simulation = _simulation(year)
deduction = {
"CA": simulation.calculate("ca_itemized_deductions", period),
"MN": simulation.calculate("mn_itemized_deductions", period),
}
ca_pre = simulation.calculate("ca_itemized_deductions_pre_limitation", period)

for i, (state, status, agi, charity, medical, investment) in enumerate(UNITS):
label = f"{year} {UNITS[i]}"
pre = deduction[state][_index(state, status, 0, charity, medical, investment)]
if state == "CA":
assert ca_pre[i] == pytest.approx(pre, abs=0.01), label
value = deduction[state][i]

# 1. The deduction lies between 0 and the pre-limitation total.
assert value >= 0, label
assert value <= pre + 0.01, label

# 2. Investment interest does not change the reduction.
j = _index(state, status, agi, charity, medical, (0, 0))
k = _index(state, status, 0, charity, medical, (0, 0))
reduction_without = deduction[state][k] - deduction[state][j]
assert pre - value == pytest.approx(reduction_without, abs=0.01), label
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
medical_expense_deduction: 10_000
ca_investment_interest_expense_deduction: 5_000
output:
ca_itemized_deductions: 12_000 # medical expenses not subject to limitation
# Medical expenses and investment interest are both left out of the
# limitation, so nothing is subject to it.
ca_itemized_deductions: 15_000

- name: Single filer with low AGI and large charitable_deduction
period: 2021
Expand Down Expand Up @@ -74,3 +76,42 @@
# 11,414.30 - 800. Were the loss limited too, line 4 would be 9,131.44,
# line 9 would be 3,000 and the result 8,414.30.
ca_itemized_deductions: 10_614.30

# 26 U.S.C. 68(c)(2), adopted by R&TC 17077, and the line 29 worksheet, line 2,
# leave investment interest out of the limitation. The amount left out is the
# FTB 3526 deduction that the pre-limitation total holds, not the interest paid.
# Both cases set that deduction as an input, so they test the exclusion list
# whatever formula computes FTB 3526.
- name: California's own investment interest deduction is left out of the high-AGI limitation
absolute_error_margin: 0.01
period: 2024
input:
state_code: CA
filing_status: SINGLE
adjusted_gross_income: 244_857 + 200_000
investment_interest_expense: 10_000
ca_investment_interest_expense_deduction: 6_000
ca_charitable_deduction: 10_000
output:
# 10,000 charity + 6,000 investment interest.
ca_itemized_deductions_pre_limitation: 16_000
# Worksheet: line 2 = 6,000; line 3 = 10,000; line 4 = 80% x 10,000 =
# 8,000; line 8 = 6% x 200,000 = 12,000; line 9 = 8,000. 16,000 - 8,000.
# Leaving out the 10,000 paid instead would give line 4 = 80% x 6,000 =
# 4,800 and 11,200.
ca_itemized_deductions: 8_000

- name: California investment interest left out of the limitation when the 6% amount is smaller
absolute_error_margin: 0.01
period: 2024
input:
state_code: CA
filing_status: SINGLE
adjusted_gross_income: 244_857 + 50_000
investment_interest_expense: 10_000
ca_investment_interest_expense_deduction: 6_000
ca_charitable_deduction: 10_000
output:
ca_itemized_deductions_pre_limitation: 16_000
# line 4 = 8,000; line 8 = 6% x 50,000 = 3,000; line 9 = 3,000.
ca_itemized_deductions: 13_000
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,36 @@
charitable_contributions_ald: 300
mn_itemizing: false
mn_amt_taxable_income: 40_000

# 2024 Schedule M1MT line 10 subtracts investment interest (Schedule M1SA
# line 13) and line 14 unreimbursed employee expenses (Schedule M1SA line 23).
- name: MN AMT taxable income subtracts investment interest
period: 2024
input:
adjusted_gross_income: 200_000
mn_itemizing: true
investment_interest_expense: 10_000
state_code: MN
output:
mn_amt_taxable_income: 200_000 - 10_000

- name: MN AMT taxable income subtracts the miscellaneous deduction
period: 2024
input:
adjusted_gross_income: 200_000
mn_itemizing: true
misc_deduction: 3_000
state_code: MN
output:
mn_amt_taxable_income: 200_000 - 3_000

- name: MN AMT taxable income keeps investment interest for a non-itemizer
period: 2024
input:
adjusted_gross_income: 200_000
mn_itemizing: false
investment_interest_expense: 10_000
misc_deduction: 3_000
state_code: MN
output:
mn_amt_taxable_income: 200_000
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,36 @@
deductible_mortgage_insurance_premiums: 1_800
interest_deduction: 11_800
mn_itemized_deductions: 10_000

# Minn. Stat. 290.0122, subd. 2(d), and the 2024 M1SA line 26 worksheets
# (step 2 takes out lines 4, 13 and 19) leave investment interest (line 13)
# out of the reduction.
- name: 2024 MN investment interest is exempt from the 80% reduction
absolute_error_margin: 0.01
period: 2024
input:
filing_status: SINGLE
adjusted_gross_income: 2_000_000
investment_interest_expense: 10_000
charitable_deduction: 5_000
state_code: MN
output:
# AGI is over $1,053,750, so the reduction is 80% of the deductions
# other than investment interest: 0.8 x 5,000 = 4,000.
# 15,000 - 4,000. Were the interest reduced too: 15,000 - 12,000 = 3,000.
mn_itemized_deductions: 11_000

- name: 2024 MN investment interest is left out of the 80% cap on the 3% reduction
absolute_error_margin: 0.01
period: 2024
input:
filing_status: SINGLE
adjusted_gross_income: 300_000
investment_interest_expense: 10_000
charitable_deduction: 1_000
state_code: MN
output:
# 3% x (300,000 - 232,500) = 2,025; the cap is 80% x 1,000 = 800, so the
# reduction is 800 and the deduction 11,000 - 800. Were the interest in
# the cap base, the cap would be 8,800 and the deduction 11,000 - 2,025.
mn_itemized_deductions: 10_200
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ def formula(tax_unit, period, parameters):
# M1MT line 12 takes the casualty and theft loss from Schedule
# M1SA line 19, Minnesota's own amount.
"mn_casualty_loss_deduction",
# M1MT line 10 takes investment interest from M1SA line 13.
"investment_interest_expense",
# M1MT line 14 takes unreimbursed employee expenses above 2% of
# AGI from M1SA line 23. The model has no M1SA line 20-23 amount
# yet, so the federal misc_deduction stands in. Its switch turns
# it off from 2018, and a reform that turns it back on also adds
# the tax preparation fees that line 23 leaves out.
# Line 13 (impairment-related work expenses) has no input here.
"misc_deduction",
]
some_itm_deds = itemizing * add(tax_unit, period, SOME_DEDUCTIONS)
AMT_SUBTRACTIONS = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,17 @@ def formula(tax_unit, period, parameters):
# ... calculate itemized deductions offset
p = parameters(period).gov.states.mn.tax.income.deductions.itemized
# Minn. Stat. 290.0122, subd. 2(d), and the M1SA line 26 worksheets
# (step 2: lines 4, 13 and 19) leave medical expenses and casualty
# and theft losses out of the reduction.
# (step 2: lines 4, 13 and 19) leave medical expenses, investment
# interest and casualty and theft losses out of the reduction. M1SA
# line 13 is the investment interest that interest_deduction holds.
exempt_deds = add(
tax_unit,
period,
["medical_expense_deduction", "mn_casualty_loss_deduction"],
[
"medical_expense_deduction",
"investment_interest_expense",
"mn_casualty_loss_deduction",
],
)
net_deds = max_(0, mn_itm_deds - exempt_deds)
filing_status = tax_unit("filing_status", period)
Expand Down
31 changes: 22 additions & 9 deletions source_conflicts/candidates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1035,26 +1035,39 @@ candidates:
the candidate runs from 2018; verify worksheet editions and affected years.'
- id: us-ca:itemized-limit-investment-interest-exclusion
program: income-tax
years:
from: 2021
type: tax
question: Does the itemized-deduction limitation exclude California investment interest or the federal Schedule
A line 9 amount?
sources:
- kind: statute
citation: R&TC 17077, incorporating IRC 68(c)(2)
url: null
citation: R&TC §17077, adopting 26 U.S.C. 68(c)(2)
url: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=RTC&sectionNum=17077
- kind: worksheet
citation: 540 Schedule CA itemized limitation worksheet, FTB Line 29 worksheet
url: null
citation: 2024 Schedule CA line 29 worksheet, line 2, Form 540 booklet PDF p.68
url: https://www.ftb.ca.gov/forms/2024/2024-540-booklet.pdf#page=68
readings:
statute: Exclude California's investment-interest deduction from FTB 3526 line 10.
statute: Exclude California's investment interest expense deduction (FTB 3526 line 8), the amount the itemized
total holds.
other: Exclude federal Schedule A line 9.
example: A 2024 single filer with AGI of $444,857 (6% of the excess over the threshold is $12,000), $10,000 of charity,
a $6,000 FTB 3526 deduction and $10,000 on federal Schedule A line 9 deducts $8,000 under the statute, which PE-US
follows, and $11,200 through line 9.
pe_us:
follows: conflicting-source
code: []
follows: statute
code:
- policyengine_us/parameters/gov/states/ca/tax/income/deductions/itemized/limit/excluded_deductions.yaml
prs:
- https://github.com/PolicyEngine/policyengine-us/pull/9977
- https://github.com/PolicyEngine/policyengine-us/pull/10645
state: ruled
note: An October 2026 ruling followed the worksheet; the later statute-first rule requires changing to the California
deduction, with years and citations verified.
note: 'Ruled 2026-11-02 for the statute. R&TC 17077 applies IRC 68 without changing 68(c), and 68(c)(2) leaves out
"any deduction for investment interest". The worksheet names federal Schedule A line 9, which gives the same result
when FTB 3526 and federal Form 4952 agree. ca_itemized_deductions_pre_limitation holds
ca_investment_interest_expense_deduction, so the exclusion list names that variable. An October 2026 ruling followed
the worksheet; the statute-first rule replaced it, and the open PR that still lists the federal amount must take
this reading.'
- id: us-ca:joint-childless-eitc-claimable-spouse
program: income-tax
years:
Expand Down
Loading