Repository navigation
Acknowledge pending workflow replay without empty-command completion errors #98
Description
Activity
- addedauthority:githubGitHub is the authoritative lifecycle record for this workGitHub is the authoritative lifecycle record for this workkind:defectA public product behavior is incorrectA public product behavior is incorrectpriority:P1High-priority product or release riskHigh-priority product or release riskcompletion:evidence-requiredClose only after all explicit acceptance and operational evidence is publicClose only after all explicit acceptance and operational evidence is publicintake:approvedCurrent issue title and body revision is approved for authority intakeCurrent issue title and body revision is approved for authority intakestatus:in-progressApproved work is actively being implemented or validatedApproved work is actively being implemented or validated
on Oct 7, 2026 Delivered in PR #99, merged as
2fe5acc9f03664bd5fff5d298849931477247d81, and published as Python SDK 2.4.2. The immutable release tag points to that exact main commit.Exact PR and main CI pass 2,460 unit tests across Python 3.10/3.11/3.12 and 22 connected tests, plus lint, mypy, corpus and package checks. Publication succeeds. The live SDK reference documents the waiting acknowledgement and stream metadata guard. The merged branch is deleted.
A normal PyPI install of 2.4.2 passes the published Server 2.3.12 to 2.5.6 recovery scenario with PHP 2.2.3 and Rust 3.2.0 on protocol 1.19. All nine original completed/waiting/queued workflows complete with identical 204800-byte external payloads and committed history prefixes. After repeated signals and SDK process SIGKILL while timers are still pending, waiting runs each have one scheduled/fired timer and total eighteen. Each run has one activity and workflow completion.
The complete HTTP log has zero HTTP 422s and six successful waiting acknowledgements across 2,765 requests. Python logs have no workflow task completion error. Rust's temporary HTTP 502 exit during replacement is recovered by its normal supervisor. This verifies supervised recovery without promising uninterrupted worker processes. All disposable resources are removed. Nonempty completion parity and configured HTTP timeout tests remain passing. Stream metadata without commands is refused before a waiting request, so it cannot be silently discarded.
- addedstatus:doneDerived from the authoritative closed issue stateDerived from the authoritative closed issue statecompletion:evidence-verifiedAcceptance, fixed version, and required operational evidence are publicly verifiedAcceptance, fixed version, and required operational evidence are publicly verifiedand removedcompletion:evidence-requiredClose only after all explicit acceptance and operational evidence is publicClose only after all explicit acceptance and operational evidence is publicstatus:in-progressApproved work is actively being implemented or validatedApproved work is actively being implemented or validated
on Oct 7, 2026
Observed defect
Published Python SDK 2.4.1 preserves a pending operation during replay, but its client submits
commands: []to/worker/workflow-tasks/{task_id}/complete. Server requires a nonempty command list and returns HTTP 422,The commands field is required.This reproduces with published Server 2.3.12 and 2.5.6: start an echo activity followed by a durable timer, then signal while the timer is pending. Replay correctly retains the original timer, but its task acknowledgement is rejected. The workflow can later complete when the timer fires, hiding the failed acknowledgement in an otherwise successful final result.
PHP already sends empty-command replay through the established
/failacknowledgement with failure typeWorkflowTaskWaitingForHistory. This is a waiting acknowledgement, not a workflow failure. Python should use the same protocol.Required outcome
Found while rerunning the published-package continuity scenario after #96. The scalar replay fix remains correct. This is the additional transport acknowledgement gap its corrected pending path exposes.