Repository: PolicyEngine/policyengine-us

Issue:
Add SSN requirement to EITC

Hints from issue comments:
@hua7450: Under current law, all members in the household need to have an SSN or ITIN to qualify the EITC. 
https://www.law.cornell.edu/uscode/text/26/32 
IRC § 32(c)(1)(E) 
IRC § 32(c)(3)(D)  
IRC § 32(m)@MaxGhenis: The TIN described there is only a SSN. ITINs don't count. https://www.irs.gov/credits-deductions/individuals/earned-income-tax-credit/who-qualifies-for-the-earned-income-tax-credit-eitc

<img width="887" alt="Image" src="https://github.com/user-attachments/assets/35d15cd7-c45c-4126-a9dd-511dc86b99fb" />

Solution patch:
diff --git a/changelog_entry.yaml b/changelog_entry.yaml
index e69de29bb2..d703b241f6 100644
--- a/changelog_entry.yaml
+++ b/changelog_entry.yaml
@@ -0,0 +1,4 @@
+- bump: minor
+  changes:
+    added:
+    - Add SSN requirement to current EITC formula.
diff --git a/policyengine_us/variables/gov/irs/credits/earned_income/eitc_child_count.py b/policyengine_us/variables/gov/irs/credits/earned_income/eitc_child_count.py
index 5b70c5499d..f0147cb617 100644
--- a/policyengine_us/variables/gov/irs/credits/earned_income/eitc_child_count.py
+++ b/policyengine_us/variables/gov/irs/credits/earned_income/eitc_child_count.py
@@ -8,5 +8,17 @@ class eitc_child_count(Variable):
     unit = USD
     documentation = "Number of children qualifying as children for the EITC."
     definition_period = YEAR
+    reference = (
+        # IRC 32(c)(3)(D)(i) specifies qualifying children need a taxpayer identification number.
+        "https://www.law.cornell.edu/uscode/text/26/32#c_3_D_i",
+    )
 
-    adds = ["is_child_dependent"]
+    def formula(tax_unit, period, parameters):
+        person = tax_unit.members
+        is_child = person("is_child_dependent", period)
+        meets_eitc_identification_requirements = person(
+            "meets_eitc_identification_requirements", period
+        )
+        eligible_child = is_child & meets_eitc_identification_requirements
+        # Only child who meets EITC identification requirements can claim benefit
+        return tax_unit.sum(eligible_child)
diff --git a/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_eligible.py b/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_eligible.py
index d57498f310..78af8da818 100644
--- a/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_eligible.py
+++ b/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_eligible.py
@@ -14,8 +14,14 @@ class eitc_eligible(Variable):
             "eitc_investment_income_eligible", period
         )
         demographic_eligible = tax_unit("eitc_demographic_eligible", period)
+        # The head or spouse in the tax unit must have valid SSN card type to be eligible for the EITC
+        filers_has_ssn = tax_unit(
+            "filer_meets_eitc_identification_requirements", period
+        )
         # Define eligibility before considering separate filer limitation.
-        eligible = demographic_eligible & investment_income_eligible
+        eligible = (
+            demographic_eligible & investment_income_eligible & filers_has_ssn
+        )
         # This parameter is true if separate filers are eligible.
         if eitc.eligibility.separate_filer:
             return eligible
diff --git a/policyengine_us/variables/gov/irs/credits/earned_income/filer_meets_eitc_identification_requirements.py b/policyengine_us/variables/gov/irs/credits/earned_income/filer_meets_eitc_identification_requirements.py
new file mode 100644
index 0000000000..9c9b2ec7ab
--- /dev/null
+++ b/policyengine_us/variables/gov/irs/credits/earned_income/filer_meets_eitc_identification_requirements.py
@@ -0,0 +1,22 @@
+from policyengine_us.model_api import *
+
+
+class filer_meets_eitc_identification_requirements(Variable):
+    value_type = bool
+    entity = TaxUnit
+    definition_period = YEAR
+    label = "Filer meets EITC identification requirements"
+    reference = (
+        # IRC 32(c)(1)(E) specifies filer and spouse needs a taxpayer identification number.
+        "https://www.law.cornell.edu/uscode/text/26/32#c_1_E",
+    )
+
+    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
+        person = tax_unit.members
+        is_head_or_spouse = person("is_tax_unit_head_or_spouse", period)
+        eligible_ssn_card_type = person(
+            "meets_eitc_identification_requirements", period
+        )
+        ineligible_head_or_spouse = is_head_or_spouse & ~eligible_ssn_card_type
+        return tax_unit.sum(ineligible_head_or_spouse) == 0
diff --git a/policyengine_us/variables/gov/irs/credits/earned_income/meets_eitc_identification_requirements.py b/policyengine_us/variables/gov/irs/credits/earned_income/meets_eitc_identification_requirements.py
new file mode 100644
index 0000000000..d7d9844cbf
--- /dev/null
+++ b/policyengine_us/variables/gov/irs/credits/earned_income/meets_eitc_identification_requirements.py
@@ -0,0 +1,28 @@
+from policyengine_us.model_api import *
+
+
+class meets_eitc_identification_requirements(Variable):
+    value_type = bool
+    entity = Person
+    definition_period = YEAR
+    label = "Person meets EITC identification requirements"
+    reference = (
+        # IRC 32(c)(1)(E) specifies filer and spouse needs a taxpayer identification number.
+        "https://www.law.cornell.edu/uscode/text/26/32#c_1_E",
+        # IRC 32(c)(3)(D)(i) specifies qualifying children need a taxpayer identification number.
+        "https://www.law.cornell.edu/uscode/text/26/32#c_3_D_i",
+        # IRC 32(m) defines a taxpayer identification number as a SSN,
+        # except for those listed in sections II and III of SSA 205(c)(2)(B)(i).
+        "https://www.law.cornell.edu/uscode/text/26/32#m",
+        # SSA 205(c)(2)(B)(i) defines SSNs used for benefits.
+        "https://www.ssa.gov/OP_Home/ssact/title02/0205.htm",
+    )
+
+    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


Test patch:
diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_child_count.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_child_count.yaml
new file mode 100644
index 0000000000..5b04c3664a
--- /dev/null
+++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_child_count.yaml
@@ -0,0 +1,53 @@
+- name: One child meets EITC identification requirements.
+  period: 2023
+  input:
+    people:
+      person1:
+        is_tax_unit_head_or_spouse: true
+        meets_eitc_identification_requirements: true
+      person2:
+        is_child_dependent: true
+        meets_eitc_identification_requirements: true
+    tax_units:
+      tax_unit:
+        members: [person1, person2]
+  output:
+    eitc_child_count: 1
+
+- name: Both children meets EITC identification requirements.
+  period: 2023
+  input:
+    people:
+      person1:
+        is_tax_unit_head_or_spouse: true
+        meets_eitc_identification_requirements: true
+      person2:
+        is_child_dependent: true
+        meets_eitc_identification_requirements: true
+      person3:
+        is_child_dependent: true
+        meets_eitc_identification_requirements: true
+    tax_units:
+      tax_unit:
+        members: [person1, person2, person3]
+  output:
+    eitc_child_count: 2
+
+- name: Two children, one of them meet EITC identification requirements.
+  period: 2023
+  input:
+    people:
+      person1:
+        is_tax_unit_head_or_spouse: true
+        meets_eitc_identification_requirements: true
+      person2:
+        is_child_dependent: true
+        meets_eitc_identification_requirements: true
+      person3:
+        is_child_dependent: true
+        meets_eitc_identification_requirements: false
+    tax_units:
+      tax_unit:
+        members: [person1, person2, person3]
+  output:
+    eitc_child_count: 1
diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_eligible.yaml
index 2f0c36d4e2..fc13da2b3b 100644
--- a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_eligible.yaml
+++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_eligible.yaml
@@ -3,6 +3,17 @@
   input:
     eitc_investment_income_eligible: false
     eitc_demographic_eligible: true
+    filer_meets_eitc_identification_requirements: true
+    filing_status: JOINT
+  output:
+    eitc_eligible: false
+
+- name: Ineligible due to no ITIN nor SSN.
+  period: 2022
+  input:
+    eitc_investment_income_eligible: true
+    eitc_demographic_eligible: true
+    filer_meets_eitc_identification_requirements: false
     filing_status: JOINT
   output:
     eitc_eligible: false
@@ -12,6 +23,7 @@
   input:
     eitc_investment_income_eligible: true
     eitc_demographic_eligible: false
+    filer_meets_eitc_identification_requirements: true
     filing_status: JOINT
   output:
     eitc_eligible: false
@@ -21,6 +33,7 @@
   input:
     eitc_investment_income_eligible: true
     eitc_demographic_eligible: true
+    filer_meets_eitc_identification_requirements: true
     filing_status: JOINT
   output:
     eitc_eligible: true
diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/filer_meets_eitc_identification_requirements.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/filer_meets_eitc_identification_requirements.yaml
new file mode 100644
index 0000000000..c9fd65af00
--- /dev/null
+++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/filer_meets_eitc_identification_requirements.yaml
@@ -0,0 +1,52 @@
+- name: Default is citizen, which is an eligible SSN card type for EITC.
+  period: 2023
+  output:
+    filer_meets_eitc_identification_requirements: true
+
+- name: Both are eligible SSN card type.
+  period: 2023
+  input:
+    people:
+      person1:
+        is_tax_unit_head_or_spouse: true
+        ssn_card_type: CITIZEN
+      person2:
+        is_tax_unit_head_or_spouse: true
+        ssn_card_type: NON_CITIZEN_VALID_EAD
+    tax_units:
+      tax_unit:
+        members: [person1, person2]
+  output:
+    filer_meets_eitc_identification_requirements: true
+
+- name: One person with an ineligible SSN card type.
+  period: 2023
+  input:
+    people:
+      person1:
+        is_tax_unit_head_or_spouse: true
+        ssn_card_type: OTHER_NON_CITIZEN
+      person2:
+        is_tax_unit_head_or_spouse: true
+        ssn_card_type: NON_CITIZEN_VALID_EAD
+    tax_units:
+      tax_unit:
+        members: [person1, person2]
+  output:
+    filer_meets_eitc_identification_requirements: false
+
+- name: The head meets EITC identification requirements. 
+  period: 2023
+  input:
+    people:
+      person1:
+        is_tax_unit_head_or_spouse: false
+        ssn_card_type: OTHER_NON_CITIZEN
+      person2:
+        is_tax_unit_head_or_spouse: true
+        ssn_card_type: NON_CITIZEN_VALID_EAD
+    tax_units:
+      tax_unit:
+        members: [person1, person2]
+  output:
+    filer_meets_eitc_identification_requirements: true
diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/meets_eitc_identification_requirements.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/meets_eitc_identification_requirements.yaml
new file mode 100644
index 0000000000..fbcf111a96
--- /dev/null
+++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/meets_eitc_identification_requirements.yaml
@@ -0,0 +1,18 @@
+- name: Default is citizen, which is an eligible SSN card type for EITC.
+  period: 2023
+  output:
+    meets_eitc_identification_requirements: true
+
+- name: Person is not eligible for EITC. 
+  period: 2023
+  input:
+    ssn_card_type: OTHER_NON_CITIZEN
+  output:
+    meets_eitc_identification_requirements: false
+
+- name: Person is eligible for EITC. 
+  period: 2023
+  input:
+    ssn_card_type: NON_CITIZEN_VALID_EAD
+  output:
+    meets_eitc_identification_requirements: true