Skip to content

Net self-employment losses across spouses in CalEITC and YCTC earned income - #9818

Merged
PavelMakarchuk merged 2 commits into
mainfrom
ca-eitc-earned-income-netting
Oct 8, 2026
Merged

PavelMakarchuk merged 2 commits into
mainfrom
ca-eitc-earned-income-netting

Conversation

@PavelMakarchuk

@PavelMakarchuk PavelMakarchuk commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #9816.

Adds ca_eitc_earned_income, the FTB 3514 line 19 amount. After review it reads the federal eitc_earned_income (Worksheet 3: wages, Schedule C, farm and partnership SE earnings, less the deductible part of SE tax, summed over head and spouse, floored at zero for the return). ca_eitc, ca_yctc (phase-out, line 23) and the FYTC (Step 10: line 19 earned income) use it instead of filer_adjusted_earnings / tax_unit_earned_income, which floor each person at zero first or omit farm and partnership earnings. This matches the federal netting from #8337.

2023, joint Before After
Wages 9,975.50, spouse SE −6,000: ca_eitc 191.72 258.51 (table: 259)
Wages 10,000, spouse SE −12,000: ca_eitc 191.49 0
Wages 30,000, spouse SE −10,000, child 3: ca_yctc 201.86 1,117

Filers without a self-employment loss do not change: when every filer's net earnings are zero or more, the new sum equals filer_adjusted_earnings.

Tests

  • New ca_eitc_earned_income.yaml: the three cases above, with expectations from the 2023 EITC Table (row 3,951–4,000, $259), worksheet Part I ("If the amount is zero or less, stop here") and the 2023 YCTC ($1,117, phase-out from $25,775).

  • ca_yctc.yaml: five cases fed filer_adjusted_earnings as an input; they now feed ca_eitc_earned_income. Expected values do not change.

  • Review follow-up (1a2649f): farm-only, farm-loss and partnership cases in ca_eitc_earned_income.yaml (2023 Worksheet 3 arithmetic in the YAML); FYTC unit tests now set ca_eitc_earned_income.

policyengine-core test policyengine_us/tests/policy/baseline/gov/states/ca -c policyengine_us: 779 passed.

🤖 Generated with Claude Code

…income

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (909176a) to head (a14b29d).
⚠️ Report is 257 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9818   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         3    -1     
  Lines           76        80    +4     
  Branches         2         0    -2     
=========================================
+ Hits            76        80    +4     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@hua7450 hua7450 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cross-spouse netting and the zero floor match the form. Verified against the 2023 FTB 3514 instructions (Worksheet 3: "Total business income or (loss). Add line 1, line 2, line 3, and subtract line 4"; Part I: "If the amount is zero or less, stop here") and IRC 32(c)(2)(A)(ii), which R&TC 17052(c)(4)(B) says "shall apply". The three new cases and the five re-pointed YCTC cases recompute by hand.

One gap in the new line 19 variable, so requesting changes:

ca_eitc_earned_income omits farm and partnership self-employment earnings. It reads earned_income (employment, Schedule C, SSTB), but Worksheet 3 also lists "2. Farm income or (loss). Enter the amount from federal Schedule 1 (Form 1040), line 6" and "3. Self-employment earnings from partnerships reported on federal Schedule(s) K-1 ... box 14, code A", and the comment in the formula itself says "Schedule 1 business and farm income". Meanwhile the deductible SE tax it subtracts comes from self_employment_tax, whose base (taxable_self_employment_income) includes farm_operations_income and partnership_self_employment_net_earnings. So a 2023 California filer with only $20,000 of farm_operations_income gets ca_eitc_earned_income = max(0, 0 - 1,412.96) = 0 and no CalEITC, while line 19 is 18,587.04. A head with $20,000 of wages and a spouse with a $10,000 farm loss gets 20,000 instead of 10,000. This was already true of filer_adjusted_earnings, but this PR is the one defining line 19.

The federal eitc_earned_income already has exactly the Worksheet 3 structure: the five sources summed over non-dependents, less self_employment_tax_ald_person, floored at zero. Simplest fix is to read it directly (and drop the state variable), or at minimum reuse its source list and self_employment_tax_ald_person rather than re-deriving the half from gov.irs.ald.misc. A farm case in the tests would pin it.

Non-blocking follow-ups: the FYTC phase-out still uses tax_unit_earned_income, although Step 10 says FYTC earned income is line 19, so the new label "for the CalEITC and YCTC" would need updating if that is fixed; the YCTC wage/loss PR (9881) edits lines 37 to 49 of ca_yctc.py, ten lines above this PR's phase-out change, so they should merge cleanly.

Limits: read-only review; tests not run; CI was still pending when I checked.

ca_eitc_earned_income read earned_income (wages, Schedule C, SSTB) and so
omitted farm income (Worksheet 3 line 2) and partnership self-employment
earnings (Worksheet 3 line 3), while the deductible SE tax it subtracted
included both. It now reads eitc_earned_income, which sums the same five
sources over the head and spouse, less self_employment_tax_ald_person,
floored at zero (R&TC 17052(c)(4) applies IRC 32(c)(2)(A)).

The FYTC phase-out now also uses line 19, per FTB 3514 line 34.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@PavelMakarchuk

Copy link
Copy Markdown
Collaborator Author

Thanks. Fixed in 1a2649f.

1. ca_eitc_earned_income omits farm and partnership SE earnings — agreed, fixed.

  • I confirmed the gap in the code. earned_income adds only employment_income, self_employment_income and sstb_self_employment_income. taxable_self_employment_income (the base of self_employment_tax) also adds farm_operations_income and partnership_self_employment_net_earnings.
  • Worksheet 3 lists the same five lines in the 2021, 2022, 2023, 2024 and 2025 FTB 3514 instructions. From the 2023 instructions (Step 5, Worksheet 3, lines 2 and 3):

    Farm income or (loss). Enter the amount from federal Schedule 1 (Form 1040), line 6.
    Self-employment earnings from partnerships reported on federal Schedule(s) K-1. Enter the net profit (or loss) from federal Schedule K-1 (Form 1065), box 14, code A.

  • R&TC 17052(c)(4)(B), for taxable years from 2017: "Section 32(c)(2)(A)(ii) of the Internal Revenue Code shall apply." IRC 32(c)(2)(A)(ii) uses net earnings from self-employment "within the meaning of section 1402(a)", determined "with regard to the deduction allowed to the taxpayer by section 164(f)".
  • ca_eitc_earned_income now returns the federal eitc_earned_income, which is already on this branch. It sums the five sources over the head and spouse, subtracts self_employment_tax_ald_person, and floors the total at zero. This removes the re-derived half from gov.irs.ald.misc.
  • I kept the state variable as the line 19 variable. R&TC 17052(c) changes IRC 32(c)(2)(A) for California: (c)(4)(A) counts wages only if they are subject to California withholding, and (c)(3) excluded self-employment earnings for 2015 and 2016. FTB 3514 lines 14 and 17 also let filers make the IHSS and combat pay elections independently of the federal return. PE does not model these differences, before or after this PR. The state variable is the place for them, and YCTC and FYTC read it.
  • New tests, computed by hand from Worksheet 3 (arithmetic in the YAML comments):
    • 2023, $20,000 farm income only: SE tax = 20,000 × 0.9235 × 15.3% = 2,825.91; line 4 = 1,412.955; line 19 = 18,587.045.
    • 2023, head $20,000 wages, spouse $10,000 farm loss: line 4 = 0; line 19 = 10,000.
    • 2023, $20,000 partnership K-1 box 14 code A: line 19 = 18,587.045.
  • Three cases in ca_eitc_integration.yaml set earned_income directly as an input. eitc_earned_income reads the source variables, so these cases now set employment_income with the same amount. The expected credits do not change.

2. FYTC phase-out — changed.

  • The 2022, 2023, 2024 and 2025 instructions (Step 10, line 34) say: "California earned income for purposes of the FYTC is the same as for the California EITC. Enter the amount from form FTB 3514, line 19." R&TC 17052.2(a)(2)(C)(i) reduces the credit by the "earned income, as defined in Section 17052".
  • ca_foster_youth_tax_credit_person now reads ca_eitc_earned_income instead of tax_unit_earned_income. The label is now "California earned income for the CalEITC, YCTC and FYTC". The five FYTC unit tests set the input under the new name. Their expected values do not change.

3. #9881 overlap. This commit does not change ca_yctc.py or ca_yctc.yaml. git merge-tree of this branch and the #9881 head gives no conflicts.

I updated the changelog fragment to include the new scope.

Tests. All pass:

  • policyengine_us/tests/policy/baseline/gov/states/ca: 779 passed.
  • The federal EITC tests (policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income) plus the 220 YAML files outside the CA folder that mention California or the CA credits: 2,152 passed.
  • ruff format and ruff check are clean on the two changed Python files.

@hua7450 hua7450 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Read all nine files at 1a2649f plus federal eitc_earned_income and its inputs, tax_unit_earned_income, filer_adjusted_earnings and the CalEITC, YCTC and FYTC parameters, against R&TC 17052(c)(4)(B) with IRC 32(c)(2)(A)(ii) and the 2021 to 2025 FTB 3514 instructions (Step 5 Worksheet 3, lines 23 and 34).

The blocking item is fixed in the code: ca_eitc_earned_income now returns federal eitc_earned_income, which sums wages, Schedule C, SSTB, Schedule F and K-1 self-employment earnings over the head and spouse, subtracts self_employment_tax_ald_person and floors at zero, which is Worksheet 3 lines 1 to 5. The farm-only filer from the first round now gets line 19 = 20,000 - 1,412.96 = 18,587.04 instead of 0. Pointing FYTC and YCTC at the same amount matches the forms: FTB 3514 lines 34 to 39 use the single return-level line 19 for the FYTC, so feeding the tax-unit amount to the person-level formula reproduces the form, and lines 23 and 25 phase the YCTC out on line 19 rather than AGI. All 42 cases across the four test files recompute by hand, including the re-pointed integration cases.

One interaction with PR 9881, which I approved separately: that branch tests R&TC 17052.1(b)(1)(B)(i) "earned income of zero or less" with tax_unit_earned_income, which is unfloored and omits farm and K-1 earnings. After both merge, a 2022 filer with 10,000 of wages and a 15,000 farm loss has line 19 = 0 and gets 1,083 on the form, but tax_unit_earned_income = 10,000 fails the test and the merged code gives 0. Whichever PR lands second should switch that check to ca_eitc_earned_income <= 0; the three-way merge of ca_yctc.py and its tests is otherwise clean.

Nits, not blocking: the nine-line comment in ca_eitc_earned_income could shrink to the one-line pointer at Worksheet 3; one unchanged YCTC case still sets an earned_income input that nothing reads.

Pre-existing, for a follow-up: the FYTC defined_for gate uses ca_eitc_eligible where R&TC 17052.2 says "allowed the CalEITC".

@PavelMakarchuk
PavelMakarchuk merged commit 18e3aef into main Oct 8, 2026
35 checks passed
@PavelMakarchuk
PavelMakarchuk deleted the ca-eitc-earned-income-netting branch October 8, 2026 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CalEITC and YCTC floor each spouse's earnings at zero instead of netting self-employment losses (FTB 3514 line 19)

2 participants