Skip to content

Relay simulation run stage and progress on computing economy responses - #3916

Draft
PavelMakarchuk wants to merge 1 commit into
masterfrom
feat/relay-simulation-run-progress
Draft

PavelMakarchuk wants to merge 1 commit into
masterfrom
feat/relay-simulation-run-progress

Conversation

@PavelMakarchuk

Copy link
Copy Markdown
Collaborator

Summary

While an annual economy run is computing, GET /<country_id>/economy/<policy_id>/over/<baseline_policy_id> now relays the optional stage fields that the simulation entrypoint reports for the job (PolicyEngine/policyengine-sim-api#781). Clients can show real progress instead of elapsed time divided by a fixed duration.

Related: #2001. That issue was deferred to the API v2 calculation migration, with the note that progress should come from coarse, monotonic calculation stages on an asynchronous path. policyengine-sim-api#781 adds those stages to the simulation entrypoint's job status. This PR only relays them for the asynchronous economy route. The synchronous household endpoint is unchanged and stays indeterminate.

Response

A computing body on a worker that reports stages:

{
  "status": "computing",
  "message": null,
  "result": null,
  "stage": "reform",
  "progress": 67,
  "progress_max": 96,
  "submitted_at": "2026-10-13T12:00:00Z",
  "started_at": "2026-10-13T12:00:30Z",
  "stage_started_at": "2026-10-13T12:01:00Z"
}

A segmented US national run also returns "segments": {"completed": 19, "total": 20}.

Unchanged bodies:

  • completed and error responses;
  • computing responses when the entrypoint returns no stage fields (worker apps deployed before policyengine-sim-api#781, or before that PR deploys).

Changes

  • libs/simulation_entrypoint.py: SimulationRunProgress reads stage, progress, progress_max, submitted_at, started_at, stage_started_at and segments from GET /jobs/{job_id}. ModalSimulationExecution.run_progress holds it. Malformed values give None and never fail a poll. stage is a plain string, because later entrypoint versions may add stages.
  • services/economy_service.py: EconomicImpactResult.run_progress carries the fields from the running branch of _handle_execution_state. It is not part of to_dict(), so existing callers see no change.
  • routes/economy_routes.py: merges the fields into the body only when the status is computing and the fields are present.
  • openapi_spec.yaml: documents the optional fields on the annual route.
  • changelog.d: added fragment.

The completion fields (finished_at, stage_durations) are not relayed: completed results come from the reform_impact table, not from a live poll.

Migration notes

  • Route group: economy, annual route only. It stays on the Flask/API v1 path.
  • Contracts: no migration registry or workflow contract changes. scripts/export_migration_contracts.py produced no diff, and the stable response fields are unchanged.
  • User-visible change: additive optional fields on computing bodies only.

Deploy order

Independent. Before policyengine-sim-api#781 deploys, the entrypoint returns no stage fields, so this PR changes no response. Either PR can merge first.

Testing

  • pytest tests/unit tests/contract: 2,332 passed (2,324 on master before this change).
  • New tests cover reading the fields, missing and malformed fields, an unknown stage value, the relay in _handle_execution_state, and the route bodies (computing with and without fields, completed results).
  • python scripts/run_quality_guards.py: passed.
  • ruff format --check . and ruff check on the changed files: passed.
  • Not run: integration and live tests.

Downstream

policyengine-app-v2 can read progress and progress_max in SocietyWideCalcStrategy: move its time-based estimate between the two values, never backwards, and name the stage in the RunProgress caption.

🤖 Generated with Claude Code

While an annual economy run is computing, the economy route now relays
the optional stage fields that the simulation entrypoint reports for
the job (PolicyEngine/policyengine-sim-api#781): stage, progress,
progress_max, submitted_at, started_at, stage_started_at and segments.

Malformed fields are dropped and never fail a poll. Completed, error
and field-less computing bodies keep their existing shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.59%. Comparing base (21ddf34) to head (bfb4fe2).
⚠️ Report is 10 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #3916       +/-   ##
===========================================
+ Coverage   45.22%   87.59%   +42.36%     
===========================================
  Files         183      198       +15     
  Lines       11073    12241     +1168     
  Branches     1905     2161      +256     
===========================================
+ Hits         5008    10722     +5714     
+ Misses       5644      922     -4722     
- Partials      421      597      +176     

☔ View full report in Codecov by Harness.
📢 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.

This branch was successfully deployed

1 active deployment
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.

1 participant