Repository navigation
Keep inputs when NY and AL recompute federal credits under pinned rules - #10587
Conversation
ny_eitc (TY2021), al_federal_income_tax_deduction (TY2021), ny_ctc_pre_2024 and ny_ctc_pre_2024_eligible each deleted the branch's arrays for every variable whose name matched a substring list. Core's Simulation.delete_arrays deletes inputs too, so takes_up_eitc and eitc_passive_income_also_in_earned_income fell back to their defaults in the branch: a 2021 New York EITC non-taker still got the state credit. Add drop_recomputed_values to period_branch, which applies the same name selection through drop_inherited_values and so keeps every array set_input stored, and use it in all four formulas. A supplied value for a recomputed formula variable now carries into the branch too; two YAML cases that relied on the branch discarding a supplied eitc or ctc no longer supply it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: Steps
Mutants (not committed, restored after each)
CI: not run, because the PR is a draft. No microsimulation was run. Judgment calls, please check
Generated by Claude Code |
|
Ready for hub review Independent review, round 1. The head has not moved since The take-up fix is right and reproduces: on main, a 2021 New York EITC non-taker gets the New York EITC and an Alabama non-taker loses a 2020-rule EITC they never claimed. The PR fixes both. What blocks it is the rule it picks for supplied values of recomputed formula variables. That rule gives new wrong results for anyone who supplies FindingsP1. A supplied current-law
|
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A supplied eitc, ctc or ctc_qualifying_child is the current-law amount, which the pre-ARPA, 2020-IRC and pre-TCJA branches must replace, so drop_recomputed_values now deletes every formula variable in its selection (supplied or not, as main did) and keeps only plain inputs such as takes_up_eitc, which the pinned rules don't change. Restore the supplied eitc and ctc inputs the previous head removed from the AL and NY CTC YAML cases, add order-dependent NY cases that list the current-law federal credit before the state credit, and replace the Python test file with YAML cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: Started from Findings1 (P1). Formula variables are recomputed; plain inputs carry in.
2 (P2). Inputs restored. 3 (P3). Order-dependent cases.
4 (P3).
5 (P3). Body. PATCHed from a file and read back. Content matches my file. The only difference is the attribution footer, which the server rewrote. Changes:
Changelog fragment: "Keep inputs" → "Keep plain inputs". Tests at the final head (one file per process)
MutantsEach mutant ran in its own process on
CIPull request run 41545073963 at Judgment calls
Proposed follow-upAlabama 2021 Part II: use 2021-indexed EITC amounts in the 2020-IRC pin. Generated by Claude Code |
|
Hub review in progress Round 2 review of
Still to do: rerun the mutants, run the YAML files, the 2024/2026 witnesses, and the final write-up. Generated by Claude Code |
|
Ready for hub review Independent review, round 2. The head has not moved since Each round 1 finding is resolved, and the new rule holds in every order, branch nesting and year I tried. Nothing blocks the PR. Two P3 notes follow, plus a follow-up that is identical on main. FindingsP3. The
|
|
US + core hub merge audit, us#10587 at
|
Picks up #10587's Alabama federal-credit recomputation change before the final P3 round. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6H28mCRxTXCRraPQpH
…-wages Brings in #10587's Alabama cases and later main commits before the round-3 fixes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Defect
Four formulas recompute a federal credit under pinned rules in a branch. Each one then deleted the branch's arrays for every variable whose name matched a substring list:
ny_eitcny_pre_arpa_eitceitc.decoupled)eitcal_federal_income_tax_deductional_2020_ircctc,cdcc,eitc,residential_clean_energy_creditordependent_care_assistance_exclusionny_ctc_pre_2024pre_tcja_ctcctc.pre_tcja(2018+) when the post-2024 rules are off: 2018-2024 and 2028+ctcorresidential_clean_energy_creditny_ctc_pre_2024_eligiblepre_tcja_ctcMechanism. In policyengine-core 3.33.2 (main's lock),
Simulation.delete_arrayspurges the calling branch, each ancestor and the default branch from the branch's private holder storage. Its docstring says "Deleted inputs stop counting as inputs". So any plain input whose name matched lost its value in the branch, and the branch read the input's default instead. Two plain inputs (no formula,addsorsubtracts) match the EITC and Alabama selections:takes_up_eitc(default true) andeitc_passive_income_also_in_earned_income(default 0). No plain input matches the NY CTC selection.Reproduction on main (household simulations, one parent aged 35, one child aged 3):
takes_up_eitceitcny_eitc1,020ny_eitc1,020al_federal_income_tax_deduction258.87By the same mechanism, a NY 2021 EITC non-taker in a microsimulation would get the NY EITC (no microsimulation was run here). In Alabama, a 2021 non-taker's Part II is reduced by a 2020-rule EITC they never claimed.
Fix
policyengine_us/tools/period_branch.pygainsdrop_recomputed_values(branch, name_parts). It keeps the same name selection,any(part in name for part in name_parts)over the branch system's variables, and callsbranch.delete_arraysonly for the selected variables that haveformulas,addsorsubtracts. All four formulas now call it with their existing selections; I found no selection that was wrong, and kept them all.The plain inputs it keeps, by selection:
ny_eitc(eitc) andal_federal_income_tax_deduction(ctc,cdcc,eitc,residential_clean_energy_credit,dependent_care_assistance_exclusion):takes_up_eitcandeitc_passive_income_also_in_earned_income.ny_ctc_pre_2024andny_ctc_pre_2024_eligible(ctc,residential_clean_energy_credit): none, so these two behave exactly as on main.The rule: plain inputs carry into the branch, and formula variables don't. A plain input such as
takes_up_eitcis a fact the pinned rules don't change. A supplied value of a formula variable in the selection (eitc,ctc,refundable_ctc,cdcc,ctc_qualifying_child, ...) is the current-law amount, and the pinned rules define a different one:ny_eitcrecomputes the federal EITC with pre-ARPA parameter values, andny_ctc_pre_2024calculates the pre-TCJA CTC. So the branch recomputes every formula variable in its selection, supplied or not, as main did. For a caller who suppliesctcoreitc, nothing changes from main. The parent keeps its supplied values:delete_arrayson the branch leaves the parent simulation's storage alone (a parent suppliedctc4,000 still reads 4,000 afterny_ctcruns).Checked at this head against the review's witnesses: 2023 NY, supplied
ctc4,000 givesny_ctc330 (as main; the previous head gave 633.60); NY 2021, suppliedeitc500 givesny_eitc1,020 (as main; the previous head gave 150).drop_inherited_valuesis unchanged;get_override_branch,capital_gains_responses.pyandbehavioral_response_measurements.pystill call it.Other
delete_arrayscallers on mainNone of them deletes an input, and none is changed here:
tools/branched_simulation.py: on exit, deletes from the parent only the variables first stored while the clone was open. Inputs were stored before then, so they are never selected.variables/gov/simulation/capital_gains_responses.py: deletes only variables that are neither inputs (user_set_variables) nor formula-less. Inputs that have formulas go throughdrop_inherited_values, which keeps their input periods.variables/gov/ssa/revenue/tob_revenue_total.py,tob_revenue_oasdi.py(two branches),employer_ss_tax_income_tax_revenue.pyandemployer_medicare_tax_income_tax_revenue.py: delete only variables not inbranch.input_variables, the variables with stored values when the simulation was built.variables/household/marginal_tax_rate.py,marginal_tax_rate_including_health_benefits.pyandmarginal_tax_rate_helpers.py: delete only variables not inuser_set_variables(sim), plusemployment_income, which each branch sets again with the raised earnings on purpose.(
system.pycallsdelete_input_valueson the earnings and capital-gains inputs while it builds the simulation. That is input rewriting, not a branch, so it is outside this audit.)Tests
Take-up cases (YAML):
ny_eitc.yaml: NY 2021, parent with $10,000 wages and a child aged 3. With take-up, the pre-ARPA EITC is 34% × 10,000 = 3,400 (under the 3,618 maximum), and 30% of it is 1,020 (Tax Law 606(d); 2021 IT-215 instructions). The household credit is capped at NY tax before credits, which is 0. Without take-up,ny_eitcis 0.al_federal_income_tax_deduction.yaml: AL 2021, head of household with $41,000 wages and a child aged 3. Federal tax is (41,000 − 18,800) = 22,200 taxable, so 1,420 + 12% × 8,000 = 2,380. Part I is 0, because the refundable CTC is 3,600. Part II line 6 is 2,380 − 2,000 (2020 CTC, all nonrefundable here) = 380. The 2020-rule EITC is 3,584 − 15.98% × (41,000 − 19,330) = 121.13. Deduction: 380 − 121.13 = 258.87 for a taker, and 380 for a non-taker.Order-dependent cases (YAML calculates outputs in order, and these branches copy the parent's cache, so each lists the current-law federal credit first):
ny_eitc.yaml, "2021 NY EITC recomputes the federal credit without ARPA after the ARPA credit": childless filer aged 30 with $9,000 wages.eitc(ARPA) is 15.3% × 9,000 = 1,377, under the 1,502 maximum and below the 11,610 phase-out start. Pre-ARPA (Rev. Proc. 2020-45 amounts ingov.states.ny.tax.income.credits.eitc.pre_arpa: maximum 543, phase-out start 8,880; 2020 phase-out rate 7.65%): 543 − 7.65% × (9,000 − 8,880) = 533.82; 30% = 160.15, less the household credit of 40 (capped at NY tax before credits of 40, both from the model) = 120.15.ny_ctc_pre_2024.yaml, "2023 pre-TCJA credit recomputes the federal CTC after the current-law CTC": parent with $30,000 wages, child aged 3.ctc(current law) is 2,000. Pre-TCJA: $1,000 per child, under the $75,000 head-of-household phase-out threshold; federal tax is (30,000 − 20,800) × 10% = 920, so 920 is nonrefundable and the other 80 refundable (15% × 27,000 = 4,050 exceeds it). 33% × 1,000 = 330, above the $100 minimum; the 2023 minimum age is 0.Supplied formula-variable cases (the branch recomputes them):
al_federal_income_tax_deduction.yaml, "2021 childless filer, NIIT survives the line-6 floor":eitc: 200restored as on main; expected 120 unchanged.ny_ctc.yaml, "2025 - Updated CTC disabled vs enabled comparison (young child)":ctc: 0restored as on main; expected 330 unchanged. The file is now identical to main.ny_eitc.yaml, "2021 NY EITC recomputes the federal credit when the ARPA credit is supplied": the review's witness, suppliedeitc500 for the $10,000 parent;ny_eitc1,020 (34% × 10,000 = 3,400; 30%).ny_ctc_pre_2024.yaml, "2023 pre-TCJA eligibility recomputes a supplied federal qualifying-child flag": child aged 6 withctc_qualifying_child: falsesupplied;ny_ctc_pre_2024_eligibletrue andny_ctc_pre_2024330. Moved from the deleted Python file with the expectation this rule gives.The Python file
tests/core/test_credit_recompute_branches_keep_inputs.pyis deleted: its take-up tests repeated the YAML cases, and its CTC tests asserted the reverse rule.Mutants of
drop_recomputed_values(not committed), each run onny_eitc.yaml,ny_ctc_pre_2024.yaml,al_federal_income_tax_deduction.yamlandny_ctc.yamlin its own process, code restored after:ny_eitc: "…without ARPA after the ARPA credit" (373.10 → 120.15), "…when the ARPA credit is supplied" (150 → 1,020).ny_ctc_pre_2024: "…recomputes the federal CTC after the current-law CTC" (633.60 → 330), "…supplied federal qualifying-child flag" (eligible 0 → 1). AL: 5 cases, including both take-up cases and "NIIT survives the line-6 floor" (0 → 120).ny_ctc: "2025 - Updated CTC disabled…" (100 → 330).ny_eitc: "…does not take up the federal EITC" (1,020 → 0). AL: "…no EITC take-up…" (258.87 → 380). Both CTC files pass: their selection has no plain input.ny_eitc: "…when the ARPA credit is supplied" (150 → 1,020).ny_ctc_pre_2024: "…supplied federal qualifying-child flag" (eligible 0 → 1). AL: "NIIT survives the line-6 floor" (0 → 120).ny_ctc: "2025 - Updated CTC disabled…" (100 → 330).Run at the final head, one file per process:
ny_eitc.yamlal_federal_income_tax_deduction.yamlny_ctc.yamlny_ctc_pre_2024.yamlny_supplemental_eitc.yamlnyc_eitc.yamlnyc_income_tax_elimination_credit.yamlny_a04038_enhanced_escc_infants.yamlny_working_families_tax_credit.yamlal_eitc.yamltests/code_health/test_source_conflicts.pyI left the rest of the NY and AL state folders, the NYC folder, contrib reforms and microsimulation to CI.
Follow-up (identical on main)
_pin_2020_ircinpolicyengine_us/tools/pinned_tbs.pypins the EITC, CTC and CDCC parameters to their 2020-01-01 values for TY2021, while_pin_pre_arpa_eitcrestores the Rev. Proc. 2020-45 inflation-indexed 2021 amounts. Under the 2021-indexed reading, the new Alabama case would give a 2020-rule EITC of 3,618 − 15.98% × (41,000 − 19,520) = 185.50 and a deduction of 194.50, not 258.87. Not changed here.impact: TY2021 only:
ny_eitc,ny_supplemental_eitc,ny_income_tax,al_federal_income_tax_deductionandal_income_taxmove for a tax unit that doesn't take up the federal EITC or that supplieseitc_passive_income_also_in_earned_income. None from 2022: only the 2021 NY EITC and Alabama Part II paths read those inputs, and the review's 80 witnesses for 2022-2028 match main.axiom: n/a (branch plumbing: no provision's reading changes; take-up is an input)
🤖 Generated with Claude Code