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/codex-id-primitives.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added statute-facing taxpayer ID primitives, including `taxpayer_id_type` and `has_valid_ssn`, updated federal SSN- and TIN-gated logic to consume them, and kept `has_itin` as a migration alias for `has_tin`.
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,15 @@ class filer_meets_llc_and_aoc_identification_requirements(Variable):
label = "Filer meets LLC and AOC identification requirements"

def formula(tax_unit, period, parameters):
# Both head and spouse in the tax unit must have valid SSN card type to be eligible for the CTC
# Both head and spouse in the tax unit must have valid SSNs.
person = tax_unit.members
is_head_or_spouse = person("is_tax_unit_head_or_spouse", period)
eligible_ssn_card_type = person(
meets_identification_requirements = person(
"meets_llc_and_aoc_identification_requirements", period
)
ineligible_head_or_spouse = is_head_or_spouse & ~eligible_ssn_card_type
ineligible_head_or_spouse = (
is_head_or_spouse & ~meets_identification_requirements
)
return tax_unit.sum(ineligible_head_or_spouse) == 0

class meets_llc_and_aoc_identification_requirements(Variable):
Expand All @@ -84,13 +86,7 @@ class meets_llc_and_aoc_identification_requirements(Variable):
reference = "https://docs.house.gov/meetings/WM/WM00/20250513/118260/BILLS-119CommitteePrintih.pdf#page=4"

def formula(person, period, parameters):
ssn_card_type = person("ssn_card_type", period)
ssn_card_types = ssn_card_type.possible_values
citizen = ssn_card_type == ssn_card_types.CITIZEN
non_citizen_valid_ead = (
ssn_card_type == ssn_card_types.NON_CITIZEN_VALID_EAD
)
return citizen | non_citizen_valid_ead
return person("has_valid_ssn", period)

class reform(Reform):
def apply(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@
ctc: 500
ctc_adult_individual_maximum: [0, 500] # ODC for 17-year-old

- name: Child without the required SSN gets ODC instead of child CTC in 2024
- name: Child with ITIN but without the required SSN gets ODC instead of child CTC in 2024
period: 2024
input:
people:
Expand All @@ -315,6 +315,7 @@
age: 10
is_tax_unit_dependent: true
ssn_card_type: OTHER_NON_CITIZEN
has_tin: true
tax_units:
tax_unit:
members: [parent, child]
Expand All @@ -327,6 +328,28 @@
non_refundable_ctc: 500
ctc: 500

- name: Child with explicit valid SSN gets child CTC instead of ODC in 2024
period: 2024
input:
people:
parent:
age: 40
ssn_card_type: CITIZEN
child:
age: 10
is_tax_unit_dependent: true
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
tax_units:
tax_unit:
members: [parent, child]
income_tax_before_credits: 2_000
output:
ctc_qualifying_child: [false, true]
ctc_child_individual_maximum: [0, 2_000]
ctc_adult_individual_maximum: [0, 0]
ctc: 2_000

- name: ITIN-only filer can still claim ODC for an adult dependent in 2026
period: 2026
input:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
period: 2023
input:
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
output:
meets_ctc_child_identification_requirements: true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
person2:
is_tax_unit_head_or_spouse: true
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
tax_units:
tax_unit:
members: [person1, person2]
Expand All @@ -26,9 +27,11 @@
person1:
is_tax_unit_head_or_spouse: true
ssn_card_type: OTHER_NON_CITIZEN
has_valid_ssn: false
person2:
is_tax_unit_head_or_spouse: true
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
tax_units:
tax_unit:
members: [person1, person2]
Expand All @@ -42,9 +45,11 @@
person1:
is_tax_unit_head_or_spouse: false
ssn_card_type: OTHER_NON_CITIZEN
has_valid_ssn: false
person2:
is_tax_unit_head_or_spouse: true
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
tax_units:
tax_unit:
members: [person1, person2]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
period: 2023
input:
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
output:
meets_eitc_identification_requirements: true
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
age: 65
is_tax_unit_head_or_spouse: true
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
tax_units:
tax_unit:
members: [person1, person2]
Expand All @@ -28,6 +29,7 @@
age: 64
is_tax_unit_head_or_spouse: true
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
tax_units:
tax_unit:
members: [person1, person2]
Expand All @@ -46,6 +48,7 @@
age: 65
is_tax_unit_head_or_spouse: false
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
tax_units:
tax_unit:
members: [person1, person2]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@
output:
has_tin: false

- name: has_tin derives true from taxpayer_id_type other TIN
period: 2024
input:
taxpayer_id_type: OTHER_TIN
output:
has_tin: true

- name: has_tin derives false from taxpayer_id_type none
period: 2024
input:
taxpayer_id_type: NONE
output:
has_tin: false

- name: has_tin does not infer TIN from other non-citizen SSN card type
period: 2024
input:
ssn_card_type: OTHER_NON_CITIZEN
output:
has_tin: false

- name: has_tin stays true when canonical has_tin input is true
period: 2024
input:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
- name: has_valid_ssn follows canonical input
period: 2024
input:
has_valid_ssn: false
output:
has_valid_ssn: false

- name: has_valid_ssn derives true from citizen SSN card type
period: 2024
input:
ssn_card_type: CITIZEN
output:
has_valid_ssn: true

- name: has_valid_ssn does not infer true from non-citizen EAD proxy alone
period: 2024
input:
ssn_card_type: NON_CITIZEN_VALID_EAD
output:
has_valid_ssn: false

- name: has_valid_ssn derives false from explicit other TIN taxpayer ID type
period: 2024
input:
taxpayer_id_type: OTHER_TIN
output:
has_valid_ssn: false

- name: has_valid_ssn derives false when no SSN card type is available
period: 2024
input:
ssn_card_type: NONE
output:
has_valid_ssn: false

- name: has_valid_ssn derives false from other non-citizen SSN card type
period: 2024
input:
ssn_card_type: OTHER_NON_CITIZEN
output:
has_valid_ssn: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
- name: taxpayer_id_type follows canonical input
period: 2024
input:
taxpayer_id_type: OTHER_TIN
output:
taxpayer_id_type: OTHER_TIN

- name: taxpayer_id_type derives valid SSN from citizen SSN card type
period: 2024
input:
ssn_card_type: CITIZEN
output:
taxpayer_id_type: VALID_SSN

- name: taxpayer_id_type does not infer valid SSN from non-citizen EAD proxy alone
period: 2024
input:
ssn_card_type: NON_CITIZEN_VALID_EAD
output:
taxpayer_id_type: NONE

- name: taxpayer_id_type derives valid SSN from explicit valid SSN input
period: 2024
input:
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
output:
taxpayer_id_type: VALID_SSN

- name: taxpayer_id_type does not infer other TIN from other non-citizen SSN card type
period: 2024
input:
ssn_card_type: OTHER_NON_CITIZEN
output:
taxpayer_id_type: NONE

- name: taxpayer_id_type derives other TIN from explicit TIN input
period: 2024
input:
ssn_card_type: OTHER_NON_CITIZEN
has_tin: true
output:
taxpayer_id_type: OTHER_TIN

- name: taxpayer_id_type derives none when no SSN card type is available
period: 2024
input:
ssn_card_type: NONE
output:
taxpayer_id_type: NONE
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
is_eligible_for_american_opportunity_credit: true
person2:
ssn_card_type: NON_CITIZEN_VALID_EAD
has_valid_ssn: true
qualified_tuition_expenses: 1_000
is_eligible_for_american_opportunity_credit: true
tax_units:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,5 @@ class meets_ctc_child_identification_requirements(Variable):
def formula(person, period, parameters):
p = parameters(period).gov.irs.credits.ctc
if p.child_ssn_requirement_applies:
ssn_card_type = person("ssn_card_type", period)
ssn_card_str = ssn_card_type.decode_to_str()
p = parameters(period).gov.irs.credits.ctc
return np.isin(ssn_card_str, p.eligible_ssn_card_type)
return person("has_valid_ssn", period)
return True
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,4 @@ class meets_ctc_identification_requirements(Variable):
reference = "https://www.congress.gov/bill/119th-congress/house-bill/1/text"

def formula(person, period, parameters):
ssn_card_type = person("ssn_card_type", period)
ssn_card_str = ssn_card_type.decode_to_str()
p = parameters(period).gov.irs.credits.ctc
return np.isin(ssn_card_str, p.eligible_ssn_card_type)
return person("has_valid_ssn", period)
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ class filer_meets_eitc_identification_requirements(Variable):
)

def formula(tax_unit, period, parameters):
# Both head and spouse in the tax unit must have valid SSN card type to be eligible for the EITC
# Both head and spouse in the tax unit must have valid SSNs to be eligible for the EITC.
person = tax_unit.members
is_head_or_spouse = person("is_tax_unit_head_or_spouse", period)
eligible_ssn_card_type = person(
meets_identification_requirements = person(
"meets_eitc_identification_requirements", period
)
ineligible_head_or_spouse = is_head_or_spouse & ~eligible_ssn_card_type
ineligible_head_or_spouse = (
is_head_or_spouse & ~meets_identification_requirements
)
return tax_unit.sum(ineligible_head_or_spouse) == 0
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,4 @@ class meets_eitc_identification_requirements(Variable):
)

def formula(person, period, parameters):
ssn_card_type = person("ssn_card_type", period)
ssn_card_types = ssn_card_type.possible_values
citizen = ssn_card_type == ssn_card_types.CITIZEN
non_citizen_valid_ead = ssn_card_type == ssn_card_types.NON_CITIZEN_VALID_EAD
return citizen | non_citizen_valid_ead
return person("has_valid_ssn", period)
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ class overtime_income_deduction_ssn_requirement_met(Variable):

def formula(tax_unit, period, parameters):
person = tax_unit.members
ssn_card_type = person("ssn_card_type", period)
ssn_card_str = ssn_card_type.decode_to_str()
p = parameters(period).gov.irs.deductions.overtime_income
eligible_ssn_card_type = np.isin(ssn_card_str, p.eligible_ssn_card_type)
joint = tax_unit("tax_unit_is_joint", period)
head_or_spouse = person("is_tax_unit_head_or_spouse", period)
eligible_head_or_spouse = eligible_ssn_card_type & head_or_spouse
eligible_head_or_spouse = person("has_valid_ssn", period) & head_or_spouse
return where(
joint,
tax_unit.sum(eligible_head_or_spouse) == 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@ class additional_senior_deduction_eligible_person(Variable):
reference = "https://www.congress.gov/bill/119th-congress/house-bill/1/text"

def formula(person, period, parameters):
ssn_card_type = person("ssn_card_type", period)
ssn_card_str = ssn_card_type.decode_to_str()
p = parameters(period).gov.irs.deductions.senior_deduction
eligible_ssn_card_type = np.isin(ssn_card_str, p.eligible_ssn_card_type)
head_or_spouse = person("is_tax_unit_head_or_spouse", period)
age = person("age", period)
p_irs = parameters(period).gov.irs.deductions.standard.aged_or_blind
aged = age >= p_irs.age_threshold
return eligible_ssn_card_type & head_or_spouse & aged
return person("has_valid_ssn", period) & head_or_spouse & aged
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ class tip_income_deduction_ssn_requirement_met(Variable):

def formula(tax_unit, period, parameters):
person = tax_unit.members
ssn_card_type = person("ssn_card_type", period)
ssn_card_str = ssn_card_type.decode_to_str()
p = parameters(period).gov.irs.deductions.tip_income
eligible_ssn_card_type = np.isin(ssn_card_str, p.eligible_ssn_card_type)
joint = tax_unit("tax_unit_is_joint", period)
head_or_spouse = person("is_tax_unit_head_or_spouse", period)
eligible_head_or_spouse = eligible_ssn_card_type & head_or_spouse
eligible_head_or_spouse = person("has_valid_ssn", period) & head_or_spouse
return where(
joint,
tax_unit.sum(eligible_head_or_spouse) == 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
class has_tin(Variable):
value_type = bool
entity = Person
label = "Has TIN (ITIN or SSN)"
label = "Has taxpayer identification number (TIN)"
definition_period = YEAR
default_value = True

def formula(person, period, parameters):
simulation = person.simulation

# Canonical path: allow direct `has_tin` inputs to override the formula.
# Allow direct `has_tin` inputs to override the derived value.
holder = simulation.get_holder("has_tin")
if period in holder.get_known_periods():
array = holder.get_array(period)
Expand All @@ -25,4 +25,5 @@ def formula(person, period, parameters):
if array is not None:
return array

return np.full(person.count, True)
taxpayer_id_type = person("taxpayer_id_type", period)
return taxpayer_id_type != taxpayer_id_type.possible_values.NONE
Loading
Loading