Skip to content

Align Wisconsin itemized credit with Schedule 1 and 2020 charity rules - #10311

Open
MaxGhenis wants to merge 6 commits into
mainfrom
wi-itemized-credit-2021-charity
Open

MaxGhenis wants to merge 6 commits into
mainfrom
wi-itemized-credit-2021-charity

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Wisconsin's itemized deduction credit now builds its base from the four Schedule 1 components: medical, interest, charitable, and casualty deductions. This excludes miscellaneous deductions, keeps SALT outside the base, and preserves the existing mortgage-insurance adjustment, Wisconsin standard-deduction subtraction, 5% rate, and nonrefundability calculation.

For 2020, the charitable component subtracts charitable_contributions_ald, the amount actually claimed on federal Form 1040 line 10b. Main's #10186 moved the 2020 deduction into that variable; its formula already returns zero for federal itemizers. A non-itemizer with $10,000 of gifts and $300 claimed above the line has a $9,700 Wisconsin charitable component and, with zero Wisconsin standard deduction, a $485 potential credit. Federal itemizers retain the full eligible gift amount.

The branch merges main at dc925ce7205e098cd59be3091ef22766f4b34b66. #10186 already corrected the 2021 double count on main. The 2021 $500 gift case is retained as a regression guard; $515 describes behavior before #10186. The remaining change relative to main is the explicit Schedule 1 base (including the miscellaneous exclusion) and the 2020 claimed-deduction subtraction. The 2019 case protects the unchanged federal charitable component and historical 5% rate. Federal non-itemizers remain eligible through hypothetical Schedule A deductions.

Sources and hand calculations:

Validation at d84a976854196715bd74533fc5950720c3d6654e: 176 passed across eight files, one foreground process per file, with all required thread caps set to 4.

File Passed
Wisconsin itemized credit YAML 15
Wisconsin charitable component YAML 5
Charitable ALD unit YAML 12
Charitable ALD integration YAML 14
Charitable ALD Python invariants 3
Federal non-itemizer charity YAML 12
Federal itemization YAML 12
test_source_conflicts.py 103

make format (Ruff formatting and checks) and git diff --check passed. An initial startup was interrupted under heavy host load, and a run with periodic stack diagnostics crashed during startup; both affected files passed on retry. No policy assertion failed in the completed runs.

Impact: microsimulation remains with the hub.

axiom: TheAxiomFoundation/rulespec-us#1671 queued; historical corpus ingestion, signed-release re-pin, and separate encoder approval were recorded as blockers. The hub will refresh the existing extension with this head, the actual charitable_contributions_ald mapping, the 2019 case, and all charitable-component tests.

@MaxGhenis
MaxGhenis marked this pull request as ready for review October 21, 2026 00:52
@codecov

codecov Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (909176a) to head (d84a976).
⚠️ Report is 604 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main    #10311   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         2    -2     
  Lines           76        33   -43     
  Branches         2         0    -2     
=========================================
- Hits            76        33   -43     
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 Harness.
📢 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.

MaxGhenis and others added 3 commits October 22, 2026 04:04
Retain the explicit Wisconsin Schedule A components and main mortgage insurance premium exclusion, including both sets of regression tests.
Subtract the modeled federal non-itemizer allowance only when claimed in 2020. Preserve full charitable gifts for federal itemizers and from 2021, and cite the historical five-percent rate.
The base formula (before 2020) had no test, so codecov/patch reported one uncovered line. At $150,000 of wages the 2019 Wisconsin standard deduction is 0, so 5% of a $10,000 gift gives $500.

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

DTrim99 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Fix Wisconsin itemized credit counting charitable gifts twice in 2021

PR #10311 (author: MaxGhenis), head 7869d9713a. This is a first review. Line numbers refer to 7869d9713a. The PR changes five files:

  • New variable: wi_itemized_deduction_credit_charitable_deduction.py.
  • Changed variable: wi_itemized_deduction_credit_potential.py.
  • Parameter: rate.yaml now starts in 2020.
  • Tests: seven new cases in wi_itemized_deduction_credit.yaml and a new five-case wi_itemized_deduction_credit_charitable_deduction.yaml.
  • Changelog: changelog.d/wi-itemized-credit-2021-charity.fixed.md.

Summary

The PR rebuilds the Wisconsin Schedule 1 base from four explicit components (medical, interest, charity and casualty) instead of itemized_deductions_less_salt. This drops miscellaneous deductions, as Wis. Stat. 71.07(5)(a)7 requires. For 2020 it also subtracts the $300 claimed on federal Form 1040 line 10b, as the 2020 Form 1 instructions require. The law is read correctly, and against the PR's own base (86d3ae6c6d) every expectation checks out by hand.

The problem is #10186, which merged on main after this branch's last CI run (2026-10-22 13:16 UTC):

  • Should 1 (merge blocker): the 2020 rule is dead on the merged tree. On main, charitable_deduction_for_non_itemizers is zero in 2020, because the 2020 deduction moved above the line into charitable_contributions_ald. The new formula_2020 reads the old variable, so after the merge it subtracts nothing. A 2020 non-itemizer with $10,000 of gifts gets $500 instead of $485. The 2020 tests feed charitable_deduction_for_non_itemizers: 300 as an input, so they still pass on the merged tree and can't catch this.
  • Should 2: the headline 2021 fix is already on main. Take the 2020 charitable deduction for non-itemizers above the line #10186 removed charitable_deduction_for_non_itemizers from the 2020-2021 federal itemized list. The PR's own 2021 regression case already returns $500 on main. The title, changelog and body describe a fix this PR no longer makes.
  • Should 3: the axiom extension comment is stale. The rulespec-us#1671 comment describes the first head, 6447abbecf. It says the PR has no 2020 subtraction and lists six YAML rows, but the head now has the subtraction and twelve new cases.

Status:

Critical (must fix)

None.

Should address

S1 (merge blocker). The 2020 line 10b exclusion reads a variable that main now sets to zero in 2020

Where: wi_itemized_deduction_credit_charitable_deduction.py:20-29, and the 2020 cases in both YAML files: wi_itemized_deduction_credit.yaml:34-72 and wi_itemized_deduction_credit_charitable_deduction.yaml:4-41.

What is wrong:

  • What formula_2020 subtracts. It subtracts where(tax_unit_itemizes, 0, charitable_deduction_for_non_itemizers).

  • What Take the 2020 charitable deduction for non-itemizers above the line #10186 changed on main (aa32d3efb0):

    • gov.irs.deductions.itemized.charity.non_itemizers_amount no longer has a 2020 value. For every filing status it runs 2018-01-01: 0, then 2021-01-01: 300 (600 for joint returns). So charitable_deduction_for_non_itemizers = min(0, cash gifts) = 0 in 2020.
    • main's own test charitable_deduction_for_non_itemizers.yaml now expects 0 in 2020: "2020 single filer, whose deduction is above the line instead ... charitable_deduction_for_non_itemizers: 0".
    • The amount actually claimed on line 10b is now the new charitable_contributions_ald, in the 2020 above-the-line list. Its formula is ~itemizes * min_(cash_donations, p.cap[filing_status]).
  • Merged-tree trace. I checked the tree from git merge-tree --write-tree PolicyEngine/main 7869d9713a (clean). The tree keeps formula_2020 unchanged. Take a 2020 Wisconsin non-itemizer with $10,000 of cash gifts who claimed $300 on line 10b:

    • charitable component = 10,000 − 0 = 10,000, not 9,700;
    • potential credit = $500, not $485.

    The PR body's own 2020 example is therefore wrong as soon as it merges.

  • The tests can't see it. The 2020 cases supply charitable_deduction_for_non_itemizers: 300 (and tax_unit_itemizes) as inputs, which override the formula. They pass on the merged tree while the real chain gives the wrong answer.

  • Severity. The head is correct against its own base and CI is green there. The defect appears only once the branch is combined with the newer main, so under the Integrate modeled state unemployment insurance into income flows #9558 and Follow state statutes where forms differ: NM medical exemption, VT CDCC, NY/NYC household credit, PR EITC #10300 precedent it is a merge-blocking semantic conflict, rated Should. It must be fixed before merging: the merge is textually clean and CI would stay green, so nothing else will catch it.

Source:

Fix:

  1. Merge main into the branch.
  2. In formula_2020, subtract the amount actually claimed. It is already zero for itemizers, so the where and the "potential allowance" comment can go:
    def formula_2020(tax_unit, period, parameters):
        charitable = tax_unit("charitable_deduction", period)
        # Gifts claimed on 2020 federal Form 1040 line 10b (26 U.S.C. 62(a)(22)).
        claimed_above_the_line = tax_unit("charitable_contributions_ald", period)
        return max_(0, charitable - claimed_above_the_line)
    charitable_contributions_ald returns 0 in any year whose above-the-line list doesn't include it. A single formula would therefore also work, but keeping formula_2020 dates the rule to the 2020 instruction.
  3. Change the 2020 unit inputs from charitable_deduction_for_non_itemizers to charitable_contributions_ald.
  4. Add one 2020 case that computes the chain from person inputs, so a future rename can't hide the rule again:
    • Inputs: WI; tax_unit_itemizes: false; age 40; employment_income: 150_000; charitable_cash_donations: 10_000.
    • Expected: charitable_contributions_ald: 300, wi_itemized_deduction_credit_charitable_deduction: 9_700, wi_standard_deduction: 0 and wi_itemized_deduction_credit_potential: 485.
    • Arithmetic: min(10,000, 300) = 300; 10,000 − 300 = 9,700; × .05 = 485. The 2020 table's final row reads "126,499 or over 0 0 0 0", which covers AGI of 149,700.
    • This is a hand trace; I haven't run it.

S2. The title, changelog and body claim a 2021 fix that main already has

Where:

  • changelog.d/wi-itemized-credit-2021-charity.fixed.md: "Fixed Wisconsin's itemized deduction credit counting charitable gifts twice in 2021 ...".
  • The PR title.
  • The PR body's opening example and its baseline line: "the 2021 gift returns $515 versus $500".

What is wrong:

  • The bug was real at this branch's base. At 86d3ae6c6d, gov.irs.deductions.itemized_deductions listed charitable_deduction_for_non_itemizers from 2020 to 2021. So itemized_deductions_less_salt for the 2021 case was 10,000 + 300 and the credit was (10,300) × .05 = $515.
  • Take the 2020 charitable deduction for non-itemizers above the line #10186 has since fixed it on main. It deleted the 2020 and 2022 list entries. main now has only the 2018 list: charitable, interest, SALT, medical, casualty and miscellaneous. So the 2021 case already returns $500 on main without this PR.
  • What the PR actually does on main:
    1. it drops miscellaneous deductions (71.07(5)(a)7);
    2. it adds the 2020 line 10b exclusion, once S1 is fixed;
    3. it pins the base to Schedule 1's four lines, so later additions to the federal list stay out. Count gambling winnings in federal gross income and fix the wagering losses deduction #10070's wagering_losses_deduction is one example.
  • Stale validation counts. The body's validation counts ("2 failed, 4 passed", 57 pending WI files) describe the original head on an older main.

Fix: after merging main:

  • Changelog. Reword it, for example: "Wisconsin's itemized deduction credit now uses only the Schedule 1 medical, interest, charitable and casualty components, excluding miscellaneous deductions, and excludes the 2020 charitable deduction claimed on federal Form 1040 line 10b."
  • Title and body. Retitle to match, keep the 2021 case as a regression guard, and label the $515 figure as pre-Take the 2020 charitable deduction for non-itemizers above the line #10186.

S3. The rulespec-us#1671 extension comment does not match the head

Where: rulespec-us#1671, comment of 2026-10-22 01:15 UTC.

What is wrong:

  • It names an old head. The comment names head 6447abbecf, the PR's first commit.
  • It says the 2020 subtraction is missing: "Inspection of the PR head shows that the new formula directly imports the full charitable_deduction, without this subtraction". The head now has that subtraction (516a3e2047).
  • Its test table is short. It says "These six rows match the credit YAML at the PR head". The head adds two 2020 credit cases, a 2019 case and the five-case component file. After S1, the 2020 rows will map to charitable_contributions_ald.
  • The rules require a queued issue that matches the head.

Fix: after S1, post a short update naming the new head. It should:

  • map the 2020 "actually claimed" input to charitable_contributions_ald;
  • add the 2019 row (5% × 10,000 = 500) and the component-file rows;
  • drop the "without this subtraction" sentence.

Suggestions

G1. Consider a parameter list for the Schedule 1 components.

  • Where: wi_itemized_deduction_credit_potential.py:24-33 writes the four Schedule 1 lines inline.
  • Suggestion: a list parameter such as gov.states.wi.tax.income.credits.itemized_deduction.components, with Schedule 1 lines 1-4 as its reference.
  • Why: it would carry the source and allow a dated change without a formula edit. The inline list is acceptable; this is optional.

G2. Reference polish.

  • Charitable variable: add the 2020 instructions' PDF page 2 passage quoted in S1 to wi_itemized_deduction_credit_charitable_deduction.py. It is the clearest statement that Wisconsin adopted 62(a)(22) and why the amount is excluded.
  • rate.yaml: add Wis. Stat. 71.07(5)(c) ("Multiply the amount under par. (b) by .05") so the 2019 case's backward extrapolation from 2020-01-01 has a source.
  • Form PDFs: optionally align rate.yaml's 2021/2022 Form1f.pdf hrefs with the variables' Form1.pdf. Both files exist and show Schedule 1 on page 4.

G3. Optional: a 2020 case where the itemization choice is computed.

  • Why: S1's fix case supplies tax_unit_itemizes. A second case could exercise Take the 2020 charitable deduction for non-itemizers above the line #10186's 2020 itemization logic.
  • Example: a joint return, one earner, wages $130,000, cash gifts $10,000.
  • Hand trace:
    • Schedule A is about $16,900 (gifts plus about $6,900 of modeled WI withholding as SALT), against $24,800, so the household doesn't itemize;
    • the ALD is $300 and AGI is $129,700, at or above 126,499, so the WI standard deduction is 0;
    • the component is 9,700 and the potential credit is $485.
  • Caveat: this is a hand trace only, so confirm the intermediate values when you add it.

Verified correct

Law:

  • 71.07(5)(a), current text. Itemized deductions "allowed under the internal revenue code except" items that include 2 (taxes under 164) and 7 ("Miscellaneous itemized deductions ... without regard to whether such deductions are subject to the 2 percent floor"). Then (b) subtracts the standard deduction and (c) multiplies by .05. Excluding SALT and miscellaneous deductions is therefore right in every year. 71.07(5)(a)3 keeps only disaster casualty losses, which matches the federal post-2017 casualty deduction.
  • 2020, 2021 and 2022 Schedule 1 (2020 PDF page 5, 2021 PDF page 4, 2022 PDF page 4). Each lists exactly four components: medical, interest, gifts to charity and casualty. Line 8 is ".05 (5%)". The PR's four-variable base matches.
  • 2021 non-itemizers. The 2021 instructions, PDF page 16, tell non-itemizers to "use the amounts which would be deductible if you had itemized". The 2021 booklet nowhere excludes the 170(p) amount (federal line 12b). That deduction doesn't reduce AGI, so there is no double benefit in Wisconsin. The full Schedule A charity is right for 2021, and formula_2021 gives it. The same holds for 2022, when 170(p) is $0, and for later years, where main's federal list leaves the 170(p) amount out.
  • 2020. Wisconsin adopted 62(a)(22) (2020 instructions, PDF page 2), so Wisconsin AGI already reflects the $300. Take the 2020 charitable deduction for non-itemizers above the line #10186 adds no Wisconsin add-back, which is consistent. The PR's 2020 rule is the right law; only its input variable is wrong on main (S1).
  • The mortgage insurance premium subtraction is unchanged in effect. interest_deduction adds deductible_interest_expense and deductible_mortgage_insurance_premiums, and the PR subtracts the latter.

Hand-checked expectations (12 cases). The 2021 and 2022 standard-deduction tables end at "128,113 or over 0" and "134,845 or over 0" (2021, 2022), so the Wisconsin standard deduction is 0 at $150,000.

  1. 2020 non-itemizer (credit file, line 34). 10,000 − 300 = 9,700; × .05 = 485.
  2. 2020 itemizer (line 51). 10,000; 500.
  3. 2021 gift (line 79). Standard deduction 0; base 10,000; potential 500; applied 500, well under the Wisconsin tax of about $8,000. At the PR's base it would have been 10,300 × .05 = 515.
    • Itemization. Under the model this filer itemizes federally (Schedule A ≈ $18,100 against $12,550 + $300). formula_2021 doesn't read itemization, so the result is the same for a non-itemizer. Case 12 covers that explicitly.
  4. 2019 (line 101). 10,000 × .05 = 500. The rate comes from the 2020 value extrapolated backward; it is .05 under 71.07(5)(c).
  5. 2022 charity control (line 123). 500.
  6. 2022 medical, interest and charity (line 148). Medical is 15,000 − .075 × 150,000 = 3,750; (3,750 + 10,000 + 10,000) × .05 = 1,187.50.
  7. Miscellaneous and SALT (line 173). Eligible components are 0, so the potential is 0. At the base it was 5,000 × .05 = 250.
  8. Existing unit test 1 (line 1). (3,000 + 12,000 + 1,000 + 2,000 − 10,000) × .05 = 400. Unit test 2 gives max(18,000 − 20,000, 0) → 0.
  9. 2021 mortgage insurance case (line 184). Interest 12,000 − 2,000 = 10,000; minus the 10,000 standard deduction gives 0.
  10. Component file, lines 4 and 14. 9,700 and 10,000.
  11. Component file, lines 24 and 34. 1,000 − 100 = 900; max(0, 200 − 300) = 0.
  12. Component file, line 44 (2021 non-itemizer). 10,000, with no allowance added.

Code and housekeeping:

  • Code. It is vectorized (where, max_, add) and has no hard-coded policy values.
  • Not a key variable. The new variable is a WI-gated float that no parameter lookup uses as a key, so the NH Add New Hampshire state supplementation for 2026 #10156 pattern doesn't apply.
  • Caller. The only caller of the potential is wi_itemized_deduction_credit, which is unchanged.
  • References. They are single, tuple-form and without titles. I verified their anchors (2020 instructions PDF page 17, 2021 instructions PDF page 16, Schedule 1 pages).
  • Changelog. It is a top-level .fixed.md file; the type is right.
  • No partner files are touched.

Batch checks:

Axiom line assessment

Line: axiom: TheAxiomFoundation/rulespec-us#1671 queued, extended with a comment.

  • Issue state. Add several integration tests #1671 is OPEN and labelled pe-parity (updated 2026-10-22 01:15 UTC). Its body requests the Wisconsin itemized deduction credit output, filed for Count gambling winnings in federal gross income and fix the wagering losses deduction #10070's gambling-loss rule.
  • The extension comment is dispatch-shaped. It gives the module context, corpus citations, verbatim 2020-2022 law, required outputs, companion tests from the forms and a pasteable finding.
  • Blockers are recorded:
    • ingestion of the missing 2020 Form 1 and instructions and the historical statute versions;
    • a signed corpus release and rulespec-us re-pin (axiom-corpus#335);
    • Max's per-run encoder approval.
  • It does not match the head (S3). Refresh it after S1. The queued status itself is valid.

CI status

29 pass, 0 failed, 0 pending.

  • Run. Run 39777867360 (pull_request, started 2026-10-22 12:22 UTC) tested head 7869d9713a. I re-checked gh pr checks 10311 at the end of this review.
  • Passed:
    • Baseline: all four states shards, plus contrib-hhs, household, irs, reform, rest-a, rest-b and ssa-usda.
    • Contrib: all nine shards.
    • Python: Microsimulation and both Rest shards.
    • Other: Household API Partners, PR validation, Package and compatibility, Quick Feedback, and codecov patch and project.
  • What CI didn't test. The run predates Take the 2020 charitable deduction for non-itemizers above the line #10186's merge (13:16 UTC), so CI hasn't tested the tree merged with main. It would pass anyway (S1 explains why).
  • Locally: I ran no model tests or probes. The traces above are static reads of the head and the merged tree.

Branch status

0 critical, 3 should and 3 suggestions are open at this head.

Verdict: REQUEST_CHANGES

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

The law checks out (Wis. Stat. 71.07(5)(a)2/7, the 2020-22 Schedule 1, the 2020 instructions), and all 12 cases hand-check at the PR's base. Three should-address items: (1) merge blocker: #10186 merged after this CI run and moved the 2020 deduction into charitable_contributions_ald, so formula_2020 subtracts nothing on the merged tree ($500 instead of $485 for a 2020 non-itemizer with $10k of gifts); subtract charitable_contributions_ald and add a 2020 case built from person inputs; (2) #10186 already removed the 2021 double count, so reword the title, changelog and body; (3) refresh the rulespec-us#1671 extension. Three suggestions. Full report in the comment above.

@MaxGhenis MaxGhenis changed the title Fix Wisconsin itemized credit counting charitable gifts twice in 2021 Align Wisconsin itemized credit with Schedule 1 and 2020 charity rules Oct 23, 2026
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

David, thanks. This answers your 10-22 review at d84a9768.

  1. Merge blocker (S1): main is merged (d112164a, after Take the 2020 charitable deduction for non-itemizers above the line #10186). The 2020 subtraction now reads charitable_contributions_ald, the amount actually claimed above the line, which is already zero for federal itemizers. New 2020 cases built from wages and cash gifts (single with supplied non-itemization, and joint with computed non-itemization) give a $9,700 component and a $485 potential credit.
  2. Scope (S2): the title, body and changelog now describe only what this PR still changes on top of main: the four explicit Schedule 1 components, the miscellaneous and SALT exclusions, the 2020 rule and the 2019 case. The 2021 case stays as a regression guard after Take the 2020 charitable deduction for non-itemizers above the line #10186.
  3. Parity (S3): the rulespec-us#1671 mapping is refreshed to this head.
  4. Suggestions: the reference polish (G2) and a computed-itemization case (G3) are in. G1 is skipped: the component list is already explicit and sourced inline, and a separate parameter would add indirection without changing behaviour.

176 targeted tests pass. An independent delta review is queued.

@MaxGhenis
MaxGhenis requested a review from DTrim99 October 23, 2026 04:30

This branch has not been deployed

No deployments
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.

2 participants