Skip to content

Cast time_period to string before posting to simulation gateway#3522

Merged
anth-volk merged 1 commit intomasterfrom
fix/cast-time-period-string-for-gateway
Apr 28, 2026
Merged

Cast time_period to string before posting to simulation gateway#3522
anth-volk merged 1 commit intomasterfrom
fix/cast-time-period-string-for-gateway

Conversation

@DTrim99
Copy link
Copy Markdown
Collaborator

@DTrim99 DTrim99 commented Apr 28, 2026

Summary

  • One-line fix: stringify time_period in the dict produced by SimulationOptions.model_dump() right before simulation_api.run(...) posts it to the gateway.

Why

The simulation gateway (projects/policyengine-api-simulation/src/modal/gateway/models.py in policyengine-api-v2, PR #458 merged 2026-04-17, deployed to prod as v42 on 2026-04-26) tightened its request schema to require:

time_period: Optional[str] = None

The locally-installed policyengine PyPI package's SimulationOptions declares (policyengine.py commit 29f2c1a, 2025-01-28):

TimePeriodType = int
class SimulationOptions(BaseModel):
    time_period: TimePeriodType = Field(...)

So SimulationOptions.model_validate({"time_period": "2027", ...}) coerces "2027" → 2027 (int), and model_dump() re-emits it as int. The gateway then returns:

422 Unprocessable Entity - {"detail":[{"type":"string_type","loc":["body","time_period"],"msg":"Input should be a valid string"}]}

…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:

  • B.1 (this PR): cast at the call site in economy_service.py — minimum surface, ships immediately, doesn't require coordinating a policyengine PyPI release.
  • B.2 (deferred): add a @field_serializer to SimulationOptions.time_period upstream in PolicyEngine/policyengine.py. Worth doing later as defence-in-depth so any other consumer of model_dump() is also covered, but this PR is sufficient to unblock production.

Test plan

  • Verify /us/economy/<id>/over/<id>?region=mo&time_period=2027 no longer returns 500/422 from the gateway after this lands.
  • Check NC/UT/SC dashboards (which only read precomputed CSVs) are unaffected — they don't go through this code path.
  • No simulation-side regressions: downstream SimulationOptions.time_period is still typed as int internally; we only stringify the JSON body.

🤖 Generated with Claude Code

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>
@DTrim99 DTrim99 force-pushed the fix/cast-time-period-string-for-gateway branch from 141b210 to 52ba58c Compare April 28, 2026 16:21
@DTrim99 DTrim99 requested a review from anth-volk April 28, 2026 16:27
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 76.66%. Comparing base (939b716) to head (52ba58c).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
policyengine_api/services/economy_service.py 50.00% 0 Missing and 1 partial ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Collaborator

@anth-volk anth-volk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Note this won't fully fix issue until Docker-related deploy issues are resolved in forthcoming PR(s) from my end.

@anth-volk anth-volk self-requested a review April 28, 2026 16:50
Copy link
Copy Markdown
Collaborator

@anth-volk anth-volk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, actually, just now realizing this doesn't fully solve. Will write in Slack.

@anth-volk anth-volk merged commit 5d20619 into master Apr 28, 2026
5 of 7 checks passed
@anth-volk anth-volk deleted the fix/cast-time-period-string-for-gateway branch April 28, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants