🤖 refactor: make turn cancellation and session disposal awaitable - #4118
Merged
Conversation
Keep cancellation bound to its captured stream until partial persistence, resource cleanup, and raw terminal delivery finish. Session disposal now closes admission synchronously and returns one stable Promise that joins engine cleanup, background work, and original execution leases. Keep workspace bridges attached through disposal and transfer destructive continuation-failure cleanup outside held callbacks and locks. A sibling app-scope guardian owns deferred cleanup within the existing shutdown budget; CLI teardown initiates disposal without adding a second unbounded join. Empty guardian rollback stays synchronous to preserve constructor failure reporting. Validation: full static checks pass, alongside 512 session/coordinator/queue/ hook tests, 421 engine/history/AI tests, 1162 workspace/task/container tests, and 20 CLI/updated-edit-fixture tests. Main build and isolated real-backend Electron interruption (1 test) and send-mode (5 tests) workflows also pass. Signed-off-by: Thomas Kosiewski <tk@coder.com> --- _Generated with `xum` • Model: `unavailable` • Thinking: `unavailable` • Cost: `$unavailable`_ <!-- mux-attribution: model=unavailable thinking=unavailable costs=unavailable --> Change-Id: Ic9f04b6d889877c85c694cad127f61b9dfc5e858
This comment has been minimized.
This comment has been minimized.
Member
Author
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep it up! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
This comment has been minimized.
This comment has been minimized.
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Sep 7, 2026
ibetitsmike
added a commit
that referenced
this pull request
Sep 7, 2026
When an accepted wake's consumption I/O keeps failing until the app exits, the durable transcript row is the only record of delivery: on the next run the signal derives as outstanding again and the in-memory owed acceptance is gone. The reconciler now asks the owner's history for wake records before dispatching and treats a signal whose (processId, wakeUpdatedAt) key is already in the transcript as delivered, advancing its watermark and acknowledging it with no new row. The lookup scans full history backward, compaction archive included, stopping once a chunk predates every process being checked, and is memoized per outstanding key so an unchanged frontier reconciles without another read. A failed history read rejects so dispatch stays held in the retry backoff. Also retires the wake-wiring test harness's never-completed stream handles on session close, which #4118's awaitable dispose otherwise drains forever.
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.
Cancellation now finishes the captured stream attempt's partial persistence and terminal delivery before a replacement starts. Session and workspace disposal await in-flight work, while application and CLI shutdown keep their existing bounded teardown budget.
Abort persistence moves from AIService event forwarding into StreamManager and its mock counterpart. The first cancellation owns its reason and completion; identity checks prevent old cleanup from touching a replacement, and failed commits retain recoverable partial data. Startup cancellation joins the same completion barrier without waiting on an envelope callback that may itself await stop.
AgentSession separates synchronous closing from awaitable disposal. WorkspaceService tracks destructive cleanup outside continuation callbacks to avoid joining the callback that requested removal, keeps subscriptions through captured terminal delivery, and joins cleanup within the app scope. Closing cancels idle and queue waits separately from physical cleanup. Empty service-graph rollback remains synchronous so constructor failures retain their original error.
Test fixtures now await teardown. Policy-only fake handles retire on their own session's closing signal; lifecycle tests retain independent completion barriers.
Validation: 512 session/coordinator/queue/hooks tests, 421 engine/history/AI/mock tests, 1,162 workspace/task/container tests, and 20 CLI/edit tests passed. The full static check and main-process build passed. Isolated UI suites passed for interruption (1 test) and send-mode/queue behavior (5 tests). Deterministic regressions hold disk writes, envelope callbacks, session work and task-tree locks to exercise concurrent stop, replacement, cleanup errors, reentrant disposal, and shutdown bounds.
Risk: incorrect cleanup ordering could stall interruption or workspace removal, or lose interrupted output. Raw engine events retain their role, and session policy settlement stays separate from engine completion to avoid circular waits. Compaction policy and retry ownership remain for later phases.
Generated with
xum• Model:unavailable• Thinking:unavailable• Cost:$unavailable