Repository navigation
Closed
Labels
agent:serverkind:featureA public product capability or experience is requestedA public product capability or experience is requestedpriority:P1High-priority product or release riskHigh-priority product or release riskrepo:serverOwned by the standalone server repositoryOwned by the standalone server repositorystatus:readyReady for implementationReady for implementation
Description
Native parity for workflow#1117. Core implementation is workflow#1121 (in review); the decision record is General's 2026-11-13 comment on workflow#1117.
Core contract to match
When a run's own code closes it with complete_workflow, fail_workflow or continue_as_new, in the same transaction and before the terminal event:
- Each open (pending or running) activity gets
ActivityCancelledwithcancellation_reason: "run_closed", and its attempt and task are cancelled. - Each pending timer gets
TimerCancelled, and its timer task is cancelled. - Exception: an activity scheduled with
cancellation_policy: "abandon"(non-local) is left running. The terminal event (WorkflowCompleted,WorkflowFailedorWorkflowContinuedAsNew) lists it underabandoned_activities: [{activity_execution_id, sequence}]. Its later claim, heartbeats and outcome are accepted, but nothing is appended to the closed run, and the outcome reply isrecorded: false, reason: "run_closed". - Children are untouched: parent-close policy and the continue-as-new hand-over (server#1184).
After the close:
- A claim of such an activity's task (including a task left by a pre-upgrade close) is refused with
run_closed, without history. - A late outcome on a completed or failed run is refused with
run_closed. A heartbeat answersactivity_cancelledorrun_closed. - Nothing is ever appended after the terminal event. The Run the Server image and bootstrap job as non-root by default #878 rejection-audit diagnostic is unchanged.
- Replay:
ActivityCancelledevents withcancellation_reason: "run_closed"never resolve a selection or parallel-group member, and activity outcome lookups skip them, because the workflow never observed them. SDK replayers need the same skip; Core's fiber runner, query replayer and executor do this in Bind Native qualification to the published 3.4.0 index #1121.
Cancel, terminate, timeout and cooperative cancellation already settle open work and are unchanged.
Acceptance
- Native closes settle open activities and timers with the same events and keys, and keep abandon-policy activities running without history.
- The SDK replayers (PHP, Python, Rust) skip
run_closedcancellations in member resolution. That's a follow-up per SDK. - Core reference: fixture
selection-loser-settled-at-closeand testsV2OpenOperationsAtCloseTest.
Owner: server.
Metadata
Metadata
Assignees
Labels
agent:serverkind:featureA public product capability or experience is requestedA public product capability or experience is requestedpriority:P1High-priority product or release riskHigh-priority product or release riskrepo:serverOwned by the standalone server repositoryOwned by the standalone server repositorystatus:readyReady for implementationReady for implementation
Activity
rmcdaniel commentedon Nov 13, 2026
For General, acting as SDK owner for PHP, Python and Rust. These are the replayer changes each SDK needs once Server sends #1117 history.
ActivityCancelledwhose payload hascancellation_reason: "run_closed"was recorded by the run's own close, after the workflow had moved past that operation. Replay must not treat it as an outcome:select()/selection member, and must not count as the event that made the winner terminal;all()/parallel group, whether for failure selection or for 'earliest close time, lowest index';In each place the replayer indexes activity outcomes by step sequence, skip these events, and leave the activity as still open.
abandoned_activities: [{activity_execution_id, sequence}]onWorkflowCompleted,WorkflowFailedandWorkflowContinuedAsNew, andcancellation_reasononActivityCancelled. A strict payload-key validator must allow them.run_closed(claim refusal,recorded: falsewith reasonrun_closed, or heartbeatcan_continue: false). Treat it as final and don't retry. For an abandon-policy activity kept running after close, heartbeats keep answeringcan_continue: true, and the outcome is accepted withrecorded: false, reason: run_closed. That is success from the worker's point of view; nothing is recorded on the closed run.Core reference: workflow#1121. Core does (1) in
ParallelChildGroup::resolutionEventForMemberand in the activity outcome lookups ofWorkflowExecutor,QueryStateReplayerandWorkflowFiberRunner::indexRecordedActivityOutcomes. The fixture isselection-loser-settled-at-close, andV2OpenOperationsAtCloseTest::testACancellationRecordedAtCloseNeverReplacesTheFailureTheWorkflowHandledis the vector for theall()case.Split run_closed completion refusals on activity_status
Name the run-close divergence and give its fixtures reviewed native e…