From 4f8988529aa9dcc9ca078089b6cad83f2d99fb5e Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Mon, 23 Feb 2026 14:18:17 -0500 Subject: [PATCH] Fix EITC/CDCC earned income to allow SE losses to reduce per-person Per IRC 32(c)(2)(A)(ii) and IRS EIC Worksheet B (Form 1040 Instructions, Line 4b), self-employment losses reduce earned income with no per-person floor. The previous max_(0, ...) in adjusted_earnings.py incorrectly clipped each person's earned income to zero, preventing SE losses from offsetting a spouse's wages. The zero floor now applies only to the combined tax-unit total in filer_adjusted_earnings.py, matching Worksheet B: "If line 4b is zero or less, You can't take the credit." This also fixes CDCC (Form 2441 instructions: "You must reduce your earned income by any loss from self-employment"). Co-Authored-By: Claude Opus 4.6 --- changelog_entry.yaml | 6 +++ .../gov/irs/income/adjusted_earnings.yaml | 29 +++++++++++++ .../irs/income/filer_adjusted_earnings.yaml | 41 +++++++++++++++++++ .../gov/irs/income/adjusted_earnings.py | 14 ++++++- .../gov/irs/income/filer_adjusted_earnings.py | 8 +++- 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/income/adjusted_earnings.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/income/filer_adjusted_earnings.yaml diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..8f661116377 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,6 @@ +- bump: patch + changes: + fixed: + - Fixed EITC and CDCC earned income computation to allow self-employment losses + to reduce earned income per-person, with the zero floor applied only to the + combined tax-unit total per IRS EIC Worksheet B Line 4b and Form 2441 instructions. diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/adjusted_earnings.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/adjusted_earnings.yaml new file mode 100644 index 00000000000..bf893668c40 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/adjusted_earnings.yaml @@ -0,0 +1,29 @@ +# Tests that SE losses correctly reduce adjusted earnings (no per-person floor) +# Per IRC 32(c)(2)(A)(ii) and IRS EIC Worksheet B, Line 4b: +# SE losses reduce earned income, with the floor at zero applied only +# to the combined tax-unit total (filer_adjusted_earnings), not per-person. + +- name: SE loss reduces adjusted earnings below zero + period: 2024 + input: + employment_income: 5_000 + self_employment_income: -10_000 + output: + adjusted_earnings: -5_000 + +- name: Positive SE income gives positive adjusted earnings + period: 2024 + absolute_error_margin: 0.01 + input: + employment_income: 30_000 + self_employment_income: 10_000 + output: + adjusted_earnings: 39_293.52 + +- name: Zero SE income gives wages-only adjusted earnings + period: 2024 + input: + employment_income: 20_000 + self_employment_income: 0 + output: + adjusted_earnings: 20_000 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/filer_adjusted_earnings.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/filer_adjusted_earnings.yaml new file mode 100644 index 00000000000..23e77d20278 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/filer_adjusted_earnings.yaml @@ -0,0 +1,41 @@ +# Tests that the zero floor applies at the tax-unit level, not per-person. +# Per IRS EIC Worksheet B, Line 4b: +# "If line 4b is zero or less, You can't take the credit." + +- name: Joint filers - SE loss partially offsets spouse wages + period: 2024 + input: + people: + head: + employment_income: 30_000 + self_employment_income: 0 + spouse: + employment_income: 0 + self_employment_income: -10_000 + tax_units: + tax_unit: + members: [head, spouse] + output: + # head adjusted_earnings = 30000 + # spouse adjusted_earnings = -10000 + # combined = 20000 (floor at 0 does not bind) + filer_adjusted_earnings: 20_000 + +- name: Joint filers - SE loss fully offsets wages, floor at zero + period: 2024 + input: + people: + head: + employment_income: 5_000 + self_employment_income: 0 + spouse: + employment_income: 0 + self_employment_income: -20_000 + tax_units: + tax_unit: + members: [head, spouse] + output: + # head adjusted_earnings = 5000 + # spouse adjusted_earnings = -20000 + # combined = -15000, floored at 0 + filer_adjusted_earnings: 0 diff --git a/policyengine_us/variables/gov/irs/income/adjusted_earnings.py b/policyengine_us/variables/gov/irs/income/adjusted_earnings.py index e59748efef8..79657996b94 100644 --- a/policyengine_us/variables/gov/irs/income/adjusted_earnings.py +++ b/policyengine_us/variables/gov/irs/income/adjusted_earnings.py @@ -7,12 +7,24 @@ class adjusted_earnings(Variable): definition_period = YEAR label = "Personal earned income adjusted for self-employment tax" unit = USD + reference = "https://www.law.cornell.edu/uscode/text/26/32#c_2_A" def formula(person, period, parameters): + # Per IRC 32(c)(2)(A), EITC earned income = wages + net SE earnings + # (within the meaning of IRC 1402(a)), determined with regard to + # the IRC 164(f) deduction (one-half of SE tax). + # + # Per IRS EIC Worksheet B (Form 1040 Instructions), Line 4b: + # "Combine lines 1e, 2c, 3, and 4a" — SE losses reduce earned + # income with no per-person floor. The floor at zero applies only + # to the combined tax-unit total (see filer_adjusted_earnings). + # + # Per IRS Form 2441 instructions (CDCC): "You must reduce your + # earned income by any loss from self-employment." p = parameters(period).gov.irs.ald.misc adjustment = ( (1 - p.self_emp_tax_adj) * p.employer_share * person("self_employment_tax", period) ) - return max_(0, person("earned_income", period) - adjustment) + return person("earned_income", period) - adjustment diff --git a/policyengine_us/variables/gov/irs/income/filer_adjusted_earnings.py b/policyengine_us/variables/gov/irs/income/filer_adjusted_earnings.py index 6830b102d53..43b0b1cc235 100644 --- a/policyengine_us/variables/gov/irs/income/filer_adjusted_earnings.py +++ b/policyengine_us/variables/gov/irs/income/filer_adjusted_earnings.py @@ -7,6 +7,12 @@ class filer_adjusted_earnings(Variable): definition_period = YEAR label = "Filer earned income adjusted for self-employment tax" unit = USD + reference = "https://www.law.cornell.edu/uscode/text/26/32#c_2_A" def formula(tax_unit, period, parameters): - return tax_unit_non_dep_sum("adjusted_earnings", tax_unit, period) + # Per IRS EIC Worksheet B (Form 1040 Instructions), Line 4b: + # "If line 4b is zero or less, You can't take the credit." + # The floor applies to the combined tax-unit total, not per-person. + return max_( + 0, tax_unit_non_dep_sum("adjusted_earnings", tax_unit, period) + )