Skip to content

Apply the California YCTC wage and net loss limits correctly - #9881

Merged
PavelMakarchuk merged 4 commits into
mainfrom
ca-yctc-wage-and-loss-tests
Oct 8, 2026
Merged

PavelMakarchuk merged 4 commits into
mainfrom
ca-yctc-wage-and-loss-tests

Conversation

@PavelMakarchuk

Copy link
Copy Markdown
Collaborator

Fixes #9880.

Change

ca_yctc, zero-or-negative-earned-income path (R&TC § 17052.1(b)(1)(B)):

  • (i) requires tax_unit_earned_income <= 0;
  • (ii) net loss = max(0, −total income), where total income is ca_agi (Form 540 line 17) with the capital loss limit removed: ca_agi − loss_limited_net_capital_gains + net_capital_gains + capital gain distributions (FTB 3514 line 23b: "without utilization limitations");
  • (iii) the wage test uses employment_income instead of tax_unit_earned_income (FTB 3514 line 23a).

loss_threshold.yaml description now says it applies to both the net loss and the wage test (the statute uses the same indexed $30,000 for both).

Tests

  • The two existing 2022 loss cases now enter the loss as short_term_capital_gains (−$20,000 → $1,083; −$40,000 → $0) instead of a negative irs_gross_income.
  • New 2022 cases: wages $20,000 with an SE loss of $30,000 → $1,083; wages $71,846 with an SE loss of $92,009 → $0 (line 23a); wages $20,000 with an SE loss of $80,000 → $0 (line 23b).

All California baseline tests pass (776).

TAXSIM-35 census comparison

Compared with current main, one household (107687, 2022–2025; no wages, S-corp loss $48 million) changes from the YCTC to $0. TAXSIM also gives it the credit, so it becomes a gap until TAXSIM changes (question filed in PolicyEngine/policyengine-taxsim).

Interaction with #9818: on main, household 109282 (wages $71,846, spouse SE loss $92,009) gets $0 only because the phase-out uses positive wages. #9818 nets the SE loss into YCTC earned income, so #9818 alone would give it $1,083. With this PR, the wage test gives $0, as line 23a requires. The two PRs change different lines of ca_yctc.py.

🤖 Generated with Claude Code

…ited losses

Fixes #9880.

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

@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.

Read the four files at 4b2bad4 against R&TC 17052.1(b)(1)(B) and the 2022 FTB 3514 instructions (Step 8, lines 23a and 23b). The earned-income test and the wage test match the statute and the form, and the three new 2022 cases reproduce by hand. One defect in the new net-loss line:

Capital gain distributions are counted twice. irs_gross_income already includes non_sch_d_capital_gains as its own positive source (gov/irs/gross_income/sources.yaml), so ca_agi contains them, and loss_limited_net_capital_gains is max(-3,000, LT + ST) with no distributions in it. ca_agi - loss_limited_net_capital_gains + net_capital_gains therefore already restores the unlimited capital component, and the extra + distributions adds them a second time, which understates the net loss. On main, for a 2022 California filer with a $45,000 self-employment loss, $10,000 of capital gain distributions and no wages:

adjusted_gross_income=-35,000  ca_agi=-35,000  loss_limited_net_capital_gains=0  net_capital_gains=0
PR formula: ca_agi - lim + net + dist = -25,000  -> net loss 25,000  (credit paid)
Form 540 line 17 without limits        = -35,000  -> net loss 35,000  (over $32,490, no credit)

Dropping the distributions term fixes it. No test exercises distributions on this path, so a case like the one above would pin it.

Nit: the wage test add(tax_unit, period, ["employment_income"]) includes dependents, while tax_unit_earned_income and irs_gross_income exclude them. tax_unit_non_dep_sum("employment_income", tax_unit, period), as in filer_adjusted_earnings, would match FTB 3514 line 13, which only carries the filers' wages.

Checked the overlap with the earned-income-netting PR (9818): it changes only the phase-out line, so the two should merge cleanly.

…ain distributions in the net loss

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

Copy link
Copy Markdown
Collaborator Author

Thanks for the review. The wage nit is fixed in 6c7231f: line 23a now uses tax_unit_non_dep_sum("employment_income", ...), with a new test where a dependent has $40,000 of wages.

On capital gain distributions, I kept the term. Since #9788, loss_limited_net_capital_gains includes them:

distributions = tax_unit.sum(
    max_(0, tax_unit.members("non_sch_d_capital_gains", period))
)
return max_(-loss_limit, net_capital_gains + distributions)

So ca_agi - loss_limited_net_capital_gains takes the distributions out together with the limited capital amount, and net_capital_gains + distributions puts them back once. Your example gives loss_limited_net_capital_gains = 10,000 on this branch and on current main, not 0:

2022, self_employment_income = -45,000, non_sch_d_capital_gains = 10,000
adjusted_gross_income = -35,000   ca_agi = -35,000
loss_limited_net_capital_gains = 10,000   net_capital_gains = 0
PR formula: -35,000 - 10,000 + 0 + 10,000 = -35,000  -> net loss 35,000 -> ca_yctc = 0

That matches Form 540 line 17 (−$35,000). Without the term the line would be −$45,000. Then a filer with a $35,000 self-employment loss and $3,000 of distributions (line 17 = −$32,000, within $32,490) would lose the credit. The new test "Capital gain distributions reduce a self-employment loss to within $32,490, so eligible in 2022" pins that case at $1,083, and it fails if the term is dropped.

All 778 California tests pass locally.

@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, and withdrawing my earlier blocking item: it was wrong. I ran the counter-example against a local checkout that predates PR 9788. On this branch and on main, loss_limited_net_capital_gains already includes the floored distributions, so ca_agi - loss_limited_net_capital_gains + net_capital_gains + distributions removes and restores them exactly once. Re-ran the example at 6c7231f: AGI -35,000, limited amount 10,000, net capital gains 0, so -35,000 - 10,000 + 0 + 10,000 = -35,000, net loss 35,000 above 32,490, credit 0, which is Form 540 line 17. Your numbers were right; sorry for the noise.

Checked the rest at head: the wage test now uses tax_unit_non_dep_sum("employment_income", ...) and the new dependent-wages case pins it; loss_threshold.yaml only changed its description, and 32,490 / 33,497 / 34,602 / 35,640 match the 2022 to 2025 FTB 3514 instructions; all 14 cases in ca_yctc.yaml recompute by hand. A three-way merge with PR 9818's ca_yctc.py and test file is clean.

Nit, not blocking: the two capital add-backs are whole-unit sums (net_capital_gains and the distributions) while ca_agi excludes dependents, so the line is off only when a dependent carries more than 3,000 of net capital items; non-dependent sums would align the two sides.

Follow-up, not for this PR: the 461(l) business-loss cap in loss_ald is also a utilization limitation that line 23b should ignore; undoing it needs a new intermediate for the disallowed amount.

@hua7450

hua7450 commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

One interaction to handle at merge time, noted on PR 9818 as well: this branch tests R&TC 17052.1(b)(1)(B)(i) with tax_unit_earned_income, while 9818 makes line 19 the floored federal eitc_earned_income (farm and K-1 earnings included). 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 has_no_earned_income and the merged code gives 0. Whichever lands second should switch that check to ca_eitc_earned_income <= 0.

PavelMakarchuk and others added 2 commits October 8, 2026 09:03
After PR 9818, FTB 3514 line 19 is the floored federal EITC earned
income, so a business loss that offsets wages gives zero earned income.
Use ca_eitc_earned_income for the R&TC 17052.1(b)(1)(B)(i) test, as the
review asked, and add the 2022 wages-plus-farm-loss case.

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

Copy link
Copy Markdown
Collaborator Author

Done. #9818 is merged, so this branch merges main and the R&TC 17052.1(b)(1)(B)(i) check now reads ca_eitc_earned_income <= 0 (FTB 3514 line 19) instead of tax_unit_earned_income.

New case: 2022, head of household with a child of 3, wages 10,000 and a farm loss of 15,000. Line 19 is max(0, 10,000 − 15,000) = 0; the 5,000 net loss and the 10,000 wages are within the 2022 $32,490 limits, so the YCTC is the full $1,083 (2022 FTB 3514 instructions, Step 8: "you have earned income of zero dollars or less"). It fails on the old check (0) and passes now. The CA credit tests pass (112).

@PavelMakarchuk
PavelMakarchuk merged commit 6d45a08 into main Oct 8, 2026
26 checks passed
@PavelMakarchuk
PavelMakarchuk deleted the ca-yctc-wage-and-loss-tests branch October 8, 2026 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants