Repository navigation
Let Scenario structural reforms read the simulation, and add baseline regression tests - #2193
vahid-ahmadi wants to merge 3 commits into
Conversation
Review of #2193 — Keep the baseline parameter tree unreformed under Scenario reformsBase repository: PolicyEngine/policyengine-uk Source DocumentsNo source documents registered; see scope and validation. CriticalC1 — Keep before-load spending Scenarios constructible (OPEN)CRITICAL — confirmed new public-route failure. Location: policyengine_uk/simulation.py:301 at the captured head, which now supplies the preserved baseline; the changed attachment is policyengine_uk/tax_benefit_system.py:129. A supported The public flag is declared in A fresh exact-base control with identical inputs constructs both classes successfully: its contaminated baseline and active budget both read 150, so no budget reform is registered. The fixture's £1bn household allocation is deliberately synthetic and only establishes routing; it is not a population estimate. The underlying helper problem also exists on older direct reform routes, but this scalar Reproduction and complete inputs: budget diagnostic ( Should AddressNone. SuggestionsNone. Evidence GapsNo material gaps reported. Notes
Validation Summary132 passed, 1 warning in 74.34s; runnable combined test bounded command 77.14s, configuration pr-2193-code-tests-config.json and log pr-2193-code-tests.log. 53 isolation/processing/final VAT assertions: pr-2193-code-diagnostic-results.json (bounded 9.18s). 32 energy and 8 midyear overlay assertions: pr-2193-code-interaction-energy/midyear.json and logs (bounded 16.98s and 4.94s). Exact scalar base/head constructor observations: pr-2193-code-budget-base/head.json and logs (bounded 7.02s and 5.22s); base constructs, head before-load raises missing simulation AttributeError. Source overlay hashes and identities: pr-2193-overlay-provenance.json. Hypothesis collection failure retained; no full model/microsimulation rerun. Independent static trace of exact four-file diff, Scenario field/constructor phases, processing/uprating/fiscal-date contract, baseline_vat→vat_change→household_tax→net-income route and budget allocation semantics. Read code-owned artifacts: pr-2193-code-tests.log (132 passed), pr-2193-code-diagnostic-results.json (53 assertions), pr-2193-code-interaction-energy.json (32), pr-2193-code-interaction-midyear.json (8), pr-2193-code-budget-base/head.json plus script (base success/head AttributeError for scalar pre-load150). No duplicate calculations. Source checker command existingPython3.13 check_source_manifest.py --manifest pr-2193-review-sources.json --worktree-root actual capture-policyengine-uk --run-root canonical RUN_ROOT returned exit0 (receipt f4f7e6); validation output pr-2193-review-source-cache-check.json. CI at 826ac3c: Install + smoke-import (py3.11)=QUEUED, Install + smoke-import (py3.12)=SUCCESS, Install + smoke-import (py3.13)=SUCCESS, Install + smoke-import (py3.14)=QUEUED, Lint=SUCCESS, Test=IN_PROGRESS. Detailed code, policy, source and reproduction artifacts were retained locally. Timingsetup seconds: 40.46s; code role seconds: 896.96s; consolidation cleanup seconds: 211.04s; elapsed seconds: 1188.00s; agent count: 2.00s; source count: 0.00s; render count: 0.00s; tests passed: 132.00s; focused assertions passed: 93.00s; bounded tests cli wall seconds: 77.14s; adjudication seconds: 152.00s Review SeverityREQUEST_CHANGES. Open findings: 1 critical, 0 should address, 0 suggestions. |
Fixes juaristi22's critical finding C1 on #2193: a before-load Scenario(parameter_changes={"gov.dfe.education_spending": 150}, applied_before_data_load=True) stopped Simulation and Microsimulation from constructing with "CountryTaxBenefitSystem object has no attribute simulation" at adjust_budgets.py:60. Core's Simulation.apply_reform calls reform.apply(tax_benefit_system), and core's __init__ binds tax_benefit_system.simulation first. The UK Simulation does not call core's __init__, so the binding never existed and adjust_budgets / disable_simulated_benefits could never run. With the baseline tree now unreformed, the budget reform is registered on this route for the first time. - Simulation.apply_reform binds tax_benefit_system.simulation = self on every call (clones bind to themselves). - adjust_budget reads every year's allocation before writing any, so a written year carried over to later years no longer stacks its change onto theirs, and skips years with no allocation instead of writing NaN. - Regression tests: the reviewer's repro constructing both classes with finite net income, the expected DfE allocation per year 2026-29, the reform-simulation binding on a clone, and a dataset Microsimulation check marked microsimulation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @juaristi22, C1 is fixed in 1d264ea. Root cause. policyengine-core's What changed.
Tests (
The 5 constructor, value and binding tests fail on the previous head and pass now. Full YAML policy suite: 2,712 passed. pytest outside One thing not fixed here: with the link in place, 🤖 Generated with Claude Code |
#2188) Main's dated-reform rework (3edfb4b) now keeps parameters.baseline as current law when Simulation.apply_parameter_changes reprocesses the tree, which is what this commit originally changed in simulation.py and tax_benefit_system.py. On rebase those hunks give way to main's version. These regression tests stay: baseline_vat scores a VAT change against the unreformed rate on every reform route, the baseline tree matches an unreformed system for several parameters, and adjust_budgets sees a Scenario spending change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mount The grossing factor differs between main and the VAT coverage branch, so the test now checks the 20% to 22% change against a tenth of the unreformed VAT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes juaristi22's critical finding C1 on #2193: a before-load Scenario(parameter_changes={"gov.dfe.education_spending": 150}, applied_before_data_load=True) stopped Simulation and Microsimulation from constructing with "CountryTaxBenefitSystem object has no attribute simulation" at adjust_budgets.py:60. Core's Simulation.apply_reform calls reform.apply(tax_benefit_system), and core's __init__ binds tax_benefit_system.simulation first. The UK Simulation does not call core's __init__, so the binding never existed and adjust_budgets / disable_simulated_benefits could never run. With the baseline tree now unreformed, the budget reform is registered on this route for the first time. - Simulation.apply_reform binds tax_benefit_system.simulation = self on every call (clones bind to themselves). - adjust_budget reads every year's allocation before writing any, so a written year carried over to later years no longer stacks its change onto theirs, and skips years with no allocation instead of writing NaN. - Regression tests: the reviewer's repro constructing both classes with finite net income, the expected DfE allocation per year 2026-29, the reform-simulation binding on a clone, and a dataset Microsimulation check marked microsimulation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Suggested The check isn't required yet (decision d1368); it fails fix PRs whose description names no reproducer. 🤖 Generated with Claude Code |
1d264ea to
7f43df9
Compare
|
Rebased onto main (7f43df9). 🤖 Generated with Claude Code |
|
@juaristi22 after the rebase, main already keeps the baseline parameter tree unreformed (3edfb4b, via #2305), so what is left here is your C1 fix, the regression tests for #2188 and the |
juaristi22
left a comment
There was a problem hiding this comment.
Re-reviewed 7f43df920ecb3e79dc581f4b66b2cd84c20d4072. My earlier C1 is resolved: the structural reform now reads the current simulation, and the before-load Scenario/baseline regression tests pass (16 passed, 1 skipped locally). The proposed title, “Let Scenario structural reforms read the simulation, and add baseline regression tests”, works; C1 belongs in this PR.
One required fix remains in the PR description. This is a Fix PR, and the current repository Fix evidence checker fails because the body has no named Reproducer: line. Please add Reproducer: policyengine_uk/tests/test_scenario_baseline_parameters.py::test_before_load_spending_scenario_constructs. I verified that exact line makes the checker pass. Please also refresh the description, which still attributes baseline code and tests already on main to this branch. Full hosted CI is still pending. I can approve once the description and check are corrected.
|
@juaristi22 retitled, refreshed the description and added the Reproducer line. Could you re-review? |
Fixes #2188.
What and why
#2305 (
3edfb4b99, already onmain) fixed the bug in #2188: aScenario's parameter changes no longer leak intoparameters.baseline, sobaseline_vatandadjust_budgetsnow compare a reform with the unreformed tree. That fix exposed a follow-on failure, raised as C1 in review: onceadjust_budgetssees aScenariochange to DfE, DHSC or DfT spending, it registers a structural reform that readsself.simulationfrom the tax-benefit system. The UKSimulationnever binds that attribute, so onmainanyScenariothat changes one of those budgets fails to construct withAttributeError: 'CountryTaxBenefitSystem' object has no attribute 'simulation'(atadjust_budgets.py:60). That holds for bothSimulationandMicrosimulation, before or after the data load.This PR fixes that failure and adds the regression tests for #2188.
Changes
Simulation.apply_reform(policyengine_uk/simulation.py) bindstax_benefit_system.simulationto the simulation applying the reform before it calls core'sapply_reform. policyengine-core's ownSimulation.__init__makes this binding, but the UK class does not call it. Binding on every call also keeps a cloned system pointing at the simulation that applies the reform, not the one it was cloned from.adjust_budgetsreads every year's allocation before it writes any. Each write is an input that carries over to later years without their own input, so reading a later year after writing an earlier one would stack the earlier year's change on top of its own. It also skips a year with no allocation instead of dividing by zero.changelog.d/2188.fixed.mddescribes the construction fix.The baseline tree handling itself (
process_parameters,apply_parameter_changes) ismain's, from #2305; this branch no longer changes it.Tests
New
policyengine_uk/tests/test_scenario_baseline_parameters.py(16 cases, plus 1 dataset test markedmicrosimulation):Scenarioscalar and bare-year changes,reform={...},Reform.from_dict) gives the same VAT change and leaves the baseline standard rate at 20%; no reform gives no VAT change;Scenariothat changes VAT, the personal allowance, a UC standard allowance, fuel duty and DfE spending, each baseline value matches an unreformed system, while the reformed tree still carries the change;adjust_budgetsreturns a reform after aScenarioDfE spending change and none for an unreformed system;ScenarioDfE change constructs underSimulationandMicrosimulation, and scales each year's allocation by that year's own budget change, leaving other budgets alone;On
main(merge base3381500f4), 11 of the 16 fail, all with theAttributeErrorabove. The 5 that pass there are the four VAT reform routes and the no-reform control, which #2305 already fixed. On this branch, 16 pass and the dataset test is skipped without the dataset.Reproducer: policyengine_uk/tests/test_scenario_baseline_parameters.py::test_before_load_spending_scenario_constructs
axiom: n/a: simulation and reform-route plumbing only; no policy, parameter or eligibility rule changes
🤖 Generated with Claude Code