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/codex-tip-deduction-occupation-gate.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Restricted the federal tip income deduction to Treasury-listed tipped occupations via a TTOC input, with SSTB exclusion support.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
is_tax_unit_head_or_spouse: true
ssn_card_type: CITIZEN
tip_income: 1_000
treasury_tipped_occupation_code: 102
fsla_overtime_premium: 2_000
tax_units:
tax_unit:
Expand All @@ -92,6 +93,7 @@
is_tax_unit_head_or_spouse: true
ssn_card_type: CITIZEN
tip_income: 1_000
treasury_tipped_occupation_code: 102
fsla_overtime_premium: 2_000
tax_units:
tax_unit:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
- name: Tip and overtime income are exempt
period: 2026
input:
treasury_tipped_occupation_code: 102
tip_income: 200
fsla_overtime_premium: 300
standard_deduction: 0
Expand All @@ -22,10 +23,12 @@
person1:
ssn_card_type: CITIZEN
tip_income: 200
treasury_tipped_occupation_code: 102
fsla_overtime_premium: 300
person2:
ssn_card_type: OTHER_NON_CITIZEN
tip_income: 600
treasury_tipped_occupation_code: 102
fsla_overtime_premium: 900
tax_units:
tax_unit:
Expand All @@ -51,10 +54,12 @@
person1:
ssn_card_type: NONE
tip_income: 200
treasury_tipped_occupation_code: 102
fsla_overtime_premium: 300
person2:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 600
treasury_tipped_occupation_code: 102
fsla_overtime_premium: 900
tax_units:
tax_unit:
Expand All @@ -80,10 +85,12 @@
person1:
ssn_card_type: CITIZEN
tip_income: 200
treasury_tipped_occupation_code: 102
fsla_overtime_premium: 300
person2:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 600
treasury_tipped_occupation_code: 102
fsla_overtime_premium: 900
tax_units:
tax_unit:
Expand Down Expand Up @@ -247,9 +254,11 @@
person1:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 300
treasury_tipped_occupation_code: 102
person2:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 900
treasury_tipped_occupation_code: 102
tax_units:
tax_unit:
members: [person1, person2]
Expand All @@ -274,9 +283,11 @@
person1:
ssn_card_type: NONE
tip_income: 300
treasury_tipped_occupation_code: 102
person2:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 900
treasury_tipped_occupation_code: 102
tax_units:
tax_unit:
members: [person1, person2]
Expand All @@ -301,9 +312,11 @@
person1:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 300
treasury_tipped_occupation_code: 102
person2:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 900
treasury_tipped_occupation_code: 102
person3:
ssn_card_type: NONE
is_tax_unit_dependent: true
Expand Down Expand Up @@ -331,9 +344,11 @@
person1:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 300
treasury_tipped_occupation_code: 102
person2:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 900
treasury_tipped_occupation_code: 102
tax_units:
tax_unit:
members: [person1, person2]
Expand All @@ -358,9 +373,11 @@
person1:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 300
treasury_tipped_occupation_code: 102
person2:
ssn_card_type: NON_CITIZEN_VALID_EAD
tip_income: 900
treasury_tipped_occupation_code: 102
tax_units:
tax_unit:
members: [person1, person2]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
period: 2025
input:
tip_income_deduction_ssn_requirement_met: true
treasury_tipped_occupation_code: 102
tip_income: 10_000
adjusted_gross_income: 100_000
filing_status: JOINT
Expand All @@ -22,6 +23,7 @@
period: 2025
input:
tip_income_deduction_ssn_requirement_met: true
treasury_tipped_occupation_code: 102
tip_income: 10_000
adjusted_gross_income: 1_000_000
filing_status: JOINT
Expand All @@ -32,6 +34,7 @@
period: 2025
input:
tip_income_deduction_ssn_requirement_met: true
treasury_tipped_occupation_code: 102
tip_income: 10_000
adjusted_gross_income: 190_000
filing_status: JOINT
Expand Down Expand Up @@ -71,9 +74,68 @@
is_tax_unit_head: true
is_tax_unit_spouse: false
tip_income: 1_000
treasury_tipped_occupation_code: 102
tax_units:
tax_unit:
members: [person1, person2]
output:
tip_income_deduction_ssn_requirement_met: true
tip_income_deduction: 1_000

- name: Occupation gate allows Treasury-listed tipped occupation
period: 2025
input:
people:
worker:
ssn_card_type: CITIZEN
is_tax_unit_head: true
is_tax_unit_spouse: false
tip_income: 10_000
treasury_tipped_occupation_code: 102
tax_units:
tax_unit:
adjusted_gross_income: 100_000
filing_status: SINGLE
members: [worker]
output:
tip_income_deduction_occupation_requirement_met: true
tip_income_deduction: 10_000

- name: Occupation gate blocks unlisted occupation
period: 2025
input:
people:
worker:
ssn_card_type: CITIZEN
is_tax_unit_head: true
is_tax_unit_spouse: false
tip_income: 10_000
treasury_tipped_occupation_code: 0
tax_units:
tax_unit:
adjusted_gross_income: 100_000
filing_status: SINGLE
members: [worker]
output:
tip_income_deduction_occupation_requirement_met: false
tip_income_deduction: 0

- name: SSTB exclusion blocks otherwise eligible tipped worker
period: 2025
input:
people:
worker:
ssn_card_type: CITIZEN
is_tax_unit_head: true
is_tax_unit_spouse: false
tip_income: 5_000
treasury_tipped_occupation_code: 102
business_is_sstb: true
tax_units:
tax_unit:
adjusted_gross_income: 100_000
filing_status: SINGLE
members: [worker]
output:
tip_income_deduction_occupation_requirement_met: false
tip_income_deduction: 0
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
period: 2026
input:
state_code: IN
treasury_tipped_occupation_code: 102
tip_income: 10_000
employment_income: 50_000
output:
Expand All @@ -20,6 +21,7 @@
period: 2025
input:
state_code: IN
treasury_tipped_occupation_code: 102
tip_income: 10_000
employment_income: 50_000
output:
Expand All @@ -31,6 +33,7 @@
absolute_error_margin: 1
input:
state_code: IN
treasury_tipped_occupation_code: 102
tip_income: 5_000
employment_income: 50_000
output:
Expand All @@ -41,6 +44,7 @@
period: 2027
input:
state_code: IN
treasury_tipped_occupation_code: 102
tip_income: 10_000
employment_income: 50_000
output:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ class tip_income_deduction(Variable):
def formula(tax_unit, period, parameters):
person = tax_unit.members
tip_income = person("tip_income", period)
occupation_requirement_met = person(
"tip_income_deduction_occupation_requirement_met", period
)
agi = tax_unit("adjusted_gross_income", period)
filing_status = tax_unit("filing_status", period)
p = parameters(period).gov.irs.deductions.tip_income
start = p.phase_out.start[filing_status]
agi_excess = max_(agi - start, 0)
phase_out_amount = agi_excess * p.phase_out.rate
total_tip_income = tax_unit.sum(tip_income)
qualified_tip_income = tip_income * occupation_requirement_met
total_tip_income = tax_unit.sum(qualified_tip_income)
capped_tip_income = min_(p.cap, total_tip_income)
return max_(0, capped_tip_income - phase_out_amount)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from policyengine_us.model_api import *


class tip_income_deduction_occupation_requirement_met(Variable):
value_type = bool
entity = Person
label = "Occupation requirement met for the tip income deduction"
definition_period = YEAR
reference = [
"https://www.govinfo.gov/content/pkg/PLAW-119publ21/pdf/PLAW-119publ21.pdf",
"https://www.irs.gov/irb/2025-42_IRB",
]
documentation = (
"A person meets the occupation requirement if they received tips "
"in a Treasury-listed tipped occupation and not in the course of "
"a specified service trade or business."
)

def formula(person, period, _parameters):
treasury_tipped_occupation_code = person(
"treasury_tipped_occupation_code", period
)
is_sstb = person("business_is_sstb", period)
return (treasury_tipped_occupation_code > 0) & ~is_sstb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from policyengine_us.model_api import *


class treasury_tipped_occupation_code(Variable):
value_type = int
entity = Person
label = "Treasury tipped occupation code for the tip income deduction"
definition_period = YEAR
reference = [
"https://www.govinfo.gov/content/pkg/PLAW-119publ21/pdf/PLAW-119publ21.pdf",
"https://www.irs.gov/irb/2025-42_IRB",
]
documentation = (
"Treasury Tipped Occupation Code (TTOC) from Table 1 of proposed "
"section 1.224-1(f). Use 0 if the person did not receive tips in "
"a Treasury-listed tipped occupation."
)
Loading