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/fix-filing-requirement-6012a1-2026.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Apply the 26 U.S.C. 6012(a)(1) federal filing requirement from 2026, when section 6012(f) expires: for a tax unit nobody can claim as a dependent, the threshold is the basic standard deduction plus the additions for age but not blindness, and gross income equal to it requires a return.
1 change: 1 addition & 0 deletions changelog.d/fix-filing-requirement-dependents.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Stop testing every filer's unearned income against $500 in the federal filing requirement (26 U.S.C. 6012): the unearned income test now applies only to a head or spouse who can be claimed as a dependent on another return, uses the section 63(c)(5)(A) amount for the year ($1,350 in 2025) plus that person's own additional standard deduction for age or blindness, and counts that person's gross income other than wages, business income and farm income (the earned income of the IRS dependent worksheet), so a self-employment loss no longer counts as unearned income.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
description: The Internal Revenue Service applies the section 6012(f) filing requirement, which compares gross income with the standard deduction, instead of section 6012(a)(1), if this is true.
values:
2013-01-01: false
2018-01-01: true
2026-01-01: false
metadata:
unit: bool
period: year
label: IRS section 6012(f) filing requirement applies
reference:
- title: 26 U.S. Code § 6012(a)(1) and (f)
href: https://www.law.cornell.edu/uscode/text/26/6012#f
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
loss, interest and dividends) and runs each batch, with four variants of every
unit, as one simulation for 2025 and 2026. Every batch starts with two fixed
units, one that must file and one that need not, so that each property below
has rows to check and the batch holds both answers; the test asserts both.
has rows to check and both answers occur; the test asserts that it does.

5. Split invariance: moving a filer's wages into interest, or interest into
wages, never changes the result for a tax unit whose head and spouse cannot
Expand Down Expand Up @@ -73,15 +73,22 @@
instructions, Chart A) but it does reduce the earned income that sets the
limited standard deduction, so a smaller loss raises the threshold and not
the income. `test_smaller_loss_can_end_the_requirement` pins the case.
- Property 7 leaves out blind filers. The model counts the additional
standard deduction for blindness in every filer's threshold. Chart A does
not (only age), while Table 2 does, so on the charts a blind filer under 65
with wages between the two amounts must file only if nobody can claim them.
The property holds in the model today, and leaving blind filers out keeps it
true under either reading. It also leaves out separate filers: Table 2 lets
a claimable married dependent filing separately skip a return unless the
spouse itemizes, while sections 6012(f) and (a)(1) require one with any
gross income (decision d1395).
- Property 7 leaves out blind filers. Chart A does not count blindness (only
age), while Table 2 does, so on the charts a blind filer under 65 with
wages between the two amounts must file only if nobody can claim them. From
2026 the model follows Chart A here: section 6012(a)(1)(B) raises the
threshold of a filer nobody can claim for age only, while a filer who can
be claimed keeps the standard deduction test (decision d1395).
- Property 7 also leaves out separate filers: Table 2 lets a claimable
married dependent filing separately skip a return unless the spouse
itemizes, while sections 6012(f) and (a)(1) require one with any gross
income (decision d1395).
- From 2026, property 7 also fails at one dollar: gross income equal to the
threshold of a sighted filer nobody can claim. Section 6012(a)(1)(A)
excuses that filer only if gross income is "less than" the threshold, while
a filer who can be claimed is tested with "in excess of" (d1395). The
property skips those units, and
`test_claimability_can_end_the_requirement_at_the_threshold` pins the case.
- Properties 1, 2 and 9 use wages as the only earned income. Earned income for
the limited deduction is net of the deductible part of self-employment tax
on the IRS worksheet, which Table 2 does not spell out.
Expand Down Expand Up @@ -129,8 +136,8 @@ def table_2_single_dependent(earned, unearned, aged, blind):
return unearned_test | earned_test | gross_test


def simulate(units):
"""One simulation of independent tax units.
def simulate(units, **options):
"""One simulation of independent tax units; options go to Simulation.

Each unit is {"filing_status": name, "adults": [...], "children": [...]},
with one dict of person inputs per member. Every unit states its filing
Expand Down Expand Up @@ -168,7 +175,8 @@ def simulate(units):
"tax_units": tax_units,
"households": households,
**groups,
}
},
**options,
)


Expand All @@ -192,6 +200,13 @@ def head_values(units, name):
return np.array([unit["adults"][0].get(name, 0) for unit in units])


def unit_totals(simulation, units, variable, year):
"""A person variable summed over the members of each unit."""
values = np.asarray(simulation.calculate(variable, year))
sizes = [len(unit["adults"]) + len(unit["children"]) for unit in units]
return np.add.reduceat(values, np.cumsum([0] + sizes[:-1]))


def head_medicaid_requirement(simulation, units, year):
"""`medicaid_person_is_required_to_file` for each unit's head."""
values = simulation.calculate("medicaid_person_is_required_to_file", year)
Expand Down Expand Up @@ -483,9 +498,18 @@ def test_filing_requirement_properties(anchors, drawn):
f"{year}: more income ended the requirement"
)
assert required["base"].any() and not required["base"].all()
# Property 7.
# Property 7, except at the 2026 threshold (see the docstring).
sighted = ~anyone_blind[:, 0] & ~separate[:, 0]
assert not (required["base"] & ~required["claimed"])[sighted].any(), (
ended = required["base"] & ~required["claimed"]
if year >= 2026:
gross_income = unit_totals(
simulation, units, "irs_gross_income", year
).reshape(-1, len(VARIANTS))[:, 0]
standard_deduction = np.asarray(
simulation.calculate("standard_deduction", year)
).reshape(-1, len(VARIANTS))[:, 0]
ended &= ~(nobody_claimable & (gross_income == standard_deduction))
assert not ended[sighted].any(), (
f"{year}: being claimable ended the requirement"
)
# Property 8.
Expand Down Expand Up @@ -526,3 +550,14 @@ def test_smaller_loss_can_end_the_requirement():
units[1]["adults"][0]["self_employment_income"] = -100
required = simulate(units).calculate("tax_unit_is_required_to_file", 2025)
assert required.tolist() == [True, False]


def test_claimability_can_end_the_requirement_at_the_threshold():
# Intended exception to property 7 from 2026. Nobody can claim the first
# filer, whose $16,100 of wages equals the threshold of section
# 6012(a)(1)(A)(i), so a return is due. The second filer can be claimed;
# $16,100 does not exceed their standard deduction of $16,100
# ((a)(1)(C)(i)(II) and Chart B), so no return is due (decision d1395).
units = [single_filer(40, False, claimed, 16_100, 0) for claimed in (0, 1)]
required = simulate(units).calculate("tax_unit_is_required_to_file", 2026)
assert required.tolist() == [True, False]
Loading
Loading