Skip to content

Fix state taxpayer-choice bugs: NJ property tax election and NE itemized deductions - #10654

Open
MaxGhenis wants to merge 5 commits into
mainfrom
claude/state-choice-bugs-continued-3mhani
Open

MaxGhenis wants to merge 5 commits into
mainfrom
claude/state-choice-bugs-continued-3mhani

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Fixes two state taxpayer-choice bugs found in a review of the taxpayer-choice inventory, and reports the other five items with the evidence from running each claimed household at main.

This continues an earlier session's work on the same items. That session pushed nothing, so this branch starts from main.

The VM running this session could not reach any statute or agency site (Iowa, Virginia, Nebraska, Oregon, New York, New Jersey and New Mexico sites, irs.gov and law.cornell.edu were all blocked). Each fix rests on the code and on the references already in the repo. Where an item turns on text that couldn't be read, it is left unchanged, and the text needed is named below.

Items

# State Claim Status
1 IA Alternate tax compared per spouse, not on combined amounts Reproduced; not changed (rule text unreachable)
2 VA Spouse tax adjustment lacks the worksheet's $259 shortcut Reproduced; not changed (rule text unreachable)
3 NJ Property tax deduction-or-credit choice ignores the refundable NJ CTC and CDCC FIXED
4 NE Itemized deductions aren't federal itemized minus income taxes FIXED
5 NY Federal non-itemizers get both the tuition deduction and the tuition credit Reproduced; already covered by open #10100
6 OR No zero standard deduction for a separate filer whose spouse itemizes Reproduced; not changed (rule text unreachable)
7 NM 40% capital gains element is 0 from 2025 Not a parameter error. The repo's own reference ties the zero to a 2025 law change; the remaining gap is a missing input

3. New Jersey property tax election: FIXED

nj_taking_property_tax_deduction chose the deduction only when its tax saving beat the $50 credit. The deduction also lowers nj_taxable_income. Besides the main tax, nj_ctc and nj_cdcc are the only NJ variables that read it, and both are refundable credits whose amounts step down with taxable income. The choice now adds the change in those two credits to the tax saving. The CTC child count moved to the new nj_ctc_qualifying_children, so the election and nj_ctc share it.

The existing code treats this as the filer's choice, and the change keeps that. It only makes the comparison count everything the deduction changes. Worksheet H compares only the tax saving with the $50 credit, so a filer who follows it keeps the credit in the witness below and gives up $197.25.

Witness (2023, single parent, one child aged 3, $33,000 wages, $15,000 rent):

  • At main: taxable income $30,500. PE keeps the $50 credit and pays a $800 NJ CTC. nj_income_tax is −$1,253.01.
  • With this PR: PE takes the $2,700 deduction (18% of rent). Taxable income is $27,800, the NJ CTC is $1,000 and nj_income_tax is −$1,450.26.
  • Hand check: the tax is 280 + 10,500 × 1.75% = $463.75 at $30,500 and 280 + 7,800 × 1.75% = $416.50 at $27,800. The $47.25 saving is below $50, but the CTC rises by $200. The net gain is 47.25 + 200 − 50 = $197.25, matching the difference in nj_income_tax.

Overlap. #10043 (open) drops a child from the New Jersey child tax credit when someone can claim the filer as a dependent, in the child count this PR moves. Whoever lands second puts that ~filer_is_dependent condition into nj_ctc_qualifying_children.py, not back into nj_ctc.py, so the election and the credit count the same children.

4. Nebraska itemized deductions: FIXED

Neb. Rev. Stat. 77-2716.01(4) gives a federal itemizer the greater of the Nebraska standard deduction and federal itemized deductions "except for the amount for state or local income taxes included in federal itemized deductions before any federal disallowance". The Form 1040N booklet's line 8 says the same: enter the Schedule A line 5a income taxes even when the SALT cap limited line 5e, and nothing when line 5a holds sales taxes. (This session couldn't fetch the Legislature's site or the booklet. The quoted words are from the text the hub supplied.)

ne_itemized_deductions now does that:

  • Form 1040N line 7, Schedule A line 17: itemized_taxable_income_deductions, the federal total after any section 68 reduction. On main as built (Count gambling winnings in federal gross income and fix the wagering losses deduction #10070 still open), this total does not include wagering_losses_deduction. taxable_income_deductions_if_itemizing adds those losses separately. Count gambling winnings in federal gross income and fix the wagering losses deduction #10070 moves them into itemized_deductions.yaml, and Nebraska picks them up then with no change here.
  • Line 8: when line 5a holds income taxes (state_withheld_income_tax + local_income_tax above state_sales_tax + local_sales_tax, the same comparison state_and_local_sales_or_income_tax makes), subtract those income taxes in full, with no cap. A tie counts as sales tax, and then nothing is subtracted.
  • Floor at 0. Line 9 can fall below zero, but line 10 takes the larger of lines 6 and 9, so the floor changes no tax.

Witnesses:

  • 2025, single, $700,000 wages, $30,000 real estate tax, $35,000 income tax, $20,000 mortgage interest. The federal SALT cap is 40,000 − 30% × 200,000, floored at $10,000. Federal itemized deductions are 10,000 + 20,000 = $30,000. Nebraska: 30,000 − 35,000, floored at 0. ne_taxable_income takes the $8,600 standard deduction: 700,000 − 8,600 = $691,400. At 6df1752b this was $30,000 of itemized deductions and $670,000 of taxable income.
  • 2024, single, $100,000 wages, $8,000 income tax, $5,000 real estate tax, $15,000 mortgage interest. The SALT deduction is min(13,000, 10,000) = $10,000, and federal itemized deductions are $25,000. Nebraska: 25,000 − 8,000 = $17,000. At 6df1752b this was $20,000, because real estate taxes counted first inside the cap and only $5,000 of income tax was removed.

Before this PR, main gave itemized_deductions_less_salt + capped_property_taxes, which dropped sales taxes and could exceed the federal total from 2025. Both errors stay fixed: the sales-tax filer still gets $23,000 and the uncapped income-tax filer still gets $20,000.

1. Iowa alternate tax: reproduced, not changed

ia_base_tax_indiv takes min(ia_regular_tax_indiv, ia_alternate_tax_indiv) for each spouse. ia_alternate_tax_indiv is the unit's alternate tax prorated by ia_prorate_fraction, so the per-spouse sum is never above min(sum of regular, unit alternate), and can be below it. Witness, 2022, married filing separately on a combined return:

Wages (head, spouse) Regular Alternate Per-spouse sum Min on combined amounts
$12,000, $4,000 212.53, 6.07 159.94, 53.31 166.00 213.25
$14,000, $2,000 295.33, 0 186.59, 26.66 186.59 213.25

Needed to decide: the Iowa Alternate Tax Worksheet (41-145), lines 7–11, for filing status 3 and 4, and the alternate-tax paragraph of Iowa Code 422.5 for 2021–2022. Those show whether the smaller-of comparison is made per spouse or on combined amounts. The path applies only while married_filing_separately_on_same_return.availability is true.

2. Virginia spouse tax adjustment: reproduced, not changed

PE's worksheet never reaches the $259 cap. For two earners each above $17,000, va_spouse_tax_adjustment is $257.50, which is 2 × tax($17,000) − tax($34,000) at the 2/3/5/5.75% rates. Witnesses (2023, two earners at $30k/$30k, $40k/$25k, $26k/$26k and $100k/$30k) all give $257.50. The existing integration test expects $257.50 too. The cap.yaml comment says the legal code doesn't explicitly include the adjustment.

Needed to decide: the 2021–2025 Form 760 Spouse Tax Adjustment worksheet (instructions p. 19), for the exact condition under which it enters $259 directly. Also needed is any statutory basis for the adjustment. The review cited Va. Code 58.1-332, which the repo doesn't cite. If the statute fixes the amount by the tax difference, statute-first would keep $257.50.

5. New York tuition: reproduced, already covered by #10100

Witness (2023, federal non-itemizer, $10,000 qualified tuition): ny_itemizes is false because the filer doesn't itemize federally, so ny_college_tuition_credit is $400. But ny_deductions = max(itemized, standard) still takes the $17,000 NY itemized amount, which includes the $10,000 tuition deduction. Open PR #10100 changes ny_deductions to follow ny_itemizes. That removes the overlap, since the credit already requires ~ny_itemizes. That PR was updated today, so this one leaves New York alone.

6. Oregon: reproduced, not changed

or_standard_deduction never reads separate_filer_itemizes. Witness (2024, separate filer, spouse itemizes, $60,000 wages): federal standard_deduction is 0, but or_standard_deduction and or_deductions are $2,745. Needed: ORS 316.695, the subsection on separate returns, and the OR-40 instructions on it. DC (dc_standard_deduction) and Idaho (id_itemizes) already read separate_filer_itemizes, so the change would be one line once the rule is confirmed.

7. New Mexico: not a parameter error

uncapped_element_percent.yaml sets 40% through 2024 and 0 from 2025. Its own reference is titled: "amends NMSA 7-2-34 to restrict the 40% element to business-sale gains, effective 2025-01-01". With no input for gains from the sale of a business, PE gives everyone the capped element only: $100,000 of long-term gains yields a $40,000 deduction in 2024 and $2,500 in 2025. That is a missing feature, not a wrong value. Two caveats: that reference names HB0037, while nm_net_capital_gains_deduction cites 2024 HB252 for the 2025 text, and neither could be read here.

Tests

  • nj_taking_property_tax_deduction.yaml: 8 new cases, 11 in all. They cover the CTC bracket crossing, the same case without a child, a separate filer with a child (no NJ CTC, so the $50 credit stays), CDCC rate crossings each way, a deduction that lands taxable income exactly on $30,000 (the 50% NJ CDCC rate, as nj_cdcc reads it), an end-to-end renter household, and a separate filer who lives with the spouse and so weighs the deduction against half the credit, $25.
  • ne_itemized_deductions.yaml: 8 cases, each hand-computed in its comments. The new or changed cases are the 2025 witness (now with wages, plus ne_taxable_income), the 2024 binding cap, a tie between income and sales taxes, and three capped cases whose values change: unit test 1 goes from 35,000 to 31,000, unit test 2 from 16,000 to 15,000, and the 2023 income-above-cap case from 19,000 to 13,000. The sales-tax filer (23,000) and the uncapped income-tax filer (20,000) are unchanged. At 6df1752b, 5 of the 8 fail; the tie case passes at both heads.
  • Mutants (each in its own process, code restored after). NJ, against the 10 cases: dropping the CTC term failed 2 (the CTC bracket case, the end-to-end renter); dropping the CDCC term failed 2 (the CDCC rate rise, the $30,000 case); dropping * nj_ctc_eligible failed 1 (the separate filer); dropping right=True from the after-deduction CDCC rate failed 1 (the $30,000 case). Against the 11 cases, dropping the halving of the credit for a cohabiting separate filer failed 1 (that filer's case). NE, against the 8 cases: treating every filer as an income-tax claimer failed 2 (sales-tax filer, tie). Capping the subtracted income taxes at salt_deduction failed 2 (2025 witness, 2023 above-cap case). Dropping the floor failed 1. Using >= failed the tie. The old real-estate-first allocation (6df1752b) failed 5.
  • Property checks, run locally and not committed (CLAUDE.md prefers YAML to new simulation-building Python tests):
    • NJ: 300 random 2023 households had income $10k–80k, rent $0–30k, 0–2 children and childcare. Of the 266 eligible, 9 elections were worse than the alternative at main and 0 after.
    • NE (earlier round, not rerun): 300 random 2025 filers. At main, 82 had NE itemized deductions above the federal itemized total. With the fix, the deduction is at most the federal total by construction.

impact: the hub will measure

axiom: TheAxiomFoundation/rulespec-us#2037 and TheAxiomFoundation/rulespec-us#2038 queued


Generated by Claude Code

…mized deductions on federal SALT as claimed

New Jersey: the deduction-or-credit choice compared only the tax saving
with the $50 credit, but the deduction also lowers NJ taxable income, which
sets the refundable NJ child tax credit and the NJ child and dependent care
credit. A filer just above $30,000 kept the $50 credit and lost a $200 child
tax credit increase. The choice now counts those credit changes. The child
count moves to nj_ctc_qualifying_children so both formulas share it.

Nebraska: itemized deductions added real estate taxes capped by the static
SALT cap to the non-SALT deductions. That dropped sales taxes claimed on
Schedule A and, from 2025, could exceed the federal SALT deduction after
the cap phase-down. They now start from the federal SALT deduction and
remove only the income taxes in it, counting real estate taxes first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6L5ENJPWh7rPevAeE7
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. This continues an earlier session's work on the state taxpayer-choice items; that session pushed nothing, so this branch starts from main. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: 6df1752b37433d6198ed6ceaab2b44ef23e9b669 (5404c25 plus a merge of main at adea703; main had changed only California files).

This continues an earlier session's work on these items. It pushed nothing (its branch never existed), so there were no earlier commits to keep or fix. This PR is on branch claude/state-choice-bugs-continued-3mhani, the branch this cloud session was assigned, not the brief's fix-state-choice-bugs-ia-va-nj-ne-ny-or-nm, which still returns 404.

Source access: this VM couldn't reach any statute or agency site. The Iowa, Virginia, Nebraska, Oregon, New York, New Jersey and New Mexico hosts, irs.gov, govinfo, uscode.house.gov and law.cornell.edu all failed (proxy 403 or DNS). Nothing below quotes a source fetched in this session. The only quotations come from text already in the repo, and they say so.

Per item

# Item Result Where
1 IA alternate tax per spouse Reproduced; BLOCKED (rule text unreachable), not changed ia_base_tax_indiv.py:18-23
2 VA $259 shortcut Reproduced; BLOCKED (rule text unreachable), not changed va_spouse_tax_adjustment.py:53-55, cap.yaml
3 NJ property tax election FIXED nj_taking_property_tax_deduction.py:76-98, new nj_ctc_qualifying_children.py, nj_ctc.py:25
4 NE itemized deductions FIXED ne_itemized_deductions.py:17-41
5 NY tuition deduction and credit Reproduced; ALREADY_COVERED by open #10100 ny_deductions.py, ny_college_tuition_credit_eligible.py:13
6 OR separate filer, spouse itemizes Reproduced; BLOCKED (ORS 316.695 unreachable), not changed or_standard_deduction.py
7 NM 40% element 0 from 2025 NOT A PARAMETER ERROR; the repo's reference cites a 2025 law change; feature gap uncapped_element_percent.yaml

The witnesses, hand computations and what each blocked item needs are in the PR body.

Judgment calls

  1. NJ is the filer's choice. The existing variable already models the deduction-or-credit pick as a choice. I kept that and widened only what the comparison counts. The principle applied is taxpayer choice (P4): a filer would weigh everything the deduction changes. The comparison uses the same uncapped bracket calls nj_ctc and nj_cdcc use, so the two stay in step.
  2. NE allocation under the cap (unverified). When the federal SALT cap binds and income taxes are claimed, I count real estate taxes first, as the old formula did. A Nebraska worksheet may allocate differently. I couldn't read 77-2716 or the current 1040N booklet. The governing words quoted come from the booklet excerpt already in ne_taxable_income.py.
  3. NE tie. When income taxes equal sales taxes, the filer is treated as claiming sales taxes and keeps them. That is the taxpayer-favourable pick, and the federal max_ is indifferent.
  4. NE existing cases. The two old cases in ne_itemized_deductions.yaml didn't say which tax Schedule A claims. PE's computed sales tax made them sales-tax filers under the fix. I added explicit income-tax inputs so they test what their expected values assume.
  5. NY: I left it to Choose New York's itemizing election by State plus City tax and require federal itemizing only before 2018 #10100, since it is open and was updated today.
  6. axiom: line. The brief both requires axiom: (hub files pe-parity before review) and forbids writing it. I used axiom: needed, CLAUDE.md's form for parity work left to a maintainer, so the hub can replace it.
  7. No committed Hypothesis tests. CLAUDE.md asks for YAML over new simulation-building Python tests. I ran the properties locally instead (below) and can add them if the hub wants them in CI.

Tests

  • All 154 YAML files under the NJ and NE test trees, one file per process: 1,175 passed, 0 failed (before the merge of main). After the merge, I re-ran the two changed files: NJ election 8/8 and NE itemized 6/6.
  • New cases: 5 NJ (CTC crossing, same without a child, CDCC crossing each way, an end-to-end renter) and 4 NE (sales-tax filer, income-tax filer, 2025 phased-down cap, binding cap).
  • Hand computations are in each case's comments. NJ end-to-end: tax $463.75 at $30,500 and $416.50 at $27,800, a $47.25 saving. With the $200 CTC gain and the $50 credit forgone, the net gain is $197.25, which matches the change in nj_income_tax from −$1,253.01 to −$1,450.26.
  • Mutants, each in its own process with the code restored after; all killed:
    • NJ without the CTC term: 2 fail.
    • NJ without the CDCC term: 1 fails.
    • NE with every filer treated as an income-tax claimer: 1 fails.
    • NE with real estate taxes uncapped by the SALT deduction: 1 fails.
  • Property checks, run locally and not committed:
    • NJ: 300 random 2023 households, 266 of them eligible. The elected option was worse than the alternative for 9 households at main and for 0 after.
    • NE: 300 random 2025 filers. NE itemized deductions exceeded the federal itemized total for 82 at main and for 0 after.
  • No microsimulation was run; impact is for the hub.

CI

The draft was skipped: the Pull request run at 6df1752b completed with conclusion skipped (https://github.com/PolicyEngine/policyengine-us/actions/runs/41735413844). CI hasn't run.

Proposed follow-ups

  • Oregon and Oklahoma itemized deductions add statically capped real estate taxes. or_itemized_deductions and ok_itemized_deductions use capped_property_taxes, the same pattern fixed here for Nebraska. From 2025 they can exceed the federal SALT deduction after the phase-down. Each needs its own statute check.
  • NJ child tax credit at exactly $30,000 of taxable income. credits/ctc/amount.yaml with calc() gives $800 at $30,000, while the NJ CDCC uses right=True and gives 50% there. If N.J.S.A. 54A:4-17.1 says "$30,000 or less" (unverified), each bracket edge is off by one dollar.
  • New Mexico business-sale capital gains element. Add an input for gains from the sale of a business and apply the 40% element to it from 2025. Also reconcile the HB0037 and HB252 citations between uncapped_element_percent.yaml and nm_net_capital_gains_deduction.py.
  • NJ election below the filing threshold. When AGI is at or below the filing threshold, NJ tax is zero, but the election still counts a bracket-schedule tax saving. It may take the deduction when the $50 credit is worth more. I didn't reproduce this.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

…apped

Neb. Rev. Stat. 77-2716.01(4) allows federal itemized deductions except
the state or local income taxes "before any federal disallowance", and the
Form 1040N line 8 instructions say to enter the line 5a income taxes even
when the SALT cap limited line 5e. The prior formula counted real estate
taxes first inside the capped SALT deduction and removed only the rest, so
it left too much whenever the cap bound. Start from
itemized_taxable_income_deductions (Schedule A line 17), subtract the
income taxes in full when line 5a holds them, and floor at zero.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6K6CPev5JwhCMUY7j6
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: e9502f5dfa0386e28bcac35c50bc5651d30b2b06. That is one commit on top of 6df1752b37433d6198ed6ceaab2b44ef23e9b669, the head the item named. No other commits landed on the branch while I worked. The New Jersey half is untouched.

Ownership note: the last push before mine (22:56Z) was inside the 6-hour window, but it was the named head, and its writer handed off at 22:59Z, before this item was filed. I took it as finished work, not an active writer.

Source access: nebraskalegislature.gov failed DNS and web.archive.org was refused, so I couldn't fetch 77-2716.01 or the 1040N booklet. The statute and booklet words in the code, body and here are the text the hub supplied. I didn't verify them independently.

Items

  1. Rewrite ne_itemized_deductions. FIXED.

    • policyengine_us/variables/gov/states/ne/tax/income/deductions/ne_itemized_deductions.py:22: starts from itemized_taxable_income_deductions (Schedule A line 17, after any section 68 reduction).
    • On main as built, Count gambling winnings in federal gross income and fix the wagering losses deduction #10070 is still open, so this total does not include wagering_losses_deduction (it is added separately in deductions_if_itemizing.yaml). Once Count gambling winnings in federal gross income and fix the wagering losses deduction #10070 moves the losses into itemized_deductions.yaml, Nebraska picks them up with no change.
    • :28-33: when state_withheld_income_tax + local_income_tax is strictly above state_sales_tax + local_sales_tax, the formula subtracts the income taxes in full, uncapped; otherwise 0.
    • :37: floored at 0.
    • The reference now leads with 77-2716.01; the old tuple cited 77-2716. The changelog fragment is reworded to match.
  2. Cases. Done; hand values are in the comments of .../ne/tax/income/deductions/ne_itemized_deductions.yaml.

    • 2025 witness, rebuilt with wages: SALT cap max(40,000 − 0.3 × 200,000, 10,000) = 10,000. Federal itemized: 10,000 + 20,000 = 30,000. NE: max(0, 30,000 − 35,000) = 0. ne_taxable_income: 700,000 − 8,600 = 691,400. At 6df1752: 30,000 and 670,000.
    • 2024 binding cap: SALT min(13,000, 10,000) = 10,000; federal 25,000. NE: 25,000 − 8,000 = 17,000. At 6df1752: 20,000.
    • Tie (2023): income 3,000 = sales 2,000 + 1,000, both inputs given. Federal: 3,000 + 5,000 + 15,000 = 23,000. NE: 23,000 (nothing removed).
    • Sales-tax filer (23,000) and uncapped income-tax filer (20,000): unchanged. Their inputs moved from itemized_deductions_less_salt to deductible_interest_expense, because the new formula reads the federal total.
    • Three existing capped cases changed value, because they encoded the old allocation:
      • Unit test 1: 36,000 − 5,000 = 31,000 (was 35,000).
      • Unit test 2: 20,000 − 5,000 = 15,000 (was 16,000).
      • 2023 income-above-cap case: 25,000 − 12,000 = 13,000 (was 19,000).
    • At 6df1752, 5 of the 8 fail: unit tests 1 and 2, the 2025 witness, the 2024 binding cap and the 2023 above-cap case. All 8 pass after the fix. The tie case passes at both heads, because the old formula also treated a tie as sales tax. Here it guards the strict > (mutant below), not the bug.
  3. Mutants, each in its own process against the 8 NE cases, with the code restored after:

    Mutant Fails Killed by
    Every filer treated as an income-tax claimer (PR mutant 1) 2 sales-tax filer, tie
    Real estate taxes first inside the cap, i.e. the code at 6df1752 (the PR's mutant 2 targeted that allocation, which no longer exists) 5 listed in item 2
    New: subtracted income taxes capped at salt_deduction 2 2025 witness, 2023 above-cap case
    No floor at 0 1 2025 witness
    >= instead of > 1 tie
    total_itemized_taxable_income_deductions (before the section 68 reduction) 0, survives No case runs in 2026+, where the reduction is non-zero
  4. Body. Rewritten. The Nebraska section now:

    • quotes the 18-word operative clause of (4), not the whole subsection, to stay within the 25-word quote limit;
    • gives both witnesses with hand values;
    • drops the old allocation paragraph and the "Judgment call (unverified)".

    The NE test and mutant bullets are updated. The session link line is deleted. impact: the hub will measure and axiom: needed are left as they were for the hub. The body ends with the standard footer, which the server rewrote into its own form.

  5. Runs, one file per process at e9502f5:

    File Passed
    ne_itemized_deductions.yaml 8/8
    ne_taxable_income.yaml 5/5
    ne_income_tax_before_credits.yaml 4/4
    rates/ne_income_tax_rates_2026.yaml 3/3
    ne_integration.yaml 1/1
    gov/irs/salt_refund_integration.yaml 38/38
    nj_taking_property_tax_deduction.yaml 8/8

    The four ne_taxable_income files are every NE test file that names that variable. No microsimulation was run.

CI

The Pull request run at e9502f5 completed as skipped, because the PR is a draft: https://github.com/PolicyEngine/policyengine-us/actions/runs/41744533541. CI hasn't run.

Judgment calls

  • Line 17 includes the section 68 reduction. I read Schedule A line 17 as the federal total after any section 68 reduction, so I used itemized_taxable_income_deductions. The hub should confirm that the 2026+ Schedule A line 17 nets out the 2/37 limitation; the surviving mutant above is the case that would separate the two readings.
  • No wagering losses for now. I didn't add wagering_losses_deduction alongside the total. Line 17 includes gambling losses, so Nebraska misses them until Count gambling winnings in federal gross income and fix the wagering losses deduction #10070 merges, but adding them here would double-count after Count gambling winnings in federal gross income and fix the wagering losses deduction #10070.
  • The NE property check wasn't rerun. The earlier round's random-filer check was not repeated. With the fix, the result can't exceed the federal total, because a non-negative amount is subtracted and the result is floored.

Proposed follow-ups


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Hub review in progress

Reviewing head e9502f5dfa0386e28bcac35c50bc5651d30b2b06. Findings so far; the final review follows as a separate comment.

  • Witnesses reproduce. NJ 2023 renter: at main nj_income_tax is -1,253.01 with the $50 credit; at head it is -1,450.26 with the deduction, a $197.25 difference. NE 2025 witness: at main ne_itemized_deductions is 50,000, above the 30,000 federal total; at head it is 0 and ne_taxable_income is 691,400.
  • Changed and reader test files pass at head, one file per process. ne_itemized_deductions 8/8, nj_taking_property_tax_deduction 8/8, and 38, 4, 3, 5, 1, 2, 19, 8 and 6 in the reader files.
  • NE mutants match the hand-off: 2, 2, 1 and 1 fail. The pre-section-68 total survives.
  • NJ mutants: dropping the CTC gain fails 2 cases and dropping the CDCC gain fails 1. Dropping nj_ctc_eligible from the election survives (8/8): no case covers a separate filer with a child. That's a test gap (P3).
  • Source hosts (Nebraska Legislature, Nebraska DOR, irs.gov, govinfo, uscode.house.gov, ecfr.gov, the NJ Legislature, Justia, web.archive.org) all refuse connections from this VM.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review
VERDICT: APPROVE
e9502f5
METHODOLOGY_CHOICE: yes

Independent review of round 1 at the head above. The head hasn't moved since e9502f5dfa. Both halves compute what the PR says, and every hand value I recomputed matches a run. No finding is P1. The methodology choices are the New Jersey comparison, which departs from Worksheet H, and the Nebraska line 7 total after section 68. They are listed so the hub can rule on them.

Findings

P2-1. New Jersey: the election departs from Worksheet H, and nothing records that as a reading

policyengine_us/variables/gov/states/nj/tax/income/property_tax/nj_taking_property_tax_deduction.py:93-98

  • Scenario. A 2023 renter with one child has $30,500 of NJ taxable income and a $2,700 deduction. Worksheet H, as the PR body describes it, compares only the $47.25 tax saving with the $50 credit, so the filer keeps the credit. The PR also counts the $200 NJ CTC gain and takes the deduction. Run: nj_income_tax is −1,253.01 at main and −1,450.26 at the head.
  • Why it matters. The filer ends up better off, but PE no longer follows the form's worksheet. The election statute (54A:3A-17 to -20) is unread: this VM couldn't reach it, and neither could the author's. If the statute leaves the choice to the filer, the worksheet is a shortcut and the PR's reading follows the statute ("the operative words govern over form shortcuts"). If the statute ties the choice to the tax saving, the PR is wrong.
  • What I ask of the hub. Decide whether this is a form-versus-statute reading for source_conflicts/candidates.yaml (CONTRIBUTING.md, Source conflicts, step 1). Whatever the ruling, line 22 is now stale. Replace
    # follows NJ-1040 form Worksheet H
    with
    # Worksheet H compares the tax saving with the credit; this also counts the change in the refundable NJ CTC and CDCC (below).

P2-2. New Jersey: #10043 rewrites the lines this PR moves, and its rule must go into nj_ctc_qualifying_children

Open PR #10043 (head 6f241acce1) edits the child count inside nj_ctc.py. It drops dependents when the filer can be claimed as a dependent elsewhere (IRC 152(b)(1)). This PR moves that count into nj_ctc_qualifying_children, which the election also reads.

P3-1. New Jersey: no case covers a separate filer, so dropping nj_ctc_eligible from the election survives

nj_taking_property_tax_deduction.py:81-83

  • Mutant. ctc_children = tax_unit("nj_ctc_qualifying_children", period), without * nj_ctc_eligible.
  • Result. It passes all 8 cases in nj_taking_property_tax_deduction.yaml.
  • Scenario. A separate filer with a child, $30,500 taxable income and a $2,700 deduction has a $47.25 saving, and the CTC can't change. The filer should keep the $50 credit. The mutant counts a $200 CTC gain and takes the deduction.

I ran this case at the head (passes) and under the mutant (fails, 1 failed). Add it:

- name: Separate filer with a child gets no NJ child tax credit gain, so keeps the $50 credit
  # Tax saving 463.75 - 416.50 = 47.25 < 50; a separate filer cannot claim the
  # NJ child tax credit, so its bracket change adds nothing.
  period: 2023
  absolute_error_margin: 0
  input:
    people:
      parent:
        age: 35
      child:
        age: 3
        is_tax_unit_dependent: true
    tax_units:
      tax_unit:
        members: [parent, child]
        filing_status: SEPARATE
        cohabitating_spouses: false
        nj_property_tax_deduction_eligible: true
        nj_potential_property_tax_deduction: 2_700
        nj_taxable_income_before_property_tax_deduction: 30_500
        cdcc: 0
    households:
      household:
        members: [parent, child]
        state_code: NJ
  output:
    nj_ctc_qualifying_children: 1
    nj_ctc_eligible: false
    nj_taking_property_tax_deduction: false

P3-2. New Jersey: no case sits on a CDCC bracket edge, so dropping right=True survives

nj_taking_property_tax_deduction.py:89

  • Mutant. p_credits.cdcc.rate.calc(taxable_income_after_deduction).
  • Result. It passes all 8 cases.
  • Scenario. nj_cdcc uses right=True, so taxable income of exactly $30,000 gets the 50% rate. Under the mutant the election reads 40% there and disagrees with the credit it predicts.

This case passes at the head and fails under the mutant:

- name: Deduction that lands NJ taxable income exactly on $30,000 gets the 50% NJ CDCC rate
  # Tax saving: 500 x 1.75% = 8.75. At $30,000 the NJ CDCC rate is 50%, not
  # 40%: 8.75 + 10% x $600 = 68.75 > 50.
  period: 2023
  absolute_error_margin: 0
  input:
    nj_property_tax_deduction_eligible: true
    nj_potential_property_tax_deduction: 500
    nj_taxable_income_before_property_tax_deduction: 30_500
    filing_status: SINGLE
    cdcc: 600
    state_code: NJ
  output:
    nj_taking_property_tax_deduction: true

P3-3. Nebraska: line 7 before or after section 68 is still open, and so is every year ≤2017

policyengine_us/variables/gov/states/ne/tax/income/deductions/ne_itemized_deductions.py:22

  • Mutant. Using total_itemized_taxable_income_deductions (before the section 68 reduction) still passes 8/8.
  • The case that separates the readings. I derived it and ran it at the head: 2026, single, $1,000,000 wages, $30,000 real estate tax, $8,000 income tax, $40,000 mortgage interest.
    • SALT deduction: $10,000. The cap phases down to its floor.
    • Federal total: 10,000 + 40,000 = $50,000.
    • Section 68 reduction: 2/37 × min(50,000, taxable income over the 37% threshold) = 2/37 × 50,000 = $2,702.70. PE agrees: itemized_taxable_income_deductions_reduction is 2,702.70.
    • After the reduction (the PR's reading): 47,297.30 − 8,000 = $39,297.30. The run gives that, and ne_taxable_income is 960,702.69.
    • Before it: 50,000 − 8,000 = $42,000.
    • Main gives $70,000.
  • Which reading the sources support. I couldn't reach the 2026 Schedule A, IRC 63(d) or 68, or the Nebraska statute, so I can't say. The PR's reading matches PE's federal model, whose taxable income uses the post-reduction itemized_taxable_income_deductions. That only shows consistency, not law.
  • The same choice binds pre-2018 years (Pease), where no case runs either.
  • For the hub. Once someone reads the 2026 form, add this case with whichever value it supports.

P3-4. Nebraska: gamblers lose their wagering losses on main and on this head; #10070 fixes both, in either order

Witness: 2024, single, $100,000 wages, $30,000 gambling winnings and $30,000 losses, $3,000 real estate tax, $4,000 income tax, $5,000 mortgage interest. Schedule A line 17 should be 3,000 + 4,000 + 5,000 + 30,000 = 42,000, and Nebraska should give 42,000 − 4,000 = 38,000.

Code ne_itemized_deductions
main 8,000
this head 8,000
main + #10070 (local trial merge) 38,000
this head + #10070 (local trial merge) 38,000

The two PRs touch no common file, and the merge reports no conflict. The landing order doesn't matter, and this PR makes nothing worse. Follow-up after #10070 lands: add this gambler case to ne_itemized_deductions.yaml.

Checked and sound

Defects reproduce at main (25c4253483). I ran a witness script against each tree.

  • NJ witness: main keeps the credit, nj_income_tax −1,253.01. The head takes the deduction: −1,450.26.
  • NE 2025 witness: main gives ne_itemized_deductions 50,000, above the 30,000 federal total, because capped_property_taxes ignores the 2025 phase-down. The head gives 0, and ne_taxable_income is 691,400.
  • NE 2024 binding cap: main 20,000, head 17,000.

NJ hand check of the $197.25 (computed before reading the code).

  • Exemptions: 1,000 + 1,500 = 2,500, so taxable income is 33,000 − 2,500 = 30,500.
  • Tax: 280 + 10,500 × 1.75% = 463.75.
  • Deduction: 18% × 15,000 = 2,700, so taxable income is 27,800 and tax is 280 + 7,800 × 1.75% = 416.50.
  • CTC: $800 above $30,000 and $1,000 at or below, from ctc/amount.yaml for 2023.
  • Credit route: 463.75 − 800 − 50 = −386.25. Deduction route: 416.50 − 1,000 = −583.50. The difference is 197.25, which matches −1,253.01 versus −1,450.26.

NE hand checks, all 8 cases, matching the YAML comments:

Case Federal itemized Income taxes removed Nebraska
Unit test 1 2,000 + 24,000 + 10,000 = 36,000 5,000 31,000
Unit test 2 3,000 + 7,000 + 10,000 = 20,000 5,000 15,000
Sales-tax filer 23,000 0 (sales 3,000 > income 1,000) 23,000
Uncapped income-tax filer 22,000 2,000 20,000
2025 witness 30,000 35,000 0, so ne_taxable_income = 700,000 − 8,600 = 691,400
2024 binding cap 25,000 8,000 17,000
2023 income above cap 25,000 12,000 13,000
Tie 23,000 0 (3,000 = 2,000 + 1,000) 23,000

The NE rule in code.

  • The formula subtracts state_withheld_income_tax + local_income_tax in full when that sum is strictly above state_sales_tax + local_sales_tax. That is the same pair state_and_local_sales_or_income_tax compares for federal line 5a.
  • It doesn't branch on filing status or year, so the uncapped subtraction holds for every status, the MFS $5,000 cap included.
  • It floors at 0.
  • The only reader is ne_taxable_income, which takes max_(itm_ded, std_ded) for federal itemizers. state_itemized_deductions lists it, but no non-test variable reads that total.

NE tests, before and after. The head's NE file fails 5 cases with the 6df1752b formula (unit tests 1 and 2, the 2025 witness, the 2024 binding cap, the 2023 above-cap case) and 7 with main's. All 8 pass at the head.

NJ readers of nj_taxable_income.

  • nj_main_income_tax, nj_ctc and nj_cdcc read it, plus taxsim_state_taxable_income, a reporting sum.
  • nj_non_refundable_credits has no components, so the full main-tax saving reaches nj_income_tax.
  • The election itself moves nj_property_tax_credit, which the comparison already counts.
  • The filing-threshold zeroing can't create a phantom saving, because nj_property_tax_deduction_eligible requires AGI above the threshold.
  • nj_eitc doesn't read taxable income. No reader goes uncounted.

NJ structure.

  • No cycle: the election reads nj_ctc_qualifying_children (age and dependency), nj_ctc_eligible (filing status), federal cdcc and nj_taxable_income_before_property_tax_deduction. None of them depends on the election.
  • nj_ctc_qualifying_children has the same expression nj_ctc had on main, and nj_ctc.yaml passes 19/19.
  • taxable_income_after_deduction is floored at 0, like nj_taxable_income.
  • The CTC term applies nj_ctc_eligible as nj_ctc's defined_for does.
  • The election also runs in 2020 and 2021 (scratch cases, passed), where the CTC is 0.

NJ tests at main. The head's NJ file fails 3 cases on main's code (the CTC case, which can't load nj_ctc_qualifying_children, the CDCC case and the end-to-end renter) and passes 5. All 8 pass at the head.

Runs at the head, one file per process, all passing:

File Passed
ne_itemized_deductions.yaml 8
nj_taking_property_tax_deduction.yaml 8
salt_refund_integration.yaml 38
ne_income_tax_before_credits.yaml 4
ne_income_tax_rates_2026.yaml 3
ne_taxable_income.yaml 5
ne_integration.yaml 1
nj_taxable_income.yaml 2
nj_ctc.yaml 19
nj_cdcc.yaml 8
nj_main_income_tax.yaml 6

Mutants, each in its own process in a scratch worktree, restored after (git status clean):

Mutant Fails Killed by
NE: every filer an income-tax claimer 2 sales-tax filer; tie
NE: subtraction capped at salt_deduction 2 2025 witness; 2023 above-cap case
NE: no floor 1 2025 witness
NE: >= 1 tie
NE: pre-section-68 total 0, survives none (P3-3)
NJ: drop CTC gain 2 CTC bracket case; end-to-end renter
NJ: drop CDCC gain 1 CDCC rate-rise case
NJ (mine): drop nj_ctc_eligible 0, survives the P3-1 case kills it
NJ (mine): drop right=True 0, survives the P3-2 case kills it

Body claims about the unchanged items.

CI. The Pull request run at the head, https://github.com/PolicyEngine/policyengine-us/actions/runs/41745610068, concluded success. All 36 jobs succeeded, including the four state baseline shards and Household API Partners. The earlier draft run (41744533541) was skipped.

Scope and body.

Baseline impact. The diff moves baseline outputs.

  • Nebraska federal itemizers in every year:
    • Sales-tax claimers gain their sales tax back.
    • Income-tax claimers lose up to the part of their income tax that main hid behind real estate taxes.
    • From 2025, high-income filers lose main's overstatement from the unphased cap.
  • New Jersey filers near a CTC or CDCC bracket switch to the deduction.
  • The hub's population run should report:
    • the count and net revenue of changed NE itemizers, split by sales-tax and income-tax claimers;
    • the count of NJ elections that flip, and their net change in nj_income_tax.

What I couldn't check

  • Sources. This VM couldn't reach any primary source: the proxy refused nebraskalegislature.gov, revenue.nebraska.gov, irs.gov, govinfo.gov, uscode.house.gov, ecfr.gov, lis.njleg.state.nj.us, law.justia.com, nj.gov and web.archive.org (403 or DNS failure). So:
    • I didn't confirm Neb. Rev. Stat. 77-2716.01(4), the Form 1040N booklets or the $8,600 2025 Nebraska standard deduction. I used PE's parameter.
    • I didn't read N.J.S.A. 54A:3A-17 to -20, NJ-1040 Worksheet H, the 2026 Schedule A, or IRC 63(d) and 68.
    • A web search returned only third-party summaries of 54A:3A-20, which I don't rely on.
  • Population impact. I ran no microsimulation on population data.
  • The author's property checks (300 random NJ households, 300 NE filers): not rerun, so unverified.
  • The Iowa witness table in the body: not run.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

…st two edges

The comment said the formula follows Worksheet H, but since the last round it
also counts the change in the refundable NJ CTC and CDCC, which the worksheet
leaves out. Two review cases close gaps no existing case covered: a separate
filer, who cannot claim the NJ CTC, keeps the $50 credit; and a deduction that
lands taxable income exactly on $30,000 gets the 50% NJ CDCC rate, as nj_cdcc's
right=True reads it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpcqEDJ2tmDgRbDecMcN7j
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: ae2a795084e4f3190ace272e43eb3760222ee447 (one commit on top of e9502f5dfa; nobody else pushed to the branch while I worked, and main merges cleanly, so I made no merge commit).

What the round 1 review asked for, and what I did

# Item Resolution
1 P2-1: stale comment nj_taking_property_tax_deduction.py:22 now reads # Worksheet H compares the tax saving with the credit; this also counts the change in the refundable NJ CTC and CDCC (below). I left it on one line, since ruff format doesn't wrap comments and the lint config ignores E501, so ruff never asked. The form-versus-statute question (candidates entry or not) is still the hub's to rule on; I changed only the comment.
2 P3-1 and P3-2: two cases Added to nj_taking_property_tax_deduction.yaml exactly as the review gives them. "Separate filer with a child…" is at line 81, next to the other CTC cases. "Deduction that lands NJ taxable income exactly on $30,000…" is at line 141, after the CDCC cases. Both pass at the head and fail under their mutants (below).
3 Body, section 3 Added the Worksheet H sentence after "It only makes the comparison count everything the deduction changes." Added the Overlap. paragraph at the end of section 3. I checked it first: #10043 is open (draft, head 6f241acce1), and its nj_ctc.py diff adds & ~filer_is_dependent to the child count this PR moves. Tests: "7 new cases, 10 in all", now naming both new cases. The mutant sentence is rewritten from my reruns, because the new $30,000 case also kills the CDCC-term mutant, so "failed 1" became 2. I left the impact: and axiom: lines alone. Readback after the PATCH matches what I sent.
4 Runs All pass; see below.

Hand computations (2023, single rates 1.4% to $20,000, 1.75% to $35,000)

  • Separate filer. Tax on $30,500 is 280 + 10,500 × 1.75% = 463.75. On $27,800 it is 280 + 7,800 × 1.75% = 416.50, so the saving is 47.25.
    • nj_ctc_eligible is false for SEPARATE (nj_ctc_eligible.py). cohabitating_spouses is false, so the credit stays $50. 47.25 < 50, so the filer keeps the credit.
    • The mutant adds 1 × (1,000 − 800) = 200: 247.25 > 50.
  • $30,000 edge. The saving is 500 × 1.75% = 8.75.
    • nj_cdcc uses calc(..., right=True), so $30,000 gets 50% and $30,500 gets 40%: 8.75 + 10% × 600 = 68.75 > 50.
    • Without right=True on the after-deduction rate, both rates are 40%: 8.75 < 50.

Mutants

Each ran in its own process on a scratch worktree, against the 10-case file at this head. I removed the worktrees afterwards; git status is clean.

Mutant Result Killed by
Drop * nj_ctc_eligible (review's P3-1) 1 failed, 9 passed Separate filer case
Drop right=True from the after-deduction CDCC rate (review's P3-2) 1 failed, 9 passed $30,000 case
Drop + ctc_gain 2 failed CTC bracket case; end-to-end renter
Drop + cdcc_gain 2 failed CDCC rate rise; $30,000 case

Tests at the head (one process per file)

File Result
nj_taking_property_tax_deduction.yaml 10 passed
nj_ctc.yaml 19 passed
nj_ctc_eligible.yaml 2 passed
nj_cdcc.yaml 8 passed
ne_itemized_deductions.yaml 8 passed
test_source_conflicts.py (the comment is new text) 103 passed

ruff format --check and ruff check on the changed Python file both pass.

CI

Not finished at the 60-minute mark; the runners were congested. This is the only run at this head: the Pull request run 41856636964 at ae2a795084.

At 16:20Z, 60 minutes after my 15:20Z push, the run was in_progress:

  • 29 of 36 jobs had succeeded: all eleven Baseline shards (the four state shards included), Household API Partners, PR validation, Package and compatibility, Quick Feedback, the Rest Python planning and check jobs, all nine Rest Python shards, and Contrib states-shard-3, other-shard-2a and other-shard-2b.
  • 7 were still running: Python Full Suite - Microsimulation, and Contrib states-shard-1, -2 and -4, other-shard-1 and -3, and congress.
  • None had failed or been cancelled.

The hub needs to read the run's conclusion.

Judgment calls

  • I kept the new comment on one line (see item 1).
  • I placed the two cases beside their related cases rather than at the end of the file.
  • I rewrote the body's NJ mutant sentence from my own runs at this head, and left the NE mutant sentence as it was (the NE code and tests didn't change).

Proposed follow-up

NJ child tax credit: an income exactly on a bracket edge gets the lower amount. The 2025 NJ-1040 instructions (line 65, fetched from nj.gov this session) give $1,000 for taxable income of "$30,000 or less". But nj_ctc uses p.amount.calc(taxable_income) without right=True, so exactly $30,000 gets $800; the same happens at $40,000, $50,000 and $60,000, and $80,000 gets nothing. The election here mirrors nj_ctc, so the two stay consistent. The fix is right=True in both, plus edge cases in nj_ctc.yaml. This is on main and not part of this PR.


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Hub review in progress

Round 2 delta review of head ae2a795084e4f3190ace272e43eb3760222ee447 (unchanged since the hand-off). Findings so far; the final review follows as a separate comment.

  • The delta from e9502f5dfa is one comment line in nj_taking_property_tax_deduction.py and two YAML cases in nj_taking_property_tax_deduction.yaml.
  • CI: the Pull request run at the head, https://github.com/PolicyEngine/policyengine-us/actions/runs/41856636964, concluded success, 36 of 36 jobs.
  • Sources: this VM's proxy refuses nj.gov, the NJ Legislature hosts, law.justia.com and govinfo.gov, so N.J.S.A. 54A:3A-20 and the NJ-1040 instructions are unread here.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review
VERDICT: APPROVE
ae2a795
METHODOLOGY_CHOICE: yes

Round 2 delta review, from e9502f5dfa (round 1's approved head) to ae2a795084. The head hasn't moved since the hand-off. The delta is one commit with two changes: a one-line comment in nj_taking_property_tax_deduction.py, and two YAML cases in nj_taking_property_tax_deduction.yaml. The body was also edited. Every round 1 item the round 2 brief assigned is done as asked. CI is green. I found no P1 or P2. METHODOLOGY_CHOICE stays yes: the Nebraska line 7 total after section 68 (round 1 P3-3) is still an open reading. The New Jersey election now rests on the hub's statute reading, and this PR follows it.

Findings

P3-1. NJ CTC at exactly $30,000: the election inherits nj_ctc's bracket edge. It's identical on main, so it's a follow-up.

nj_taking_property_tax_deduction.py:85-86 calls p_credits.ctc.amount.calc(...) without right=True, as nj_ctc.py:23 does. So the election stays consistent with the credit it predicts, including at the edge.

  • Witness (run at the head): 2023, single, one child aged 3, cdcc 0, $30,500 of taxable income before the deduction and a $500 deduction.
    • nj_ctc at exactly $30,000 is 800. At $30,001 and $30,500 it is also 800.
    • The election's CTC gain is calc(30,000) − calc(30,500) = 800 − 800 = 0. The benefit is 500 × 1.75% = 8.75, below 50, so nj_taking_property_tax_deduction is false.
    • The hand-off says the NJ-1040 instructions pay $1,000 for "$30,000 or less". If that holds, the CTC gain is 200, the benefit is 208.75, and the filer should take the deduction, a net gain of 158.75.
  • This PR's cases: no case moves. Every CTC case goes from $30,500 to $27,800, and the $30,000 case has no child. My mutant M6, which adds right=True to both CTC calc calls in the election, survives 10/10.
  • Main: main keeps the credit for this household too, because it ignores the CTC. Nothing gets worse here.
  • Follow-up: add right=True to nj_ctc.py:23 and to both CTC calls at nj_taking_property_tax_deduction.py:85-86 in one change, with $30,000 and $40,000 edge cases in nj_ctc.yaml and this witness in the election file. I couldn't read the instructions or 54A:4-17.1 (see below), so the "or less" wording is unverified.

P3-2. The election's reference doesn't cite 54A:3A-20, the section its reading rests on

nj_taking_property_tax_deduction.py:10-16 cites 54A:3A-17, 54A:4-17.1 and the NJ-1040 instructions. The hub's reading comes from 54A:3A-20(a)(1), which the credits/property_tax/amount.yaml parameter already cites. Add after line 11:

        "https://law.justia.com/codes/new-jersey/2022/title-54a/section-54a-3a-20/",

P3-3. The pre-existing halved credit for cohabiting separate filers has no case. Dropping it survives.

nj_taking_property_tax_deduction.py:75. This PR didn't change that line.

  • Mutant M7: credit_amount = credit_amount, which drops the / (1 + separate * cohabitating) halving. It passes 10/10.
  • Ready case. It passes at the head (1 passed) and fails under M7 (1 failed):
- name: Cohabiting separate filer weighs the deduction against a $25 credit
  # Tax saving 463.75 - 416.50 = 47.25. A separate filer who lives with the
  # spouse gets half the $50 credit, $25, so the deduction wins: 47.25 > 25.
  period: 2023
  absolute_error_margin: 0
  input:
    nj_property_tax_deduction_eligible: true
    nj_potential_property_tax_deduction: 2_700
    nj_taxable_income_before_property_tax_deduction: 30_500
    filing_status: SEPARATE
    cohabitating_spouses: true
    cdcc: 0
    state_code: NJ
  output:
    nj_taking_property_tax_deduction: true

This is a test gap in code this PR didn't change, so it can go in a follow-up.

Checked and sound

The comment (P2-1). Line 22 now reads # Worksheet H compares the tax saving with the credit; this also counts the change in the refundable NJ CTC and CDCC (below). It describes what lines 77-95 compute: the tax difference plus ctc_gain plus cdcc_gain, compared with credit_amount. It claims nothing about the statute. The body's new sentence ("Worksheet H compares only the tax saving with the $50 credit, so a filer who follows it keeps the credit in the witness below and gives up $197.25.") matches the witness arithmetic: 47.25 < 50, and 47.25 + 200 − 50 = 197.25. Neither line claims more than the hub's reading. No register entry is needed, and test_source_conflicts.py passes, 103 passed.

The two new cases, computed by hand before the run. The 2023 single and separate schedules are 1.4% to $20,000 and 1.75% to $35,000. The credit is $50, halved only for a cohabiting separate filer. The CTC is $1,000 at or below $30,000 and $800 above, with calc and no right=True. The CDCC rate is 50% at or below $30,000 and 40% above, with right=True.

  • Separate filer with a child (line 81).
    • Tax is 280 + 10,500 × 1.75% = 463.75 at $30,500, and 280 + 7,800 × 1.75% = 416.50 at $27,800, a saving of 47.25.
    • nj_ctc_eligible is false for SEPARATE (nj_ctc_eligible.py), so the CTC gain is 0. cdcc is 0. Since 47.25 < 50, the result is false. The asserted nj_ctc_qualifying_children: 1 and nj_ctc_eligible: false follow.
    • Under M1, the gain is 1 × (1,000 − 800) = 200, so 247.25 > 50.
  • $30,000 edge (line 141). The saving is 500 × 1.75% = 8.75. The CDCC rate is 50% at $30,000 and 40% at $30,500, so the gain is 0.10 × 600 = 60. Since 68.75 > 50, the result is true. Under M2, both rates are 40% and 8.75 < 50.
  • Both assert the claim in their names, not a weaker one.

Defect at main. I ran the head's 10-case file against main's code. 5 fail: the CTC bracket case, the CDCC rate rise, the $30,000 case, the end-to-end renter, and the separate filer. The separate filer fails only because nj_ctc_qualifying_children doesn't exist on main. Without that output line it passes at main, so it guards M1 and doesn't witness the bug. The $30,000 case fails at main, so it is a second witness of the CDCC defect.

Mutants, each in its own process on a scratch worktree, against the 10-case file. I restored the code after each and git status was clean.

Mutant Result Killed by
M1: drop * nj_ctc_eligible 1 failed, 9 passed Separate filer with a child…
M2: drop right=True on the after-deduction CDCC rate 1 failed, 9 passed Deduction that lands NJ taxable income exactly on $30,000…
M3: drop + ctc_gain 2 failed CTC bracket case; renter end-to-end
M4: drop + cdcc_gain 2 failed CDCC rate rise; $30,000 case
M5 (mine): >= instead of > survives 10/10 none. At a tie the net tax is equal either way, so this is close to an equivalent mutant
M6 (mine): right=True in both CTC calls survives 10/10 none (P3-1)
M7 (mine): drop the cohabiting halving survives 10/10 the P3-3 case kills it (1 failed)

M1-M4 match the hand-off and the body's mutant sentence.

Runs at the head, one file per process:

File Result
nj_taking_property_tax_deduction.yaml 10 passed
nj_ctc.yaml 19 passed
nj_ctc_eligible.yaml 2 passed
nj_cdcc.yaml 8 passed
ne_itemized_deductions.yaml 8 passed
test_source_conflicts.py 103 passed

ruff format --check and ruff check on the changed Python file both pass.

Overlap paragraph. It holds at #10043's current head, 6f241acce1 (open, draft, last updated 2026-10-16).

Readers. The round 2 delta changes no formula, so no reader moves. The readers are unchanged from round 1:

  • nj_taking_property_tax_deduction: nj_property_tax_deduction and nj_property_tax_credit;
  • nj_ctc_qualifying_children: nj_ctc and the election.

Body.

  • "7 new cases, 10 in all" is right: main's file has 3 cases and the head's has 10.
  • The listed cases and the mutant sentence match my runs.
  • impact: the hub will measure and axiom: needed are present. needed is CLAUDE.md's form for an external contributor, so the hub still has to replace it.

Baseline impact. The delta can't move any output, since it changes a comment and adds tests. The PR as a whole moves NE itemizers and NJ elections near a CTC or CDCC bracket edge, as round 1 listed. The population check round 1 asked for still applies.

Scope.

CI. The Pull request run at the head, https://github.com/PolicyEngine/policyengine-us/actions/runs/41856636964, concluded success. All 36 jobs succeeded, none skipped or cancelled, including Python Full Suite - Microsimulation and every Contrib shard, which were still running at the hand-off.

Still open from round 1, not in this round's scope: P3-3, Nebraska line 7 before or after section 68, and P3-4, wagering losses until #10070 lands.

What I couldn't check

  • Sources. This VM's proxy refused nj.gov, lis.njleg.state.nj.us, pub.njleg.state.nj.us, www.njleg.state.nj.us, law.justia.com, casetext.com and govinfo.gov (403 on CONNECT or DNS failure). So I didn't read:
    • N.J.S.A. 54A:3A-20(a)(1). The hub's reading of it is taken as given.
    • Worksheet H.
    • The NJ-1040 line 65 "$30,000 or less" wording, or 54A:4-17.1.
  • The author's 300-household NJ property check: not rerun.
  • Population impact: I ran no microsimulation.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

…filers

The election's reading rests on N.J.S.A. 54A:3A-20, which the property
tax credit parameter already cites, so cite it here too. Add a case for a
separate filer who lives with the spouse: the $50 credit halves to $25,
so a $47.25 tax saving makes the deduction the better choice. Without
the case, dropping the halving passed every test in the file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6HWtPqg7fKcLTqL3ef
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: 1511c2c92243134e63051a43b4bfa803819dfe99

Built on ae2a795084, the head the item named; no other commit landed on the branch. No merge of origin/main was needed.

Items

  1. P3-2, the 54A:3A-20 reference. policyengine_us/variables/gov/states/nj/tax/income/property_tax/nj_taking_property_tax_deduction.py:12 adds the 54A:3A-20 entry right after the 54A:3A-17 entry. I didn't fetch it (the review reports law.justia.com refused).
  2. P3-3, the cohabiting separate filer. policyengine_us/tests/policy/baseline/gov/states/nj/tax/income/deductions/property_tax/nj_taking_property_tax_deduction.yaml:191-206 adds the review's inputs and output under the item's name and comment.
  • Hand values (2023 separate schedule: 1.4% to $20,000, 1.75% to $35,000): tax is 280 + 10,500 × 1.75% = 463.75 at $30,500 and 280 + 7,800 × 1.75% = 416.50 at $27,800, a saving of 47.25. nj_ctc_eligible is false for a separate filer and cdcc is 0, so neither credit moves. The cohabiting separate filer's credit is 50 / 2 = 25, and 47.25 > 25, so nj_taking_property_tax_deduction is true.
  • At this head: passes.
  1. The body. The test bullet now reads "8 new cases, 11 in all" and names the new case; the mutant bullet adds the M7 result against the 11 cases and keeps the earlier mutants' "against the 10 cases". P3-1, impact: and axiom: are untouched. I read the body back after the PATCH, and it matches.
  2. Runs, one file per process at this head:
File Result
nj_taking_property_tax_deduction.yaml 11 passed
nj_ctc.yaml 19 passed
nj_ctc_eligible.yaml 2 passed
nj_cdcc.yaml 8 passed
code_health/test_reference_urls.py 32 passed

ruff format --check and ruff check pass on nj_taking_property_tax_deduction.py.

Mutant

M7: credit_amount = credit_amount in place of credit_amount / (1 + separate * cohabitating) (line 76 at this head). It ran in its own process, and I restored the file afterwards; git status showed only my two intended changes. Result: 1 failed, 10 passed, with only the new case failing: nj_taking_property_tax_deduction@2023: [0.] differs from 1.0. Under M7 the credit stays 50, and 47.25 < 50.

CI

Pull request run 41947357640 at 1511c2c922 concluded success: all 36 jobs completed with success, none cancelled or skipped.

Judgment calls

  • The body has no CI sentence, so item 16 needed no change there.
  • I didn't rerun M1-M4 against the 11-case file; the new case holds no child and cdcc 0, so it doesn't reach the terms they mutate. The body keeps those results labelled "against the 10 cases".

Proposed follow-up (the hub's to file)

None from this round. The review's P3-1 (right=True at NJ CTC's $30,000 edge) is already with the hub.


Generated by Claude Code

@DTrim99

DTrim99 commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Fix state taxpayer-choice bugs: NJ property tax election and NE itemized deductions

Summary

The New Jersey change is sound in principle. N.J.S.A. 54A:3A-20(a)(1) lets a taxpayer "elect to take a credit instead of the deduction". Both refundable credits that read taxable income (the NJ CTC and the NJ CDCC) use NJ-1040 line 42, after the property tax deduction. So counting their change when picking the better election is the right comparison. The algebra matches the net-tax difference, and the inputs don't depend on the election, so there is no cycle.

The Nebraska change matches 77-2716.01(4) and the Form 1040N line 7–8 instructions for every year tested (2021–2025, all checked word for word). There are four open issues:

  • Nebraska line 5a election. The new rule always treats the larger of income and sales taxes as the line 5a entry. When the federal SALT cap binds either way, a filer can enter sales taxes on line 5a at no federal cost and lose nothing on Nebraska's line 8. The PR's headline 2025 witness is such a case, and the PR moves it from main's $670,000 of taxable income to $691,400.
  • New Jersey separate filers. A new test pins a $50 credit for a married-filing-separately filer who doesn't live with the spouse. 54A:3A-20(b) gives every spouse filing separately half the credit. This statute-vs-instructions choice isn't recorded.
  • NJ CTC boundary. The new CTC term (like nj_ctc) misses the statute's "$30,000 or under" boundary, while the CDCC line next to it gets the same boundary right. No test pins it.
  • Unpinned terms. Two new terms fail no test when deleted.

I hand-checked all 16 expectations in the two changed test files. CI is 36/36 green, and the merge with current main is clean.

Critical

None.

Should address

S1. Nebraska: a filer whose federal SALT deduction is capped either way would enter sales taxes on line 5a. The PR always subtracts income taxes, which reverses its own 2025 witness and makes common homeowner cases worse than main.
policyengine_us/variables/gov/states/ne/tax/income/deductions/ne_itemized_deductions.py:32 sets claims_income_taxes = income_taxes > sales_taxes.

  • The law leaves line 5a to the filer. The 2024 Schedule A instructions, line 5a: "You can elect to deduct state and local general sales taxes instead of state and local income taxes. You can't deduct both." The Nebraska booklet, line 8 (2024; 2025): "If you entered general sales taxes on Federal Schedule A, line 5a, do not enter an amount on line 8."
  • The cap makes the choice free. When real estate taxes plus sales taxes already reach the federal cap, line 5e is the same under either election. The federal return doesn't change, and the sales-tax election removes nothing on Nebraska's line 8. The PR's own tie rule ("a tie counts as sales taxes") is the narrow case of this principle. Federal indifference also happens whenever the cap binds under the sales-tax election.
  • The PR's 2025 witness (test line 77) is such a case. Real estate taxes are $30,000 against a $10,000 cap: max(10,000, 40,000 − 0.30 × 200,000) = 10,000.
    • With a sales-tax election, line 5e is still min(30,000 + sales, 10,000) = 10,000. Federal itemized deductions stay at $30,000, line 8 is 0, and Nebraska itemized deductions are $30,000.
    • Nebraska taxable income is then 700,000 − 30,000 = $670,000, which is main's value (the body's "$670,000 at 6df1752b").
    • The PR asserts $691,400. That is 21,400 × 5.20% = $1,112.80 more Nebraska tax than the filer is legally entitled to pay.
  • A common profile. 2024, single, $150,000 wages, $12,000 real estate tax, $15,000 mortgage interest, $7,000 state income tax withheld, $1,500 sales tax. This is a hand trace of the head's formula; I ran no code.
    • Federal SALT is min(19,000, 10,000) = 10,000 under the income-tax election and min(13,500, 10,000) = 10,000 under the sales-tax election. Federal itemized deductions are $25,000 either way.
    • The PR gives 25,000 − 7,000 = $18,000. Main gives 15,000 + min(12,000, 10,000) = $25,000, which is also the sales-tax-election answer.
    • The difference is 7,000 × 5.84% = $408.80 of Nebraska tax.
    • From 2018 to 2024 this hits any Nebraska itemizer whose property taxes plus sales-table taxes reach $10,000.
  • Fix. Treat line 5a as sales taxes whenever the sales-tax election gives the same federal SALT deduction. This keeps every other expectation and subsumes the tie rule:
    property_taxes = add(tax_unit, period, ["real_estate_taxes"])
    salt_if_sales = min_(tax_unit("salt_cap", period), property_taxes + sales_taxes)
    claims_income_taxes = tax_unit("salt_deduction", period) > salt_if_sales
    • Against the eight cases: unit tests 1–2, the uncapped case, the 2024 case and the 2023 above-cap case still remove income taxes. The sales-tax case and the tie still remove nothing. Only the 2025 witness changes, to ne_itemized_deductions: 30_000 and ne_taxable_income: 670_000.
    • Add the 2024 profile above as a case, and update the body and rulespec-us#2038's 2025 row.
    • If the hub keeps "line 5a = the larger amount" on purpose, as a convention matching the federal model, say so in the code and the body, and drop the claim that the 2025 result follows from the law.

S2. New Jersey: 54A:3A-20(b) halves the credit for every spouse filing separately, but the code (and a new test) halves it only for spouses who live together. The choice isn't recorded.

  • The statute. N.J.S.A. 54A:3A-20(b): "A husband and wife who elect to file separate income tax returns … shall each be entitled to one-half of the credit allowed pursuant to subsection a. of this section." It sets no same-home condition.
  • The instructions add one. The 2025 NJ-1040 instructions, Worksheet H line 8: "$50 or more ($25 if you and your spouse file separate returns but maintained the same main home)".
  • The code follows the instructions. nj_taking_property_tax_deduction.py:76 and nj_property_tax_credit.py:24 divide by 1 + separate * cohabitating. That line is unchanged, but the PR's new case at test line 81 ("Separate filer with a child … so keeps the $50 credit", cohabitating_spouses: false) pins the instructions' reading.
    • Under the statute, that filer's credit is $25. The saving is 463.75 − 416.50 = 47.25, and 47.25 > 25, so the expected value would be true.
    • The case is also the only one that kills mutant M1 (dropping * nj_ctc_eligible), so the CTC-eligibility pin rests on the contested reading.
  • CLAUDE.md and CONTRIBUTING.md#source-conflicts require following the statute, or, for a reading found in the code, recording it. No us-nj property-tax entry exists in source_conflicts/candidates.yaml or the pinned register.
  • Fix: either
    • (a) follow the statute: halve the credit for every separate filer in both files, and re-pin M1 with a reading-neutral case (a cohabiting separate filer with a child, $30,500, a $1,000 deduction and cdcc: 0: saving 17.50 < 25 gives false, while M1 gives 17.50 + 200 > 25); or
    • (b) record a candidate (for example us-nj:property-tax-credit-separate-filer-half) and rename the test so it doesn't assert the $50 as law.
    • Either way, rulespec-us#2037's "separate filer with child" row (required "Same", i.e. false) contradicts the 6(b) text the issue itself quotes, and should be corrected.

S3. New Jersey CTC boundary: the new election term (and nj_ctc) treat "$30,000 or under" as exclusive. No test pins the edge.

  • The statute. N.J.S.A. 54A:4-17.1(a): "$30,000 or under $1,000; over $30,000 but not over $40,000 $800 …". The 2025 instructions, line 65 (PDF page 46), say "$30,000 or less".
  • The code. nj_taking_property_tax_deduction.py:86-87 calls p_credits.ctc.amount.calc(...) without right=True, as nj_ctc.py:23 does, so taxable income of exactly $30,000 gets $800. The same applies at $40,000, $50,000, $60,000 and $80,000; at exactly $80,000 the statute pays $200 and PE pays $0.
    • The CDCC line right below (lines 91-92) uses right=True for the same "$30,000 or less" wording on Worksheet J.
  • Witness. 2023, one child under 6, $30,500 before a $500 deduction, no CDCC.
    • Under the statute, the deduction gains 8.75 + 200 = 208.75 > 50, so the filer takes it.
    • The head keeps the credit, which costs the household $158.75.
    • The hub's mutant that adds right=True survives all 11 cases. That makes this a missing boundary test for changed logic.
  • The nj_ctc edge is pre-existing, and fixing only the election would make outcomes worse. Fix: add right=True to nj_ctc.py:23 and both CTC calls in the election, with $30,000 and $80,000 edge cases in nj_ctc.yaml and the witness above in the election file.

S4. Two new terms are unpinned: deleting either fails no test.

  • local_income_tax in ne_itemized_deductions.py:29. Every case sets local_income_tax: 0. Line 5a includes local income taxes, and the booklet says "state and local income taxes".
    • Fix: split one case's income tax between state and local. For example, in the 2024 case use $6,000 state_withheld_income_tax and $2,000 local_income_tax; the result stays $17,000, and deleting the term gives $19,000.
  • right=True on the before-deduction CDCC call (nj_taking_property_tax_deduction.py:92). Every CDCC case starts at $30,500, where right has no effect.
    • Fix: add a case at $30,000 before a $2,000 deduction with cdcc: 600. Both rates are 50%, so the gain is 0 and 35 < 50 gives false. Without right=True, the before rate is 40%: 35 + 60 = 95 gives true.

Suggestions

  1. Tie handling. Worksheet H line 8 recommends the deduction when the saving is "$50 or more". Line 99 uses a strict >, as main did. At an exact tie the net tax is equal either way, so this only changes which of line 41 or line 56 PE reports. Consider >= to match the worksheet.
  2. References.
    • ne_itemized_deductions cites only the 2021 and 2022 booklets, with no page anchors, while the tests run through 2025. Add the dated line 7–8 pages: 2021 p.8, 2022 p.9, 2023 p.9, 2024 p.10 and 2025 p.14.
    • The election's comment names the CDCC, but the reference cites neither N.J.S.A. 54A:4-17 nor Worksheet H/J pages.
    • The .../pdf/current/1040i.pdf link changes every year. Prefer the dated tgi-ee/<year>/1040i.pdf copies.
  3. Test file for the new variable. Add nj_ctc_qualifying_children.yaml with a dependent aged 5 versus 6 and a non-dependent child under 6. It is a new formula variable, and CLAUDE.md asks for variable-named test files.
  4. Nebraska follow-ups to note in code.

Verified correct

  • NJ statute and form. 54A:3A-20(a)(1) makes the credit an election ("may elect to take a credit instead of the deduction"). Worksheet H describes itself as a comparison aid ("Complete both columns of this worksheet to find out whether the deduction or the credit is better for you"). Counting the refundable-credit changes therefore follows the statute and fills a gap in the worksheet; it is not a statute-vs-form conflict, and no register entry is needed for that part.
  • Both credits read line 42. Worksheet J line 2 and the line 65 calculation both use "taxable income from line 42, NJ-1040" (2025 instructions, PDF pages 45-46). 54A:4-17.1(c) makes the CTC refundable.
  • Comparison algebra. nj_non_refundable_credits is empty, and eligibility requires NJ AGI above the filing threshold, so the 54A:2-4 zeroing never applies. The deduction therefore wins exactly when Δtax + ΔCTC + ΔCDCC > credit, which is what lines 80-99 compute.
  • No cycle. The inputs are nj_taxable_income_before_property_tax_deduction, nj_ctc_qualifying_children, nj_ctc_eligible and the federal cdcc, and none depends on the election.
  • Readers. Only nj_main_income_tax, nj_ctc and nj_cdcc read nj_taxable_income, as the body says (grep at head). nj_ctc_qualifying_children is read by nj_ctc and the election. The CTC count moved unchanged.
  • Senior, blind and disabled route. Taxpayers at or below the filing threshold get the credit through nj_property_tax_credit_eligible and never reach the election, which is defined_for deduction eligibility. This is unchanged and consistent with 54A:3A-20(a)(1)(b).
  • NE statute and booklets. 77-2716.01(4) ("except for the amount for state or local income taxes included in federal itemized deductions before any federal disallowance") and the 2021, 2022, 2023, 2024 and 2025 booklets (line 7: Schedule A line 17; line 8: line 5a income taxes "even if" capped, nothing if sales taxes) match the formula, apart from S1.
    • The federal-itemizer gate in ne_taxable_income matches (3)(a) and (4).
    • The zero floor can't change line 10.
  • Hand-checks (2023 NJ single/separate schedule 1.4% to $20,000 and 1.75% to $35,000; head of household is the same in this range):
# Case Arithmetic Expected OK
1 NJ CTC bracket (280+183.75) − (280+136.50) = 47.25; + (1,000−800) = 247.25 > 50 true yes
2 NJ no child 47.25 < 50 false yes
3 NJ separate, child, not cohabiting 47.25; CTC ineligible; vs $50 false yes under the code (S2: true under 3A-20(b))
4 NJ CDCC rise 2,000 × 1.75% = 35; + 0.10 × 600 = 95 > 50 true yes
5 NJ small CDCC 35 + 10 = 45 < 50 false yes
6 NJ $30,000 CDCC edge 8.75 + 0.10 × 600 = 68.75 > 50 true yes
7 NJ renter 33,000 − 1,000 − 1,500 = 30,500; 0.18 × 15,000 = 2,700; 27,800; 280 + 7,800 × 1.75% = 416.50; CTC 1,000; credit 0 as listed yes
8 NJ cohabiting separate 47.25 > 50/2 = 25 true yes
9 NE unit 1 (2021) 2,000 + 24,000 + 10,000 − 5,000 31,000 yes
10 NE unit 2 (2022) 3,000 + 7,000 + 10,000 − 5,000 15,000 yes
11 NE sales filer 15,000 + 8,000; sales 3,000 > income 1,000 23,000 yes
12 NE uncapped 15,000 + 7,000 − 2,000 20,000 yes
13 NE 2025 cap max(10,000, 40,000 − 60,000) = 10,000; 30,000 − 35,000 → 0; 700,000 − 8,600 0 / 691,400 yes under the code (S1: 30,000 / 670,000)
14 NE 2024 cap min(13,000, 10,000) + 15,000 − 8,000 17,000 yes
15 NE 2023 above cap 15,000 + 10,000 − 12,000 13,000 yes
16 NE tie 3,000 = 2,000 + 1,000; 5,000 + 3,000 + 15,000 23,000 yes
  • Published tax table. The new NJ cases reach the same conclusions under the 2023 table (464/455/429/417): 47 + 200, 47, 35 + 60, 35 + 10, 9 + 60, and 47 against 25.
  • Code structure. The formulas are vectorized (where, max_, calc on arrays), with TaxUnit entities and YEAR periods. The NH Add New Hampshire state supplementation for 2026 #10156 pattern doesn't apply: the new int count is not used as a parameter key.
  • Housekeeping.
    • The changelog fragment changelog.d/state-choice-bugs-nj-ne.fixed.md is top level with type fixed.
    • No partner-contract files are touched.
    • The new comments don't match the source-conflict ratchet's patterns, and test_source_conflicts.py is unchanged on main since the merge base.

Axiom line assessment

axiom: TheAxiomFoundation/rulespec-us#2037 and #2038 queued. Both issues are OPEN, labelled pe-parity, name head 1511c2c922, and are dispatch-ready. Each gives module paths, corpus citations, verbatim law, required outputs and companion rows from official sources. The line is valid in form. Three content notes:

CI status

gh pr checks 10654 re-checked at the end: 36/36 pass at head 1511c2c922 (Pull request run 41947357640). None pending or failed.

Branch status

  • The branch is 5 commits ahead of main and 42 behind. git merge-tree --write-tree PolicyEngine/main 1511c2c922 merges cleanly.
  • Since the merge base, main changed NJ EITC files, the federal standard deduction and source_conflicts/candidates.yaml. None of these overlap the PR's files or move its expectations.
  • Sibling note: open Apply New Jersey, North Dakota, Ohio, Oklahoma and Pennsylvania rules for a filer who can be claimed as a dependent #10043 edits the CTC child count this PR moves; per the earlier hub check, it conflicts in nj_ctc.py. Whichever lands second should put its dependent-filer condition in nj_ctc_qualifying_children.py, as the body says.

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.

Requesting changes per the review above: 0 critical, 4 should (NE line 5a always treated as income taxes even when the SALT cap makes the sales-tax election free; NJ separate-filer half credit follows the instructions over 54A:3A-20(b) without a record; NJ CTC $30,000-or-under boundary; two unpinned terms), 4 suggestions.

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.

3 participants