Repository navigation
Conversation
The abolish-federal-income-tax and abolish-payroll-tax reforms replaced household_tax_before_refundable_credits with a formula that summed a separate parameter list, gov.household.household_tax_before_refundable_credits, less the abolished tax. That list had drifted from the baseline adds lists: it lacked id_pbf, the CA, IN, NC, OK and PA use taxes, and every local tax except New York City's, and it held pa_income_tax, which is after refundable credits. Under either reform, household tax and net income were wrong for those households. Each reform now redefines the total as the system's current adds list less its own component, so the lists cannot drift and the two reforms combine. The parameter list and the unread gov.household.household_refundable_credits are removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Python value test already applies both reforms to 17 households, and the YAML case would add one more reform combination for the runner to hold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A reform that edited the default system's lists in place would also have moved the lists the structural tests compared with, so the check that the default system is unchanged could pass after an earlier test had already applied the edit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The replacement variable inherits any formula of the variable it replaces, and the formula is computed in place of adds, so the exclusion would be silently ineffective. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new class passed to update_variable drops attributes that core does not inherit from the replaced variable, among them defined_for, is_neutralized and a custom set_input. Cloning the current definition and replacing only its adds list keeps them, as TaxBenefitSystem.neutralize_variable does, and adds no baseline_variable link when a reform is applied again. The value test now checks that each household has a nonzero amount of the tax it is there to exercise, not only that each component is nonzero somewhere in the population. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adding and neutralizing the test variable already set the flag, so the assertion passed whether or not exclude_from_total set it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both reforms replaced the household tax totals with copies built from a separate list. With either flag on, the baseline formulas already return 0 for the abolished tax, so dropping it from the total did nothing; the copy's only effect was the drift it introduced. The structural reforms were also switched on only if the flag was set at the start instant (2024-01-01). The one effect the parameters lacked, leaving federal refundable credits out of household net income when the federal income tax is abolished, is now a per-year check in household_refundable_tax_credits, which no reform replaces. The YAML cases set only the parameters, and a structural test keeps reforms from redefining any household tax total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes main's version of every file #10026 changed. The branch's own change is the one commit "Make household state tax totals equal each state's own income tax", rebased onto main. It no longer edits gov/household/household_tax_before_refundable_credits.yaml, which #10071 removes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR Review: Remove the abolish-tax structural reforms so household totals keep every other taxPR #10071 (author: MaxGhenis, head SummaryThe PR deletes the two UBI Center structural reforms in
Critical (must fix)None. Should address1.
2. The PR body is incomplete, and its merge-order section points at the wrong PR.
Suggestions
Verified correct
Axiom line assessmentValid
CI statusAll 26 checks pass (
Branch status
Verdict: REQUEST_CHANGES |
DTrim99
left a comment
There was a problem hiding this comment.
The bug reproduces on main, and the head gives a $0.00 gap for every household and scenario. No org repo imports the removed module, and the deleted parameters were app-hidden, so no deprecation path is needed. Two should items (see the comment above): (1) household_refundable_tax_credits switches from adds to a formula, so its adds metadata becomes None, and app-v2's net-income tree, which reads adds/subtracts, would show 'Refundable tax credits' as a leaf for every US household. Keep adds and gate the federal part in a new component with a defined_for boolean. (2) The PR body's 'Gap on this branch' column still says pending, the #10039 note is stale, and #10038 edits both deleted parameter files, so whichever lands second hits a modify/delete conflict.
This removes the contributed abolish-federal-income-tax and abolish-payroll-tax structural reforms. Their parameters stay and still abolish the two taxes. With either parameter on, household tax and net income now count every other baseline tax. Before, each reform replaced the household totals with a copy built from a separate hand-kept list. That list had drifted from the baseline, so
household_net_incomechanged by more than the abolished tax.No baseline value changes: every change is behind a contrib parameter that defaults to false.
The defect (read from code at upstream main
0590757714)Baseline
household_tax_before_refundable_creditsis anaddslist:employee_payroll_tax,self_employment_tax,income_tax_before_refundable_credits,flat_tax,household_state_tax_before_refundable_credits,local_income_tax_before_refundable_credits,local_occupational_tax. The state member adds the list parametergov.states.household.state_income_tax_before_refundable_creditsandstate_use_tax.When
gov.contrib.ubi_center.flat_tax.abolish_federal_income_taxorabolish_payroll_taxwas true at the start instant,create_structural_reforms_from_parametersapplied a reform that replaced that variable with a formula. The formula summed a different list parameter,gov.household.household_tax_before_refundable_credits, less one member. Comparing the two lists:id_pbfca_use_tax,in_use_tax,nc_use_tax,ok_use_tax,pa_use_taxil_total_tax)local_income_tax_before_refundable_creditsexcept its New York City memberlocal_occupational_taxpa_income_tax_before_refundable_credits(the reform list heldpa_income_tax, which subtractspa_refundable_tax_credits)household_refundable_tax_creditsThree more faults in the same code:
update_variablewith its own full formula, so the one applied later overwrote the other.DEFAULT_START_DATE, 2024-01-01). A parameter set from a later year left them off. For the income tax, federal refundable credits then stayed in household net income whileincome_taxwas 0. The YAML test runner never applies structural reforms, so it showed the same.gov.household.household_refundable_creditshad no reader at all.Why remove the reforms rather than fix them
With either parameter on, the baseline formulas already return 0 for the abolished tax:
income_tax_before_refundable_creditsandincome_taxfor the income tax,employee_payroll_taxfor payroll tax. Taking a zero out of the household total changes nothing. So the reforms' only effect on household tax was the drift above.The one thing the parameters did not already do was leave federal refundable credits out of household net income when the federal income tax is abolished. That is now a check in
household_refundable_tax_credits, read for each year. It goes there and not inincome_tax_refundable_credits, because seven other contributed reforms replaceincome_tax_refundable_creditsand would drop the check, while no reform replaceshousehold_refundable_tax_credits.The change
policyengine_us/reforms/federal/(both reforms) and their entries inpolicyengine_us/reforms/reforms.py.household_refundable_tax_creditsbecomes a formula: state plus local refundable credits, plusincome_tax_refundable_creditsunlessabolish_federal_income_taxis true for that year. This matchesincome_tax, which nets federal refundable credits and is 0 under the parameter.gov/household/household_tax_before_refundable_credits.yaml(only the two reforms read it) andgov/household/household_refundable_credits.yaml(nothing read it).tests/test_aggregate_list_integrity.pygainstest_no_reform_redefines_a_household_tax_total, which parsespolicyengine_us/reforms/and fails if any reform defines a class named after a household tax total.What was checked before deleting
reforms.py(repogit grep). GitHub code search across the PolicyEngine and UBICenter organizations finds no other importer.UBICenter/blank-slate-ubi-us(policy.py) andPolicyEngine/blank-slate-ubi-in-the-us(notebook) set the two parameters, which are kept.gov.household.household_tax_before_refundable_credits: read only by the two reforms (repo grep; organization code search finds no other reader).gov.household.household_refundable_credits: no reader in the repo or the organization search.app/src/mocks/US_Metadata.json.Reproduction
One simulation of 17 single-adult households, 2025, $60,000 of wages unless noted, with both parameters on from 2024-01-01. "Gap" is
household_tax_before_refundable_creditsminus the sum of the baseline components evaluated in the same simulation; it should be zero.Main's column was measured earlier today with the same script (
param_path.pyin the review folder). The branch column is pending a local run that is waiting for host memory; it will be filled in here. The script also runs a second window, with both parameters true for 2025 only, which main's structural reforms never saw.Invariants
For every household, period and set of inputs, on this branch:
household_tax_before_refundable_creditsis the sum of its baselineaddscomponents, with or without either parameter. No reform redefines it (enforced by the structural test).abolish_federal_income_taxtrue for a year,income_tax_before_refundable_creditsandincome_taxare 0 for that year, andhousehold_refundable_tax_creditsequalshousehold_refundable_state_tax_credits+household_refundable_local_tax_credits. With it false, the federal term is added.abolish_payroll_taxtrue for a year,employee_payroll_taxis 0 for that year.Tests
YAML, in the two existing files under
policy/contrib/federal/(15 cases). Every case now sets only the parameter; no case names a reform. The cases pin some components and leave the abolished tax to its formula, so it is the parameter that zeroes it.abolish_federal_income_tax.yaml(9 cases): the five existing cases, rewritten without the reform object, plus an Idaho filer (id_pbfcomputed, $10), California use tax, the Wilmington earned income tax (computed, $500), and Pennsylvania refundable credits counted once (with use tax andhousehold_net_income). On main, six of the nine fail, each by the $800 of federal refundable credits still inhousehold_refundable_tax_credits; the YAML runner applies no structural reform, so on main the parameter alone left the credits in.abolish_payroll_tax.yaml(6 cases): the two existing cases, plus an Idaho filer, North Carolina use tax, the Jefferson County occupational tax (computed, $1,100) and Maryland county income tax. Payroll tax is left to its formula on wages, and each case expectsemployee_payroll_tax: 0. These pass on main as well, because on the formula path main was already right; they now guard the only path there is.Structural:
test_no_reform_redefines_a_household_tax_totalpasses on this branch. Against main'spolicyengine_us/reforms/it fails and names both reforms' redefinitions ofhousehold_tax_before_refundable_creditsand the income tax reform's redefinition ofhousehold_refundable_tax_credits.The 17-household check above was run locally as a script. It is not added as a test: with no structural reform left, the YAML runner and
Simulationcompute the household totals through the same formulas, so the YAML cases cover it.CI cost
astand builds no model.test_batched.pyfalls from 1.25 to 0.5 each, since they no longer name a structural reform.Merge order with #10039
#10039 (draft) adds members to
gov/household/household_tax_before_refundable_credits.yaml, which this PR deletes. Whichever lands second drops that file. Its additions togov.states.household.state_income_tax_before_refundable_creditsreach the household totals with no further edit.Partner contract tests
None is edited and none can move: no file under
tests/policy/baseline/partners/sets either parameter, and no baseline value changes.axiom: n/a: contrib reform aggregation
🤖 Generated with Claude Code