Fix DE Filing Status 4 per-column credit allocation#7940
Fix DE Filing Status 4 per-column credit allocation#7940PavelMakarchuk wants to merge 15 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 18 5 -13
Lines 353 112 -241
Branches 4 0 -4
==========================================
- Hits 353 112 -241
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.
|
Please rebase from upstream/main (there are conflicts) and address the requested changes. CI and review will proceed once those are cleared. |
Replace all-or-nothing assignment with proportional floor/ceil algorithm that splits credits optimally between head and spouse columns, maximizing total credits used (minimizing tax). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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