Fix DE Filing Status 4 per-column credit allocation#7940
Fix DE Filing Status 4 per-column credit allocation#7940PavelMakarchuk wants to merge 13 commits intomainfrom
Conversation
For combined separate filing (FS4), non-refundable credits must be allocated per-column per PIT-RES Instructions: - Personal credits (line 27a): optimally allocated between columns - Aged credits (line 27b): locked to each person's column - CDCC (line 28): to higher-income column - Non-refundable EITC (line 30): to higher-income spouse's column - Each column's credits capped at that column's tax Previously credits were pooled at the tax-unit level, overstating the credit benefit when one spouse has little or no tax liability. Closes #7931 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7940 +/- ##
==========================================
Coverage 100.00% 100.00%
==========================================
Files 19 5 -14
Lines 297 100 -197
==========================================
- Hits 297 100 -197
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:
|
The issue's expected $359 counted only personal + aged credits. The actual per-column result also applies the non-refundable EITC (~$50) to the higher-income column per PIT-RES p.10. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CDCC (Line 31) goes to LOWER-income column per instructions: "applied against the tax imposed on the spouse with the lower taxable income reported on Line 23" - Personal credit optimization now uses capacity (tax - fixed credits) to account for CDCC position in lower-income column - Line 32: sum all non-refundable credits per column, cap at that column's Line 26 tax (single cap, not sequential) - Line 33: balance per column - Line 34: EITC to higher-income column's Line 33 - Comments reference actual PIT-RES line numbers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CDCC goes to lower-income column per PIT-RES Line 31 instructions. Head's column (low-income) can only absorb ~$6 of the ~$200 CDCC, wasting the rest. This is correct per form rules even though TAXSIM35 pools all credits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split de_income_tax_before_refundable_credits into two files: - Main variable: picks joint vs FS4 path (short, easy to read) - de_income_tax_before_refundable_credits_fs4: per-column credit allocation logic matching PIT-RES Lines 26-34 No behavior change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- de_fs4_line33 (Person): each person's Line 33 balance after non-refundable credits (aged, CDCC, optimized personal) - de_income_tax_before_refundable_credits_fs4 (TaxUnit): sums Line 33 values and applies EITC to higher-income column No behavior change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- de_fs4_line33 → de_income_tax_after_non_refundable_credits_indv (mirrors existing de_income_tax_before_non_refundable_credits_indv) - Removed de_income_tax_before_refundable_credits_fs4 (intermediate variable); inlined the EITC application into the main variable - "FS4" was internal jargon; the existing DE convention uses _indv for combined-separate-filing per-person variables No behavior change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each non-refundable credit is now its own per-person variable: - de_aged_personal_credit_indv (Line 27b): locked to person's column - de_cdcc_indv (Line 31): locked to lower-income spouse's column - de_personal_credit_indv (Line 27a): optimally allocated greedy de_income_tax_after_non_refundable_credits_indv now just sums these credits, caps at Line 26 (Line 32), and returns Line 33. No behavior change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- de_aged_personal_credit_indv: aged credit locked to person's column - de_cdcc_indv: CDCC locked to lower-income spouse - de_personal_credit_indv: greedy optimal allocation between columns - de_income_tax_after_non_refundable_credits_indv: Line 32 cap + Line 33 - de_income_tax_before_refundable_credits: FS4 EITC application to higher-income column Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Document tie-break behavior (head wins ties for higher-income;
routes EITC to head and CDCC to spouse on ties — internally
consistent since "higher" and "lower" go to opposite columns)
- Document Lines 28-30 (other state tax, volunteer firefighter,
PIT-CRS) not implemented in PE; not allocated per-column
- Fix label on de_income_tax_after_non_refundable_credits_indv
("when filing combined separate" → "PIT-RES Line 33")
- Add edge case tests:
- Tied taxable incomes for CDCC and EITC routing
- Personal credits exceeding combined column capacity
- EITC exceeding higher-column tax (waste, no redistribution)
- Both spouses 60+ with very low column taxes (aged waste)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
is_tax_unit_dependent doesn't automatically clear head/spouse; defaults can leave is_tax_unit_head_or_spouse True unexpectedly. Replace with two clearer tests: spouse-under-60 and an explicit non-head/non-spouse aged dependent. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per PIT-RES Line 27a, the form lets the taxpayer split the total between Columns A and B in $110 increments. Use the simplest rule that satisfies the form: assign the full total to whichever column has more remaining capacity (Line 26 minus aged + CDCC). Always in $110 increments since total = exemptions × $110. Matches the PolicyEngine pattern of person-level _indv variables with simple per-spouse logic (no chunked optimization loop). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Correct #page= anchors: personal credit → page 8, tax after NR credits → page 10. Tighten FS4 elderly couple test margin from 10 to 0.5. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
hua7450
left a comment
There was a problem hiding this comment.
I think there are two correctness issues here:
P1: de_personal_credit_indv still implements line 27a as an all-or-nothing allocation. The comment acknowledges that PIT-RES allows splitting the personal credit between Columns A and B in $110 increments, but the formula routes the full amount to whichever column has more remaining capacity. That can overstate liability whenever both columns can absorb part of the credit.
P2: de_income_tax_before_refundable_credits still relies on de_files_separately, but de_files_separately is computed from pre-credit tax only. After this refactor, FS4 can waste non-refundable credits on a per-column basis, so the optimal filing choice can change after credits are applied. I do not see a later recomputation of that choice, which means the model can now select FS4 even when the joint path produces the lower final liability.
Summary
Previously PE pooled all credits, overstating the credit benefit when one spouse has little or no tax liability (e.g., elderly couple with $314 primary wages — PE computed $199 tax vs correct $359).
Test plan
Closes #7931
🤖 Generated with Claude Code