Fix open-ended reforms applying only to their start year in microsimulation#454
Merged
Merged
Conversation
Open-ended parameter values (end_date=None) serialised as bare date period keys, which policyengine-core Reform.from_dict applies for a single instant only — so flat-dict reforms silently reverted to baseline after their start year in US microsimulation runs. Serialise every period as an explicit start.stop range, clipping open-ended values at the next-later value of the same parameter. Fixes #453 Co-Authored-By: Claude Fable 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 #453
What
reform_dict_from_parameter_valuesserialised open-ended parameter values (end_date=None) as bare"YYYY-MM-DD"period keys. policyengine-core'sReform.from_dictapplies a bare date key for a single instant only, so any open-ended reform — including every flat-dict reform, whose compile path produces open-endedParameterValues — silently reverted to baseline after its start year in US microsimulation runs.Every period key now uses the
"start.stop"range format:end_date→ serialised verbatim, as before2100-12-31(OPEN_ENDED_REFORM_STOP) when no later value followsThe UK path (
simulation_modifier_from_parameter_values) already handled open-ended values correctly viaParameter.update(stop=None)and is unchanged.Verification
Unit tests: four existing assertions updated from the buggy shape, three new regression tests (open-ended far-future stop; reverse-order step schedule; open-ended + explicit-end mix). Simulation-level suites
tests/test_dict_reforms_on_simulation.py,tests/test_us_reform_application.py, andtests/test_household_impact.pypass (41 tests).End-to-end, the #453 repro through
compile_reform_to_policy→build_reform_dict→Reform.from_dict:and the docs' step-schedule example:
Real-world magnitude: a 10-year (2026–2035) revenue estimate of a 39% top rate scored +$17.7B in 2026 and exactly $0.0B in each of 2027–2035 before this fix; after, the years grow +$17.7B → +$33.5B (+$251.4B over the window).
Note
uv.lockincludes a one-line true-up of the project's own version (4.18.7 → 4.18.10) produced byuv sync— the committed lock was stale relative topyproject.tomlon main.🤖 Generated with Claude Code