Skip to content

Fix DE Filing Status 4 per-column credit allocation#7940

Open
PavelMakarchuk wants to merge 13 commits intomainfrom
de-per-column-credits
Open

Fix DE Filing Status 4 per-column credit allocation#7940
PavelMakarchuk wants to merge 13 commits intomainfrom
de-per-column-credits

Conversation

@PavelMakarchuk
Copy link
Copy Markdown
Collaborator

Summary

  • For combined separate filing (FS4), non-refundable credits are now allocated per-column instead of pooled at the tax-unit level
  • Personal credits (line 27a) are optimally allocated between columns
  • Aged credits (line 27b) are locked to each person's column
  • CDCC (line 28) and non-refundable EITC (line 30) go to the higher-income spouse's column
  • Each column's credits are capped at that column's tax

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

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
Copy link
Copy Markdown

codecov bot commented Apr 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (d95d3cd) to head (0122e06).
⚠️ Report is 147 commits behind head on main.

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     
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 Sentry.
📢 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.

PavelMakarchuk and others added 11 commits April 6, 2026 14:59
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>
Copy link
Copy Markdown
Collaborator

@hua7450 hua7450 left a comment

Choose a reason for hiding this comment

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

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.

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.

DE Filing Status 4: non-refundable credits must be allocated per-spouse, not pooled at unit level

2 participants