Skip to content

fix(server): OpenCode stop no longer hangs when a turn is interrupted before submission - #12003

Open
SunkenInTime wants to merge 1 commit into
pingdotgg:mainfrom
SunkenInTime:devin/1789518164-opencode-stop-settles-admission
Open

SunkenInTime wants to merge 1 commit into
pingdotgg:mainfrom
SunkenInTime:devin/1789518164-opencode-stop-settles-admission

Conversation

@SunkenInTime

@SunkenInTime SunkenInTime commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #11889

What Changed

OpenCodeAdapter.sendTurn now settles promptAdmission.submissionSettled in an Effect.ensuring finalizer on the admission body, so the deferred resolves no matter how the body exits.

context.promptSemaphore.withPermit(
  Effect.gen(function* () { /* unchanged */ }).pipe(
    Effect.ensuring(/* Deferred.succeed(context.promptAdmission?.submissionSettled) */),
  ),
);

Test: stopSession completes after sendTurn is interrupted before the prompt is submitted gates the Clock so sendTurn is parked right after it publishes the admission (in updateProviderSession's nowIso), interrupts it there, then asserts stopSession finishes and the session is gone. It hangs indefinitely without the fix and passes with it.

Why

sendTurn publishes context.promptAdmission and only settles submissionSettled later — at the early-cancel check or in the forked prompt fiber's onExit. Between those points there are yield points (updateProviderSession, emit). If the caller fiber is interrupted in that window (e.g. the turn start is torn down while a thread is being deleted), the deferred is never settled. stopSession → stopOpenCodeContext → cancelPendingOpenCodePrompt then waits on it forever.

That hang sits inside the thread-deletion worker. ws.ts fences every thread.create on ThreadDeletionReactor.drainThrough, so one stuck OpenCode teardown stops every new chat until the server restarts — the symptom reported in #11889. Settling the deferred on every exit path is the smallest change that removes the pin; the deletion fence itself is left as designed.

Reproduce

This is a fiber-interruption race, so there is no deterministic UI or screenshot repro. The regression test is the reproduction:

  1. Check out main, apply only the test from this PR.
  2. vp test run apps/server/src/provider/Layers/OpenCodeAdapter.test.ts -t "interrupted before the prompt is submitted" — the test never completes (stopSession blocks on submissionSettled).
  3. Apply the adapter change — the test passes (111 passed).

In-app the symptom is: delete an OpenCode thread whose turn was being started, then every subsequent "New chat" spins until restart.

UI Changes

Not applicable (server-only; no deterministic UI reproduction).

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A)
  • I included a video for animation/interaction changes

Verified with vp test run apps/server/src/provider/Layers/OpenCodeAdapter.test.ts (111 passed), server tsc --noEmit, and vp lint on the two touched files.

Written by Claude (Devin harness).

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where stopping a session could become stuck if an in-progress message submission was interrupted.
    • Session stopping now completes reliably regardless of whether a pending submission succeeds, fails, or is canceled.
  • Tests

    • Added coverage for stopping sessions while a message submission is paused before being sent.

… before submission

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 16, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 8b9b3c9

Macroscope's review found this PR approvable — This is a small, self-contained server bug fix that settles the pending OpenCode admission during interrupted turns, preventing teardown hangs. A targeted regression test covers the race, with no product-default, schema, deployment, security, or static-analysis changes.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: ccf0eb78-c393-480b-9f61-7fd75fcfd618

📥 Commits

Reviewing files that changed from the base of the PR and between 935c55b and 8b9b3c9.

📒 Files selected for processing (2)
  • apps/server/src/provider/Layers/OpenCodeAdapter.test.ts
  • apps/server/src/provider/Layers/OpenCodeAdapter.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

sendTurn now settles prompt submission state when it completes, including interruption. A regression test interrupts a pre-submit send and verifies that stopSession completes and removes the session.

Changes

OpenCode shutdown

Layer / File(s) Summary
Prompt submission settlement and regression coverage
apps/server/src/provider/Layers/OpenCodeAdapter.ts, apps/server/src/provider/Layers/OpenCodeAdapter.test.ts
sendTurn settles submissionSettled in an Effect.ensuring finalizer. The test uses a gated clock, interrupts a pre-submit send, and verifies successful session shutdown and session removal.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: t3dotgg

Merge Risk: ⚪ Minimal · up to 8b9b3

No concrete merge-blocking risk remains; the interrupted-send shutdown fix is mergeable after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the OpenCode server hang and its fix when a turn is interrupted before submission.
Description check ✅ Passed The description includes the change, cause, rationale, reproduction steps, test coverage, UI applicability, and validation results. It is small in scope and matches the required template.
Linked Issues check ✅ Passed Issue #11889 requires teardown to complete when prompt admission is interrupted and to avoid the deletion barrier blocking later chats. The PR wraps the sendTurn prompt-admission body in `Effect.ens…
Out of Scope Changes check ✅ Passed The changes are limited to apps/server/src/provider/Layers/OpenCodeAdapter.ts and its test. The production change fixes the prompt-admission teardown state from issue #11889. The test directly cover…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@shivamhwp

Copy link
Copy Markdown
Collaborator

Note: GPT-6 on behalf of shivam (@shivamhwp).

This fixes the interrupted-send cancellation race behind #11889. The remaining gap is that ThreadDeletionReactor.drainThrough still waits for all deletions, so cleanup stuck for another reason can block unrelated new chats.

Could we make that wait specific to the thread being created? Reusing the same thread ID should still wait for its previous cleanup, while unrelated chats should proceed. Add regression coverage for both behaviors.

This could be a separate follow-up PR to keep your cancellation fix focused.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Stuck OpenCode deletion blocks new chats in ThreadDeletionReactor.drainThrough

2 participants