Skip to content
Open
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/fix-de-military-pension-cap-2027.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Raise Delaware's military pension exclusion cap to $15,000 for 2027, $20,000 for 2028 and $25,000 from 2029, let filers age 60 or older take the greater of the $12,500 pension exclusion and the military pension exclusion from 2027, and apply the domicile requirement for filers 60 or older from 2027, under 30 Del. C. § 1106(b)(3) as 85 Del. Laws c. 426 amended it.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
description: Delaware caps the military pension income exclusion at this amount.
values:
# 30 Del. C. 1106(b)(3)b, for 2022 through 2026.
2022-01-01: 12_500
# 1106(b)(3)c, d and e.
2027-01-01: 15_000
2028-01-01: 20_000
2029-01-01: 25_000
metadata:
unit: currency-USD
period: year
Expand All @@ -17,5 +22,7 @@ metadata:
href: https://revenuefiles.delaware.gov/2022/PIT-RES_TY22_2022-02_Instructions.pdf#page=6
- title: The Delaware Code - Title 30 - Chapter 11 - Subchapter II - § 1106 - (b) - (3)
href: https://delcode.delaware.gov/title30/c011/sc02/index.html
- title: 30 Del. C. § 1106(b)(3)c-e, military pension caps for 2027, 2028 and 2029 on
href: https://delcode.delaware.gov/title30/c011/sc02/index.html
- title: Delaware Individual Income Tax Return Line 6
href: https://revenuefiles.delaware.gov/2023/PIT-RES_TY23_2023-01_Instructions.pdf#page=6
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
description: Delaware limits the pension exclusion for filers at or above the age threshold to those who meet its domicile requirement, if this is true.
values:
2007-01-01: false
# 30 Del. C. 1106(b)(3)f.4, added by 85 Del. Laws c. 426 (Senate Bill 219
# with Senate Amendment 1). The act took effect when the Governor signed it
# on August 17, 2026 and names no first tax year for this rule; its fiscal
# note applies the act from tax year 2027.
2027-01-01: true
metadata:
unit: bool
period: year
label: Delaware pension exclusion domicile requirement applies
reference:
- title: 30 Del. C. § 1106(b)(3)f.4
href: https://delcode.delaware.gov/title30/c011/sc02/index.html
- title: Senate Amendment 1 to Senate Bill 219, 153rd General Assembly
href: https://legis.delaware.gov/json/BillDetail/GenerateHtmlDocument?legislationId=143006&legislationTypeId=5&docTypeId=2&legislationName=SA1
- title: Senate Bill 219 fiscal note, assumption 1
href: https://legis.delaware.gov/json/BillDetail/GetPdfDocument?fileAttachmentId=653814#page=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
description: Delaware lets filers at or above the pension exclusion age threshold take the greater of the pension exclusion and the military pension exclusion, if this is true.
values:
# 30 Del. C. 1106(b)(3)b.2: for 2022 through 2026, filers age 60 or older
# exclude up to $12,500 of pensions and eligible retirement income.
2022-01-01: false
# 1106(b)(3)c.2, d.2 and e.2: from 2027 they exclude the greater of that
# amount and their United States military pension, up to the military cap.
2027-01-01: true
metadata:
unit: bool
period: year
label: Delaware military pension exclusion available at or above the age threshold
reference:
- title: 30 Del. C. § 1106(b)(3)b-e
href: https://delcode.delaware.gov/title30/c011/sc02/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"""Properties of Delaware's pension exclusion for military pensions, 2022-2031.

30 Del. C. 1106(b)(3) subtracts, for 2022 through 2026, the greater of
pensions up to $2,000 and a United States military pension up to $12,500 for
a person under 60, and pensions and eligible retirement income up to $12,500
for a person 60 or older. For 2027, 2028 and from 2029 ((b)(3)c, d and e) the
military cap is $15,000, $20,000 and $25,000, and a person 60 or older takes
the greater of the $12,500 exclusion and the military pension up to that cap.
From 2027 ((b)(3)f.4), a person 60 or older who fails the domicile requirement
gets no subtraction.

The reference below restates those rules from the statute, not from the
model's parameters. Hypothesis draws batches of single filers (any age;
military retired pay, survivor benefits, other pensions, IRA distributions,
interest, capital gains or losses, and the domicile requirement), runs each
batch as one simulation with the same inputs in every year, and checks for
every filer and year:

1. The exclusion equals the reference amount.
2. It is never negative and never exceeds the military pension plus the
pension basket floored at zero.
3. From 2027, a filer 60 or older who meets the domicile requirement never
gets less than the 2026 rule gives.
"""

import numpy as np
from hypothesis import HealthCheck, given, settings
from hypothesis import strategies as st

from policyengine_us import Simulation

YEARS = tuple(range(2022, 2032))
MILITARY_CAP = {2027: 15_000, 2028: 20_000}


def military_cap(year):
if year <= 2026:
return 12_500
return MILITARY_CAP.get(year, 25_000)


def basket(filer):
"""Pensions and eligible retirement income, with the $3,000 loss limit."""
gains = max(filer["long_term_capital_gains"], -3_000)
return (
filer["military_retirement_pay"]
+ filer["military_retirement_pay_survivors"]
+ filer["taxable_pension_income"]
+ filer["taxable_ira_distributions"]
+ filer["taxable_interest_income"]
+ gains
)


def reference(year, filer):
military = min(military_cap(year), filer["military_retirement_pay"])
if (
year >= 2027
and filer["age"] >= 60
and not filer["de_pension_exclusion_domicile_requirement_met"]
):
return 0
if filer["age"] < 60:
pensions = (
filer["taxable_pension_income"]
+ filer["military_retirement_pay"]
+ filer["military_retirement_pay_survivors"]
)
return max(min(2_000, max(pensions, 0)), military)
general = min(12_500, max(basket(filer), 0))
if year <= 2026:
return general
return max(general, military)


filers = st.fixed_dictionaries(
{
"age": st.integers(30, 90),
"military_retirement_pay": st.sampled_from(
[0, 1_000, 12_500, 15_000, 18_000, 20_000, 25_000, 40_000]
),
"military_retirement_pay_survivors": st.sampled_from([0, 3_000]),
"taxable_pension_income": st.sampled_from([0, 1_500, 20_000]),
"taxable_ira_distributions": st.sampled_from([0, 5_000, 20_000]),
"taxable_interest_income": st.sampled_from([0, 2_000]),
"long_term_capital_gains": st.sampled_from([-10_000, -2_000, 0, 4_000]),
"de_pension_exclusion_domicile_requirement_met": st.booleans(),
}
)


def simulate(batch):
people, tax_units, households = {}, {}, {}
groups = {"marital_units": {}, "spm_units": {}, "families": {}}
for i, filer in enumerate(batch):
name = f"filer_{i}"
people[name] = {k: {y: v for y in YEARS} for k, v in filer.items()}
tax_units[f"tax_unit_{i}"] = {
"members": [name],
"filing_status": {y: "SINGLE" for y in YEARS},
}
households[f"household_{i}"] = {
"members": [name],
"state_code": {y: "DE" for y in YEARS},
}
for group in groups:
groups[group][f"{group}_{i}"] = {"members": [name]}
return Simulation(
situation={
"people": people,
"tax_units": tax_units,
"households": households,
**groups,
}
)


@settings(
max_examples=6,
deadline=None,
derandomize=True,
suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large],
)
@given(batch=st.lists(filers, min_size=10, max_size=30))
def test_military_pension_exclusion(batch):
simulation = simulate(batch)
for year in YEARS:
exclusion = np.asarray(simulation.calculate("de_pension_exclusion", year))
for filer, amount in zip(batch, exclusion):
assert amount == reference(year, filer), (year, filer, amount)
assert (
0 <= amount <= filer["military_retirement_pay"] + max(basket(filer), 0)
)
if (
year >= 2027
and filer["age"] >= 60
and filer["de_pension_exclusion_domicile_requirement_met"]
):
assert amount >= reference(2026, filer)
Loading
Loading