Repository navigation
Keep reform stop dates through policy normalisation - #741
Merged
Merged
Conversation
_normalise_period_key turned a legacy start.stop key into its start date, so the wrapper read every bounded API reform as open-ended and it never expired. Keys now keep their stop dates. A policy with any interval key is compiled into a policyengine.core Policy whose ParameterValues carry explicit end_dates, because the pinned wrapper's dict compiler rejects interval keys. Paths are still validated by the wrapper's compile_reform. Policies without interval keys keep going through the wrapper's own dict compilation. Malformed keys and intervals that end before they start raise. Current-law baselines keep their deterministic artifact ids; reforms never reuse them. Fixes #740. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hanged Once the installed wrapper ships the UK Budget reform contract, every case sent in the legacy start.stop form must reach Simulation(policy=...) as the same parameter values the contract's wrapper.policy route compiles. Unknown paths are rejected by both. Skipped until then. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed dates Review fixes (GPT-6.1 Sol): - Stage 12 aggregation handed the normalised policy dict straight to the wrapper, whose pinned dict compiler rejects interval keys. Every path that hands a request policy to the wrapper now goes through _runtime_policy (normalise, then compile intervals). - Policy keys accept unpadded months and days, as the wrapper's strptime always has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #740
Review: GPT-6.1 Sol requested four changes in round 1; all are fixed, and round 2 approved this head (ece6e16). The review read the code; it did not execute it. CI passes.
What this changes
_normalise_period_keyused to turn a legacy"start.stop"policy key intostart. The wrapper then read it as an open-ended effective date, so every bounded reform sent to the API kept going past its end date. For example,{"gov.hmrc.income_tax.rates.uk[0].rate": {"2027-04-06.2028-04-05": 0.21}}also changed 2028-29 and every later year._normalise_period_keyvalidatesYYYY-MM-DDandYYYY-MM-DD.YYYY-MM-DDand returns them unchanged. A malformed key, or an interval that ends before it starts, raisesValueErrornaming the key._compile_interval_policyhandles a policy with any interval key. The pinned wrapper (6.2.3) rejects interval keys in dict policies, so this builds apolicyengine.core.PolicywhoseParameterValues carry explicitend_dates.compile_reform, so unknown paths still raise with close-match hints.end_date=None), and scalars keep the wrapper's{year}-01-01default.policy=None) keeps its deterministic id, and a reform never reuses a baseline artifact.Review
GPT-6.1 Sol round 1 (on e307617) asked for two changes. Both are fixed in ece6e16, and round 2 is running.
_runtime_policy(normalise, then compile intervals). New test:test_aggregate_stand_ins_keep_bounded_policy_end_dates."2027-4-6") are accepted again, as the wrapper'sstrptimealways accepted them.Invariants
reform_dict_from_parameter_values(compiled.parameter_values)gives back the same intervals (tested for UK and US).Full UK correctness for dated reforms also needs the wrapper and model fixes that this service's updater will pull in: PolicyEngine/policyengine.py#575 and PolicyEngine/policyengine-uk#2305. This PR makes sure the end date reaches them.
Tests
cd projects/policyengine-simulation-executor && uv run pytest tests/test_stage12_runtime.py tests/test_simulation_runtime_policy.py tests/test_baseline_artifacts.py tests/test_simulation_output_builder.py tests/test_budget_reform_contract_route.py: 143 passed, 1 skipped. The skipped test is the contract-route differential, which runs once the installed wrapper ships the contract; with the runner and policyengine-uk#2305 on the path, it passes all 9 cases.The new
test_simulation_runtime_policy.pycovers:test_baseline_artifacts.pycovers id behaviour for baselines and reforms. The test that asserted the stop date is dropped now asserts it is kept.Part of the UK Autumn Budget 2026 CI plan (workstream W1).
🤖 Generated with Claude Code