fix: implement NJ same-category loss rule for gross income#7280
fix: implement NJ same-category loss rule for gross income#7280
Conversation
Fixes #7017 Under NJ's "same category rule" (N.J.S. 54A:5-1), if any of the income categories has a net loss, that loss must be disregarded (treated as $0) and cannot offset income from other categories. This change applies max_(0, category_total) to: - Capital gains (short-term + long-term combined) - Partnership/S-corp income - Self-employment income - Farm income - Rental income Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7280 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 4 1 -3
Lines 76 16 -60
Branches 1 1
=========================================
- Hits 76 16 -60
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move hardcoded income source lists to parameter YAML files: - non_negative_sources.yaml (categories a, e, f, g, j, n, o) - loss_eligible/category_b.yaml (business profits) - loss_eligible/category_c.yaml (capital gains) - loss_eligible/category_d.yaml (rental income) - loss_eligible/category_k_p.yaml (partnership/S-corp) - Add unemployment_compensation (NJ-1040 Line 20b, Category o) - Remove orphaned gross_income_sources.yaml - Add tests for unemployment comp and farm loss scenarios - All parameter files reference N.J.S. 54A:5-1 and NJ-1040 form Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove 4 separate category parameter files; keep groupings inline in the formula with category letter and NJ-1040 line references. The non_negative_sources.yaml parameter file remains. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each NJ statute category (b, c, d, k/p) gets its own parameter file under loss_eligible_categories/ with references to N.J.S. 54A:5-1 and NJ-1040 line numbers. The formula reads all sources from parameters. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
State Tax Parameter AuditSource
Issues FoundISSUE 1 (HIGH):
|
| Component | Verification | Status |
|---|---|---|
| Same-category loss rule logic | Instructions for Lines 18, 19, 21, 22, 23, 24 all say "if net is a loss, make no entry" | ✅ |
category_b (self-employment + farm) |
Maps to Line 18 / N.J.S. 54A:5-1(b) | ✅ |
category_c (capital gains) |
Maps to Line 19 / N.J.S. 54A:5-1(c) | ✅ |
category_d (rental) |
Maps to Line 23 / N.J.S. 54A:5-1(d) | ✅ |
category_k_p (partnership + S-corp) |
Maps to Lines 21-22 / N.J.S. 54A:5-1(k,p) | ✅ |
employment_income |
Line 15 / Category (a) | ✅ |
taxable_interest_income |
Line 16a / Category (e) | ✅ |
dividend_income |
Line 17 / Category (f) | ✅ |
taxable_pension_income |
Line 20a / Category (j) | ✅ |
taxable_ira_distributions |
Line 20a / Category (j) | ✅ |
gambling_winnings |
Line 24 / Category (g) | ✅ |
alimony_income |
Line 25 / Category (n) | ✅ |
miscellaneous_income |
Line 26 (other) | ✅ |
| 6 of 7 YAML tests | Verified against NJ-1040 form and instructions | ✅ |
Pre-existing Issues (not introduced by this PR)
-
Categories (k) and (p) combined: The statute defines partnership (k) and S-corp (p) as separate categories with separate NJ-1040 lines (21 and 22). Under the same-category rule, a partnership loss should NOT offset S-corp gain. But PolicyEngine uses a single
partnership_s_corp_incomevariable, making separate clamping impossible. This is a data model limitation. -
Gambling losses not netted for NJ: NJ-1040 Line 24 is "Net Gambling Winnings" — gambling losses can offset winnings in the same year. The code uses
gambling_winningswithout subtractinggambling_losses. Sincegambling_winningscan't go negative this doesn't overstate income, but misses a legitimate NJ-specific deduction. -
Estate/trust income not modeled: Category (h) uses "net gains" language and could have losses, but PolicyEngine doesn't have a dedicated variable for this.
-
Alternative Business Calculation Adjustment (ABCA) not implemented: Per P.L. 2011 c.60, NJ allows limited cross-category netting (50%) between business categories (b, d, k, p) with 20-year carryforward. Out of scope for this PR.
Summary
The core same-category loss rule implementation is correct and well-structured. The parameter-driven refactoring is an improvement over the hardcoded version. The one actionable fix is removing unemployment_compensation from non_negative_sources.yaml and correcting the associated test — NJ has exempted unemployment from state income tax since 1976.
NJ does not tax unemployment benefits per NJ Division of Unemployment Insurance. Category (o) in N.J.S. 54A:5-1 is "income from crimes or offenses", not unemployment compensation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@hua7450 ready for re-review |
Summary
max_(0, category_total)to capital gains, partnership/S-corp income, self-employment income, farm income, and rental incomeFixes #7017
Test plan
make formatto ensure code style compliance🤖 Generated with Claude Code