Skip to content

Commit 4b1998c

Browse files
MaxGhenisclaude
andauthored
Add tax filing propensity variables (#7333)
* Add voluntary tax filer variable and update tax_unit_is_filer - Add would_file_taxes_voluntarily input variable for tax units that file for reasons other than being required or seeking refundable credits - Update tax_unit_is_filer to use propensity variables from microdata: - required_to_file (income thresholds from IRC § 6012) - takes_up_eitc (refund-seeking behavior) - would_file_taxes_voluntarily (state requirements, documentation, habit) Closes #4286 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Refactor tax filing logic with explicit eligibility check - Add tax_unit_is_required_to_file for rules-based filing requirement - Add eligible_for_refundable_credits to check EITC/CTC eligibility - Add would_file_if_eligible_for_refundable_credit propensity variable - Update tax_unit_is_filer to use three-part logic: 1. Required to file (income thresholds) 2. Eligible for refundable credits AND would file to claim them 3. Would file voluntarily (state requirements, habit, documentation) This separates the refundable credit eligibility check from the propensity to file, enabling policy reforms that change credit eligibility to affect filing behavior. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Update changelog entry Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix exemption suspension in filing requirement and simplify credit check - Use 0 for exemption_amount when personal exemption is suspended (2018+) to match the old tax_unit_is_filer logic - Simplify eligible_for_refundable_credits: eitc + refundable_ctc > 0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent c0b9c1b commit 4b1998c

7 files changed

Lines changed: 189 additions & 60 deletions

File tree

changelog_entry.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
- bump: minor
2+
changes:
3+
added:
4+
- Add tax_unit_is_required_to_file variable for rules-based filing requirement.
5+
- Add eligible_for_refundable_credits variable for EITC/CTC eligibility check.
6+
- Add would_file_if_eligible_for_refundable_credit propensity variable.
7+
- Add would_file_taxes_voluntarily propensity variable for voluntary filers.
8+
changed:
9+
- Refactor tax_unit_is_filer to use three-part filing logic with propensity variables.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
- name: High income - required to file
2+
period: 2024
3+
input:
4+
people:
5+
person:
6+
age: 30
7+
employment_income: 100000
8+
tax_units:
9+
tax_unit:
10+
members: [person]
11+
output:
12+
tax_unit_is_required_to_file: true
13+
tax_unit_is_filer: true
14+
15+
- name: Low income with child - not required but files for credits
16+
period: 2024
17+
input:
18+
people:
19+
adult:
20+
age: 30
21+
employment_income: 5000
22+
child:
23+
age: 5
24+
tax_units:
25+
tax_unit:
26+
members: [adult, child]
27+
output:
28+
tax_unit_is_required_to_file: false
29+
eligible_for_refundable_credits: true
30+
tax_unit_is_filer: true
31+
32+
- name: No income - not required and no credits
33+
period: 2024
34+
input:
35+
people:
36+
person:
37+
age: 30
38+
employment_income: 0
39+
tax_units:
40+
tax_unit:
41+
members: [person]
42+
output:
43+
tax_unit_is_required_to_file: false
44+
eligible_for_refundable_credits: false
45+
tax_unit_is_filer: false
46+
47+
- name: Voluntary filer - not required but chooses to file
48+
period: 2024
49+
input:
50+
people:
51+
person:
52+
age: 30
53+
employment_income: 0
54+
tax_units:
55+
tax_unit:
56+
members: [person]
57+
would_file_taxes_voluntarily: true
58+
output:
59+
tax_unit_is_required_to_file: false
60+
eligible_for_refundable_credits: false
61+
tax_unit_is_filer: true
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from policyengine_us.model_api import *
2+
3+
4+
class eligible_for_refundable_credits(Variable):
5+
value_type = bool
6+
entity = TaxUnit
7+
label = "eligible for refundable tax credits"
8+
documentation = """
9+
Whether this tax unit is eligible for any refundable federal tax credits
10+
(EITC, refundable CTC, etc.) that would create an incentive to file even
11+
if not legally required.
12+
"""
13+
definition_period = YEAR
14+
15+
def formula(tax_unit, period, parameters):
16+
eitc = tax_unit("eitc", period)
17+
refundable_ctc = tax_unit("refundable_ctc", period)
18+
return (eitc + refundable_ctc) > 0

policyengine_us/variables/gov/irs/tax_unit_is_filer.py

Lines changed: 26 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,39 @@
22

33

44
class tax_unit_is_filer(Variable):
5-
value_type = float
5+
value_type = bool
66
entity = TaxUnit
77
label = "files taxes"
8-
unit = USD
9-
documentation = (
10-
"Whether this tax unit has a non-zero income tax liability."
11-
)
12-
definition_period = YEAR
13-
14-
"""
15-
(a) General rule
16-
Returns with respect to income taxes under subtitle A shall be made by the following:
17-
(1)
18-
(A) Every individual having for the taxable year gross income which equals or exceeds the exemption amount, except that a return shall not be required of an individual—
19-
(i) who is not married (determined by applying section 7703), is not a surviving spouse (as defined in section 2(a)), is not a head of a household (as defined in section 2(b)), and for the taxable year has gross income of less than the sum of the exemption amount plus the basic standard deduction applicable to such an individual,
20-
(ii) who is a head of a household (as so defined) and for the taxable year has gross income of less than the sum of the exemption amount plus the basic standard deduction applicable to such an individual,
21-
(iii) who is a surviving spouse (as so defined) and for the taxable year has gross income of less than the sum of the exemption amount plus the basic standard deduction applicable to such an individual, or
22-
(iv) who is entitled to make a joint return and whose gross income, when combined with the gross income of his spouse, is, for the taxable year, less than the sum of twice the exemption amount plus the basic standard deduction applicable to a joint return, but only if such individual and his spouse, at the close of the taxable year, had the same household as their home.
23-
Clause (iv) shall not apply if for the taxable year such spouse makes a separate return or any other taxpayer is entitled to an exemption for such spouse under section 151(c).
24-
(B) The amount specified in clause (i), (ii), or (iii) of subparagraph (A) shall be increased by the amount of 1 additional standard deduction (within the meaning of section 63(c)(3)) in the case of an individual entitled to such deduction by reason of section 63(f)(1)(A) (relating to individuals age 65 or more), and the amount specified in clause (iv) of subparagraph (A) shall be increased by the amount of the additional standard deduction for each additional standard deduction to which the individual or his spouse is entitled by reason of section 63(f)(1).
25-
(C) The exception under subparagraph (A) shall not apply to any individual—
26-
(i) who is described in section 63(c)(5) and who has—
27-
(I) income (other than earned income) in excess of the sum of the amount in effect under section 63(c)(5)(A) plus the additional standard deduction (if any) to which the individual is entitled, or
28-
(II) total gross income in excess of the standard deduction, or
29-
(ii) for whom the standard deduction is zero under section 63(c)(6).
30-
(D) For purposes of this subsection—
31-
(i) The terms "standard deduction", "basic standard deduction" and "additional standard deduction" have the respective meanings given such terms by section 63(c).
32-
(ii) The term "exemption amount" has the meaning given such term by section 151(d). In the case of an individual described in section 151(d)(2), the exemption amount shall be zero.
8+
documentation = """
9+
Whether this tax unit files a federal income tax return.
10+
11+
A tax unit files if any of the following apply:
12+
1. They are legally required to file (IRC § 6012)
13+
2. They are eligible for refundable credits and would file to claim them
14+
3. They would file voluntarily for other reasons (state requirements,
15+
documentation, habit)
16+
17+
The propensity variables (would_file_if_eligible_for_refundable_credit
18+
and would_file_taxes_voluntarily) are assigned during microdata
19+
construction.
3320
"""
21+
definition_period = YEAR
22+
reference = "https://www.law.cornell.edu/uscode/text/26/6012"
3423

3524
def formula(tax_unit, period, parameters):
36-
gross_income = add(tax_unit, period, ["irs_gross_income"])
37-
p = parameters(period).gov.irs.income.exemption
38-
exemption_amount = 0 if p.suspended else p.amount
25+
# Required to file based on income thresholds
26+
required = tax_unit("tax_unit_is_required_to_file", period)
3927

40-
# (a)(1)(A), (a)(1)(B)
41-
42-
filing_status = tax_unit("filing_status", period).decode_to_str()
43-
separate = filing_status == "SEPARATE"
44-
standard_deduction = tax_unit("standard_deduction", period)
45-
threshold = where(
46-
separate,
47-
exemption_amount,
48-
standard_deduction + exemption_amount,
28+
# Would file to claim refundable credits (EITC, CTC, etc.)
29+
eligible_for_credits = tax_unit(
30+
"eligible_for_refundable_credits", period
4931
)
50-
51-
income_over_exemption_amount = gross_income > threshold
52-
53-
# (a)(1)(C)
54-
55-
unearned_income_threshold = 500 + tax_unit(
56-
"additional_standard_deduction", period
57-
)
58-
unearned_income = gross_income - add(
59-
tax_unit, period, ["earned_income"]
60-
)
61-
unearned_income_over_threshold = (
62-
unearned_income > unearned_income_threshold
32+
would_file_for_credits = tax_unit(
33+
"would_file_if_eligible_for_refundable_credit", period
6334
)
35+
files_for_credits = eligible_for_credits & would_file_for_credits
6436

65-
required_to_file = (
66-
income_over_exemption_amount | unearned_income_over_threshold
67-
)
68-
69-
tax_refund = tax_unit("income_tax", period) < 0
70-
not_required_but_likely_filer = ~required_to_file & tax_refund
71-
72-
# (a)(1)(D) is just definitions
37+
# Would file voluntarily for other reasons
38+
files_voluntarily = tax_unit("would_file_taxes_voluntarily", period)
7339

74-
return required_to_file | not_required_but_likely_filer
40+
return required | files_for_credits | files_voluntarily
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from policyengine_us.model_api import *
2+
3+
4+
class tax_unit_is_required_to_file(Variable):
5+
value_type = bool
6+
entity = TaxUnit
7+
label = "required to file federal taxes"
8+
documentation = """
9+
Whether this tax unit is legally required to file a federal income tax
10+
return under IRC § 6012, based on gross income thresholds and filing
11+
status.
12+
"""
13+
definition_period = YEAR
14+
reference = "https://www.law.cornell.edu/uscode/text/26/6012"
15+
16+
def formula(tax_unit, period, parameters):
17+
gross_income = add(tax_unit, period, ["irs_gross_income"])
18+
p = parameters(period).gov.irs.income.exemption
19+
exemption_amount = 0 if p.suspended else p.amount
20+
21+
# (a)(1)(A), (a)(1)(B)
22+
filing_status = tax_unit("filing_status", period).decode_to_str()
23+
separate = filing_status == "SEPARATE"
24+
standard_deduction = tax_unit("standard_deduction", period)
25+
threshold = where(
26+
separate,
27+
exemption_amount,
28+
standard_deduction + exemption_amount,
29+
)
30+
31+
income_over_exemption_amount = gross_income > threshold
32+
33+
# (a)(1)(C) - unearned income threshold for dependents
34+
unearned_income_threshold = 500 + tax_unit(
35+
"additional_standard_deduction", period
36+
)
37+
unearned_income = gross_income - add(
38+
tax_unit, period, ["earned_income"]
39+
)
40+
unearned_income_over_threshold = (
41+
unearned_income > unearned_income_threshold
42+
)
43+
44+
return income_over_exemption_amount | unearned_income_over_threshold
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from policyengine_us.model_api import *
2+
3+
4+
class would_file_if_eligible_for_refundable_credit(Variable):
5+
value_type = bool
6+
entity = TaxUnit
7+
label = "would file taxes if eligible for refundable credit"
8+
documentation = """
9+
Whether this tax unit would file taxes if eligible for a refundable tax
10+
credit (EITC, ACTC, etc.), even if not legally required to file.
11+
12+
This is an input variable assigned during microdata construction based
13+
on propensity modeling. The vast majority of refundable credit eligible
14+
filers do file to claim their credits.
15+
"""
16+
definition_period = YEAR
17+
default_value = True
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from policyengine_us.model_api import *
2+
3+
4+
class would_file_taxes_voluntarily(Variable):
5+
value_type = bool
6+
entity = TaxUnit
7+
label = "would file taxes voluntarily"
8+
documentation = """
9+
Whether this tax unit would file taxes even when not required and not
10+
seeking a refund from refundable credits. Captures filing for reasons
11+
such as state requirements, documentation needs, or habit.
12+
"""
13+
definition_period = YEAR
14+
default_value = False

0 commit comments

Comments
 (0)