Repository navigation
Conversation
The coordinator waited up to 3,000 s for baseline and then up to a fresh 3,000 s for reform, so queued workers could push it past its own 4,500 s Modal timeout before it recorded the failure. Both waits now draw on one 3,000 s window, leaving 1,500 s for the 900 s production-result wait and 600 s of aggregation and failure persistence. When a child wait fails or times out, the coordinator now cancels every unfinished child, best effort, and records a cancelled sibling as failed, because Modal's InputCancellation is a BaseException the worker cannot record itself. Cancellation and state-update errors are logged and never replace the original child failure. This keeps the sequential baseline-then-reform wait; concurrent observation remains part of #712. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 tasks done
Anchor the shared child-wait deadline when coordinate_report starts, so claiming, output planning, retained-artifact reads and dispatch shorten the children's waits rather than the 1,500 s left for the production-result wait, aggregation, persistence and failure recording. Add evaluation_id and the child's simulation_execution_id to the cancellation warnings, and cover finished siblings, restored calls and the ImmediateCall cancel double. The coordinator timeout test now runs the coordinator with simulated setup time against the declared Modal timeouts, so it lives beside the other coordinator tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 tasks done
Contributor
Author
|
Closing this in favour of #712, which now covers #792 and lists |
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
…eouts The coordinator stopped waiting 3,000 s after it started, although a US simulation worker may run for 3,900 s and each of its region-group calls for 3,600 s, so US simulations could never use the time Modal allowed them. The coordinator's 5,100 s timeout was not derived from either. Following the rule from #793, a new dependency-free stage12_timeouts module defines the worker timeouts, sets the shared child-wait window to the longest of them (3,900 s), and derives the coordinator's Modal timeout as that window plus the 900 s production-result wait plus 600 s to read results, aggregate, write artifacts and record the outcome: 5,400 s. A complete testing-environment US report took 288 s, so 600 s of finishing time is ample. The Modal app, coordinator and comparison step all read these constants. The last poll no longer sleeps past the deadline, so the window closes on time instead of up to 1 s late and the finishing time is not eroded. Tests read the declared Modal timeouts and check that the window covers every simulation worker's timeout and that the coordinator's timeout leaves the production wait plus at least 600 s. They also check that setup time shortens the window and that an exhausted window gives the children no extra time. Only the Modal timeout values change: no image, secret or environment variable attachment changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
Adopt #793's cancellation practice in the concurrent coordinator: - Every simulation the coordinator stops, after a peer failure, a wait timeout or a coordinator failure, is recorded as failed with simulation_cancelled, and its error_summary gives the reason, for example "Cancelled after the baseline simulation failed.". The cancelled_after_peer_failure and cancelled_after_coordinator_failure codes and the incomplete status for cancellations are gone; the wait timeout stays the report's error code. - Only a running record changes, so a simulation that already succeeded or failed keeps its outcome. Workers already treat any status other than running as a cancellation, so a segmented worker still sees the failed record and cancels its own region-group calls. - An unsegmented simulation is always cancelled through Modal, even when its record could not be written. A segmented simulation is cancelled through Modal only when its record could not be written, because Modal does not cancel spawned calls recursively. Cancellation and state-update errors are still logged without replacing the original failure. Carry over #793's tests for a cancelled and recorded reform, a finished baseline left alone, a restored call cancelled on retry, finished siblings left unchanged, and both unfinished children cancelled on timeout. Add tests for the Modal fallback after a failed state write, for segmented and unsegmented simulations. ImmediateCall now counts cancellations, and the entry and persistence fixtures use the new cancellation record. Add a changelog line, as #793 did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
…eouts The coordinator stopped waiting 3,000 s after it started, although a US simulation worker may run for 3,900 s and each of its region-group calls for 3,600 s, so US simulations could never use the time Modal allowed them. The coordinator's 5,100 s timeout was not derived from either. Following the rule from #793, a new dependency-free stage12_timeouts module defines the worker timeouts, sets the shared child-wait window to the longest of them (3,900 s), and derives the coordinator's Modal timeout as that window plus the 900 s production-result wait plus 600 s to read results, aggregate, write artifacts and record the outcome: 5,400 s. A complete testing-environment US report took 288 s, so 600 s of finishing time is ample. The Modal app, coordinator and comparison step all read these constants. The last poll no longer sleeps past the deadline, so the window closes on time instead of up to 1 s late and the finishing time is not eroded. Tests read the declared Modal timeouts and check that the window covers every simulation worker's timeout and that the coordinator's timeout leaves the production wait plus at least 600 s. They also check that setup time shortens the window and that an exhausted window gives the children no extra time. Only the Modal timeout values change: no image, secret or environment variable attachment changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
Adopt #793's cancellation practice in the concurrent coordinator: - Every simulation the coordinator stops, after a peer failure, a wait timeout or a coordinator failure, is recorded as failed with simulation_cancelled, and its error_summary gives the reason, for example "Cancelled after the baseline simulation failed.". The cancelled_after_peer_failure and cancelled_after_coordinator_failure codes and the incomplete status for cancellations are gone; the wait timeout stays the report's error code. - Only a running record changes, so a simulation that already succeeded or failed keeps its outcome. Workers already treat any status other than running as a cancellation, so a segmented worker still sees the failed record and cancels its own region-group calls. - An unsegmented simulation is always cancelled through Modal, even when its record could not be written. A segmented simulation is cancelled through Modal only when its record could not be written, because Modal does not cancel spawned calls recursively. Cancellation and state-update errors are still logged without replacing the original failure. Carry over #793's tests for a cancelled and recorded reform, a finished baseline left alone, a restored call cancelled on retry, finished siblings left unchanged, and both unfinished children cancelled on timeout. Add tests for the Modal fallback after a failed state write, for segmented and unsegmented simulations. ImmediateCall now counts cancellations, and the entry and persistence fixtures use the new cancellation record. Add a changelog line, as #793 did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
…eouts The coordinator stopped waiting 3,000 s after it started, although a US simulation worker may run for 3,900 s and each of its region-group calls for 3,600 s, so US simulations could never use the time Modal allowed them. The coordinator's 5,100 s timeout was not derived from either. Following the rule from #793, a new dependency-free stage12_timeouts module defines the worker timeouts, sets the shared child-wait window to the longest of them (3,900 s), and derives the coordinator's Modal timeout as that window plus the 900 s production-result wait plus 600 s to read results, aggregate, write artifacts and record the outcome: 5,400 s. A complete testing-environment US report took 288 s, so 600 s of finishing time is ample. The Modal app, coordinator and comparison step all read these constants. The last poll no longer sleeps past the deadline, so the window closes on time instead of up to 1 s late and the finishing time is not eroded. Tests read the declared Modal timeouts and check that the window covers every simulation worker's timeout and that the coordinator's timeout leaves the production wait plus at least 600 s. They also check that setup time shortens the window and that an exhausted window gives the children no extra time. Only the Modal timeout values change: no image, secret or environment variable attachment changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
Adopt #793's cancellation practice in the concurrent coordinator: - Every simulation the coordinator stops, after a peer failure, a wait timeout or a coordinator failure, is recorded as failed with simulation_cancelled, and its error_summary gives the reason, for example "Cancelled after the baseline simulation failed.". The cancelled_after_peer_failure and cancelled_after_coordinator_failure codes and the incomplete status for cancellations are gone; the wait timeout stays the report's error code. - Only a running record changes, so a simulation that already succeeded or failed keeps its outcome. Workers already treat any status other than running as a cancellation, so a segmented worker still sees the failed record and cancels its own region-group calls. - An unsegmented simulation is always cancelled through Modal, even when its record could not be written. A segmented simulation is cancelled through Modal only when its record could not be written, because Modal does not cancel spawned calls recursively. Cancellation and state-update errors are still logged without replacing the original failure. Carry over #793's tests for a cancelled and recorded reform, a finished baseline left alone, a restored call cancelled on retry, finished siblings left unchanged, and both unfinished children cancelled on timeout. Add tests for the Modal fallback after a failed state write, for segmented and unsegmented simulations. ImmediateCall now counts cancellations, and the entry and persistence fixtures use the new cancellation record. Add a changelog line, as #793 did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
…eouts The coordinator stopped waiting 3,000 s after it started, although a US simulation worker may run for 3,900 s and each of its region-group calls for 3,600 s, so US simulations could never use the time Modal allowed them. The coordinator's 5,100 s timeout was not derived from either. Following the rule from #793, a new dependency-free stage12_timeouts module defines the worker timeouts, sets the shared child-wait window to the longest of them (3,900 s), and derives the coordinator's Modal timeout as that window plus the 900 s production-result wait plus 600 s to read results, aggregate, write artifacts and record the outcome: 5,400 s. A complete testing-environment US report took 288 s, so 600 s of finishing time is ample. The Modal app, coordinator and comparison step all read these constants. The last poll no longer sleeps past the deadline, so the window closes on time instead of up to 1 s late and the finishing time is not eroded. Tests read the declared Modal timeouts and check that the window covers every simulation worker's timeout and that the coordinator's timeout leaves the production wait plus at least 600 s. They also check that setup time shortens the window and that an exhausted window gives the children no extra time. Only the Modal timeout values change: no image, secret or environment variable attachment changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
Adopt #793's cancellation practice in the concurrent coordinator: - Every simulation the coordinator stops, after a peer failure, a wait timeout or a coordinator failure, is recorded as failed with simulation_cancelled, and its error_summary gives the reason, for example "Cancelled after the baseline simulation failed.". The cancelled_after_peer_failure and cancelled_after_coordinator_failure codes and the incomplete status for cancellations are gone; the wait timeout stays the report's error code. - Only a running record changes, so a simulation that already succeeded or failed keeps its outcome. Workers already treat any status other than running as a cancellation, so a segmented worker still sees the failed record and cancels its own region-group calls. - An unsegmented simulation is always cancelled through Modal, even when its record could not be written. A segmented simulation is cancelled through Modal only when its record could not be written, because Modal does not cancel spawned calls recursively. Cancellation and state-update errors are still logged without replacing the original failure. Carry over #793's tests for a cancelled and recorded reform, a finished baseline left alone, a restored call cancelled on retry, finished siblings left unchanged, and both unfinished children cancelled on timeout. Add tests for the Modal fallback after a failed state write, for segmented and unsegmented simulations. ImmediateCall now counts cancellations, and the entry and persistence fixtures use the new cancellation record. Add a changelog line, as #793 did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
…eouts The coordinator stopped waiting 3,000 s after it started, although a US simulation worker may run for 3,900 s and each of its region-group calls for 3,600 s, so US simulations could never use the time Modal allowed them. The coordinator's 5,100 s timeout was not derived from either. Following the rule from #793, a new dependency-free stage12_timeouts module defines the worker timeouts, sets the shared child-wait window to the longest of them (3,900 s), and derives the coordinator's Modal timeout as that window plus the 900 s production-result wait plus 600 s to read results, aggregate, write artifacts and record the outcome: 5,400 s. A complete testing-environment US report took 288 s, so 600 s of finishing time is ample. The Modal app, coordinator and comparison step all read these constants. The last poll no longer sleeps past the deadline, so the window closes on time instead of up to 1 s late and the finishing time is not eroded. Tests read the declared Modal timeouts and check that the window covers every simulation worker's timeout and that the coordinator's timeout leaves the production wait plus at least 600 s. They also check that setup time shortens the window and that an exhausted window gives the children no extra time. Only the Modal timeout values change: no image, secret or environment variable attachment changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
Adopt #793's cancellation practice in the concurrent coordinator: - Every simulation the coordinator stops, after a peer failure, a wait timeout or a coordinator failure, is recorded as failed with simulation_cancelled, and its error_summary gives the reason, for example "Cancelled after the baseline simulation failed.". The cancelled_after_peer_failure and cancelled_after_coordinator_failure codes and the incomplete status for cancellations are gone; the wait timeout stays the report's error code. - Only a running record changes, so a simulation that already succeeded or failed keeps its outcome. Workers already treat any status other than running as a cancellation, so a segmented worker still sees the failed record and cancels its own region-group calls. - An unsegmented simulation is always cancelled through Modal, even when its record could not be written. A segmented simulation is cancelled through Modal only when its record could not be written, because Modal does not cancel spawned calls recursively. Cancellation and state-update errors are still logged without replacing the original failure. Carry over #793's tests for a cancelled and recorded reform, a finished baseline left alone, a restored call cancelled on retry, finished siblings left unchanged, and both unfinished children cancelled on timeout. Add tests for the Modal fallback after a failed state write, for segmented and unsegmented simulations. ImmediateCall now counts cancellations, and the entry and persistence fixtures use the new cancellation record. Add a changelog line, as #793 did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
…eouts The coordinator stopped waiting 3,000 s after it started, although a US simulation worker may run for 3,900 s and each of its region-group calls for 3,600 s, so US simulations could never use the time Modal allowed them. The coordinator's 5,100 s timeout was not derived from either. Following the rule from #793, a new dependency-free stage12_timeouts module defines the worker timeouts, sets the shared child-wait window to the longest of them (3,900 s), and derives the coordinator's Modal timeout as that window plus the 900 s production-result wait plus 600 s to read results, aggregate, write artifacts and record the outcome: 5,400 s. A complete testing-environment US report took 288 s, so 600 s of finishing time is ample. The Modal app, coordinator and comparison step all read these constants. The last poll no longer sleeps past the deadline, so the window closes on time instead of up to 1 s late and the finishing time is not eroded. Tests read the declared Modal timeouts and check that the window covers every simulation worker's timeout and that the coordinator's timeout leaves the production wait plus at least 600 s. They also check that setup time shortens the window and that an exhausted window gives the children no extra time. Only the Modal timeout values change: no image, secret or environment variable attachment changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 14, 2026
Adopt #793's cancellation practice in the concurrent coordinator: - Every simulation the coordinator stops, after a peer failure, a wait timeout or a coordinator failure, is recorded as failed with simulation_cancelled, and its error_summary gives the reason, for example "Cancelled after the baseline simulation failed.". The cancelled_after_peer_failure and cancelled_after_coordinator_failure codes and the incomplete status for cancellations are gone; the wait timeout stays the report's error code. - Only a running record changes, so a simulation that already succeeded or failed keeps its outcome. Workers already treat any status other than running as a cancellation, so a segmented worker still sees the failed record and cancels its own region-group calls. - An unsegmented simulation is always cancelled through Modal, even when its record could not be written. A segmented simulation is cancelled through Modal only when its record could not be written, because Modal does not cancel spawned calls recursively. Cancellation and state-update errors are still logged without replacing the original failure. Carry over #793's tests for a cancelled and recorded reform, a finished baseline left alone, a restored call cancelled on retry, finished siblings left unchanged, and both unfinished children cancelled on timeout. Add tests for the Modal fallback after a failed state write, for segmented and unsegmented simulations. ImmediateCall now counts cancellations, and the entry and persistence fixtures use the new cancellation record. Add a changelog line, as #793 did. 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 #792
Same-Repository Draft PR Check
PolicyEngine/policyengine-sim-api, not a personal fork.Summary
This is an interim change before #712. It keeps the sequential baseline-then-reform wait, but bounds it and cleans up after a failure.
SIMULATION_WAIT_TIMEOUT_SECONDS, the same as the workers' Modal timeout) opens whencoordinate_reportstarts. It covers coordinator setup (claiming, output planning including the country model load, retained-artifact reads and dispatch) and both child waits. Eachcall.getreceives only the remaining time, never less than zero.coordinate_reportinv2_app.py._cancel_unfinished_childrencancels every unfinished child, best effort. This includes a timed-out child that is still running, and a call restored from an earlier coordinator attempt.RUNNINGasFAILEDwitherror_code="simulation_cancelled". A sibling that has already recordedSUCCEEDEDorFAILEDis left unchanged. Modal'sInputCancellationis aBaseException, so the worker can't record its own outcome.stage12_child_cancel_failed,stage12_cancelled_child_state_update_failed) carryevaluation_id, the child'ssimulation_execution_id,simulation_roleanderror_type, but no error message.ChildCallgainscancel(). Modal'sFunctionCall.cancelalready exists.Interaction with other PRs
_cancel_unfinished_children;coordinate_reportstarts, not when polling starts, to keep the guaranteed 1,500 s;cancel()line todependencies.py;cancel()doubles totests/test_stage12_runtime.py.Testing
New tests in
tests/test_stage12_runtime.py:SUCCEEDEDorFAILEDunchanged.Suites, on Python 3.13 with
uv run --frozen:Regression checks: I reverted each behaviour in turn. Each time, the matching new test failed:
RUNNINGcheck fails both finished-sibling tests;The original cancellation tests still fail against the code before this PR only at their clock fixture, because they need the new monotonic-clock hook.
Formatting and lint:
ruff format --checkandgit diff --checkpass.ruff checkwith the locked ruff (0.15.11) is clean on the changed files.tests/test_stage12_runtime.py, and the same four are already onmain.Not run: Pyright, which isn't installed in the test environment.
🤖 Generated with Claude Code