fix: don't discard a finished task result when cancel races completion - #167
Merged
PleasePrompto merged 1 commit intoJul 12, 2026
Merged
Conversation
TaskHub.cancel() arriving between CLI completion and result delivery landed CancelledError at the delivery await: the handler then overwrote the task's terminal status from "done" to "cancelled" and delivered only the TASKMEMORY excerpt, silently discarding the completed response the subprocess had already produced (and billed). Shield the final delivery and make the cancellation handler a no-op once delivery has started, so a late cancel preserves the finished result. Also log task cancellations (hub and internal API, including the requesting agent) — previously cancels left no trace in the log, making post-hoc diagnosis impossible.
ryuhaneul
force-pushed
the
fix/task-cancel-observability
branch
from
July 9, 2026 01:08
614a42e to
700780b
Compare
ryuhaneul
marked this pull request as ready for review
July 9, 2026 02:22
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.
Problem
Completion race loses finished results.
TaskHub._run()obtainsthe CLI response, writes terminal status
done, then awaits resultdelivery. A
TaskHub.cancel()arriving in that window landsCancelledErrorat the delivery await: the handler overwrites theterminal status from
donetocancelledand delivers only theTASKMEMORY excerpt — silently discarding the completed response the
subprocess had already produced (and billed). From the user's side the
task "finished into nothing".
Cancellations leave no trace. Neither
TaskHub.cancel(),cancel_all(), nor the internal API cancel endpoint logged anything,so after the fact there is no way to tell who cancelled a task or when.
Fix
a hub-level
_pending_deliveriesset (dropped via done-callback), andawait it through
asyncio.shield(). TheCancelledErrorhandlerbecomes a no-op once final delivery has started: the terminal
donestatus stands and the finished result is delivered exactly once.
Mid-run cancellation is unchanged (status
cancelled, TASKMEMORYpartial delivered). Shutdown drains any pending deliveries.
cancel(), a count incancel_all(), and the internal API cancel including the requestingagent.
Semantics note: the cancel API's
success=truemeans the request wasaccepted; when completion wins the race the task's final status remains
doneand the result is delivered.Tests
Six scenarios: late cancel via
cancel()preserves the result (deliveredonce, status
done, no partialcancelleddelivery); same viacancel_all(); mid-run cancel still delivers the TASKMEMORY partial withstatus
cancelled; the four cancel log flows (caplog); shutdown drains ablocked pending delivery; API cancel logs the requesting agent.
4 files changed, +253/−17. Rollback = revert (no config/schema impact).