Cast time_period to string before posting to simulation gateway#3522
Merged
Cast time_period to string before posting to simulation gateway#3522
Conversation
The policyengine-api-v2 simulation gateway (PR #458, deployed in v42 on 2026-04-26) tightened its request schema to require time_period as Optional[str]. The locally-installed policyengine PyPI package (PolicyEngine/policyengine.py, commit 29f2c1a 2025-01-28) declares TimePeriodType = int on SimulationOptions.time_period, so model_validate() coerces incoming string years to int and model_dump() re-emits them as int. The gateway then 422s every economy-comparison request. Cast time_period to str on the dict produced by model_dump() right before passing to simulation_api.run(), without changing the SimulationOptions schema. This is the minimum-surface fix on the caller side; downstream simulation code that consumes time_period as int is unaffected because that work happens after the gateway has deserialized the body. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
141b210 to
52ba58c
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3522 +/- ##
==========================================
- Coverage 76.68% 76.66% -0.02%
==========================================
Files 63 63
Lines 3444 3446 +2
Branches 620 621 +1
==========================================
+ Hits 2641 2642 +1
Misses 629 629
- Partials 174 175 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
anth-volk
approved these changes
Apr 28, 2026
Collaborator
anth-volk
left a comment
There was a problem hiding this comment.
LGTM. Note this won't fully fix issue until Docker-related deploy issues are resolved in forthcoming PR(s) from my end.
anth-volk
requested changes
Apr 28, 2026
Collaborator
anth-volk
left a comment
There was a problem hiding this comment.
Sorry, actually, just now realizing this doesn't fully solve. Will write in Slack.
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.
Summary
time_periodin the dict produced bySimulationOptions.model_dump()right beforesimulation_api.run(...)posts it to the gateway.Why
The simulation gateway (
projects/policyengine-api-simulation/src/modal/gateway/models.pyinpolicyengine-api-v2, PR #458 merged 2026-04-17, deployed to prod as v42 on 2026-04-26) tightened its request schema to require:The locally-installed
policyenginePyPI package'sSimulationOptionsdeclares (policyengine.pycommit29f2c1a, 2025-01-28):So
SimulationOptions.model_validate({"time_period": "2027", ...})coerces "2027" → 2027 (int), andmodel_dump()re-emits it as int. The gateway then returns:…which surfaces as a 500 to every
/<country_id>/economy/<id>/over/<id>request currently. All four state dashboards that depend on the live economy endpoint are blocked.Approach
Two places to fix:
economy_service.py— minimum surface, ships immediately, doesn't require coordinating apolicyenginePyPI release.@field_serializertoSimulationOptions.time_periodupstream inPolicyEngine/policyengine.py. Worth doing later as defence-in-depth so any other consumer ofmodel_dump()is also covered, but this PR is sufficient to unblock production.Test plan
/us/economy/<id>/over/<id>?region=mo&time_period=2027no longer returns 500/422 from the gateway after this lands.SimulationOptions.time_periodis still typed as int internally; we only stringify the JSON body.🤖 Generated with Claude Code