Skip to content

fix(opencode): a reconnect that dies no longer wedges the shared session - #25789

Open
juliusmarminge wants to merge 4 commits into
mainfrom
fix/issue-25751
Open

juliusmarminge wants to merge 4 commits into
mainfrom
fix/issue-25751

Conversation

@juliusmarminge

Copy link
Copy Markdown
Member

Problem

When reconnecting to the OpenCode event stream died with a defect instead of a typed failure (in the report, a schema-decode RangeError: Maximum call stack size exceeded, logged with errorTag: Die), the OpenCode V2 adapter never failed the session. follow used Effect.option, which only catches typed failures, so failAll was skipped: in-flight turns never ended, the session stayed ready, and every later turn on that shared session waited 30 s and then failed with the stale "The OpenCode event stream was lost. Reconnecting." until the T3 server restarted.

Reproduced on main with a red test that makes the reconnect die with that RangeError (the overflowing OpenCode payload itself was not captured, so a live trigger is not available).

Change

  • follow in packages/provider-opencode/src/server/v2/adapter.ts: after Effect.option, a defect also becomes None, so it reaches the existing failAll path, the same as a typed reconnect failure. Interruption (the session closing mid-reconnect) still propagates and does not fail the session.
  • borrow: the forked withConnection now settles its deferred with the full cause (catchCause/failCause instead of catch/fail). Before, a defect there left Deferred.await pending forever, so the reconnect (or an initial session open) hung instead of failing.

A defect is not retried (Effect.retry only retries typed failures), so the session fails on the first defective attempt and the next turn opens a fresh session. The schema RangeError that triggered this is not addressed here.

Scope and approval

Fixes #25751

Triaged via the automated issue flow.

Verification

  • OpenCode2AdapterV2.test.ts: two new table cases, fails the session when reconnecting to the event stream dies (resubscribe dies) and fails the session when borrowing the server to reconnect dies (withConnection dies before lending). Both fail with main's adapter.ts (32bf48f) and pass at 48ddd3e; reverting only the borrow change fails only the second case. Full file: 85/85 pass. vp run check:changed: format, lint, knip, typecheck (6 packages), tests pass.
  • Server-only fix, no visible surface, so no captures. Runtime transcript (same two tests, main's adapter vs this branch):
## BEFORE: test files at 48ddd3ec01, adapter.ts from main 32bf48f428
 × OpenCode2 adapter > fails the session when reconnecting to the event stream dies
 × OpenCode2 adapter > fails the session when borrowing the server to reconnect dies
Expected: "The OpenCode event stream was lost and could not reconnect."
Received: "The OpenCode event stream was lost. Reconnecting."
      Tests  2 failed | 83 skipped (85)

## AFTER: 48ddd3ec01
 ✓ OpenCode2 adapter > fails the session when reconnecting to the event stream dies
 ✓ OpenCode2 adapter > fails the session when borrowing the server to reconnect dies
      Tests  2 passed | 83 skipped (85)

A standalone replay of the adapter with the fix (synthetic transcript) logs the reporter's warning and then fails the session:

WARN: Lost the OpenCode event stream; reconnecting.
WARN: Could not reconnect to the OpenCode event stream; failing the session. RangeError: Maximum call stack size exceeded { errorTag: 'Die' }
{"milestone":"queue ended","terminals":["failed"],"sessionStatus":"error","lastError":"The OpenCode event stream was lost and could not reconnect."}
{"milestone":"later start rejected","tag":"ProviderAdapterEventStreamError","cause":"The OpenCode event stream was lost and could not reconnect."}
  • Not checked: a live OpenCode server producing the schema overflow (payload not captured).

Model and harness: Claude Opus 5.5 (lead, tests, implementation, review B) and GPT-6.1 Sol (review A) in T3 Code.

🤖 Generated with Claude Code

juliusmarminge and others added 4 commits October 27, 2026 05:16
…ect defect

These tests reproduce #25751: when reconnecting to the OpenCode event
stream dies with a defect instead of a typed failure, the session is never
failed, so later turns wait 30 seconds and fail with the stale
"Reconnecting." error and the in-flight turn never ends.

Adds a `relend` testkit hook that swaps the connection lent to reconnect
borrows, so a test can make the resubscribe die.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When resubscribing to the OpenCode event stream died with a defect
instead of a typed failure, `Effect.option` let it escape, the follow
fiber died, and failAll never ran. In-flight turns never ended and later
turns waited 30 seconds on the stale "Reconnecting." error.

`follow` now maps a defect from the reconnect to None too, so it fails
the session the same way a typed failure does, while an interruption of
the follow fiber stays an interruption. `borrow` settles its Deferred
with the full cause of `withConnection`, so a defect there fails the
reconnect instead of hanging it.

Fixes #25751

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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 Oct 27, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 48ddd3e

Macroscope's review found this PR approvable — This targeted fix prevents reconnect defects from wedging the shared OpenCode session by propagating causes and routing failures through the existing session-error path. The added regression tests cover both event-stream and connection-borrow failures, with no broader runtime or configuration changes.

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

@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.9 KiB 20.9 KiB 0 B (0.0%) 29.3 KiB ✅
Codex Live turn messages 2 2 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.2 KiB 21.2 KiB 0 B (0.0%) 29.3 KiB ✅
Claude Live turn messages 2 2 0 (0.0%) 8 ✅

Baseline: bea2e9d · PR result: 48ddd3e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitai Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between bea2e9d and 48ddd3e.

Files selected for processing: 3
  • apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts
  • apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.testkit.ts
  • packages/provider-opencode/src/server/v2/adapter.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

Walkthrough

The OpenCode adapter now preserves full connection failure causes and propagates interruption causes during reconnection. Replay tests can inject defects during reconnection and verify that the session and subsequent turn fail.

Changes: OpenCode reconnect failure handling

Layer / File(s) Summary
Preserve causes and handle reconnect failures
packages/provider-opencode/src/server/v2/adapter.ts
Connection failures are forwarded with their full cause. During reconnection, interrupt causes propagate as interruptions; other causes follow the existing failure path.
Inject reconnect failures in replay tests
apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.testkit.ts, apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts
The replay runtime can return a replacement connection on later borrows. Regression tests inject defects during reconnection and verify that the session and a subsequent startTurn fail.

Priority: Normal

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

Change: Bug fix · Severity of issue fixed: Medium

Possibly related PRs

  • pingdotgg/t3code#24158: Changes OpenCode 2 recovery, event-stream replacement, and owned-server borrowing in the same recovery path.

Suggested reviewers: maria-rcks, fixfon

Merge Risk: Minimal · up to 48ddd

No actionable merge-blocking issue was identified; the change is ready for normal merge checks.

Pre-merge checks: Passed 4
Check name Status Explanation
Description check Passed The description includes all required sections. It clearly explains the problem, the implementation, scope, linked issue, focused verification, observed results, limitations, and agent details.
Title check Passed The title is concise, specific, and accurately describes the main change: preventing a failed OpenCode reconnect from wedging the shared session.
Linked Issues check Passed Issue #25751 requires a reconnect defect to fail the shared session instead of leaving it wedged. In packages/provider-opencode/src/server/v2/adapter.ts, follow catches non-interrupting causes aft…
Out of Scope Changes check Passed The changes stay within issue #25751. The adapter changes handle defect propagation during reconnect and server borrowing. The testkit relend option injects those two failure points for deterministi…
Full details: Linked Issues check

Explanation

Issue #25751 requires a reconnect defect to fail the shared session instead of leaving it wedged. In packages/provider-opencode/src/server/v2/adapter.ts, follow catches non-interrupting causes after Effect.option and routes them to the existing failAll path. The same file changes borrow to settle its deferred with Deferred.failCause, so defects from withConnection do not leave Deferred.await pending. The two new regression cases cover both defect locations and verify the failed terminal state and subsequent ProviderAdapterEventStreamError. The issue's schema RangeError trigger is not a required implementation objective here, and the PR does not claim to fix it.

Full details: Out of Scope Changes check

Explanation

The changes stay within issue #25751. The adapter changes handle defect propagation during reconnect and server borrowing. The testkit relend option injects those two failure points for deterministic regression tests. The new tests verify the required session failure behavior. No unrelated product behavior or surface change is shown.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

GigaZoro pushed a commit to GigaZoro/CodeShip that referenced this pull request Oct 30, 2026
…ion (upstream pingdotgg#25789)

Cherry-picked from pingdotgg#25789

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juliusmarminge juliusmarminge added bugfix Fix PR opened by an issue lead; enters the PR loop pr:gate-failed A land gate failed labels Oct 30, 2026

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

bugfix Fix PR opened by an issue lead; enters the PR loop pr:gate-failed A land gate failed 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.

OpenCode event-stream reconnect dies on a schema RangeError and leaves the shared session wedged until restart

1 participant