Repository navigation
fix(opencode): a reconnect that dies no longer wedges the shared session - #25789
juliusmarminge wants to merge 4 commits into
Conversation
…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>
ApprovabilityVerdict: Approved at 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. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 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.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
No actionable comments were generated in the recent review.
|
| 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:
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: 
4
-
Full details: Linked Issues check
-
Explanation
Issue
#25751requires a reconnect defect to fail the shared session instead of leaving it wedged. Inpackages/provider-opencode/src/server/v2/adapter.ts,followcatches non-interrupting causes afterEffect.optionand routes them to the existingfailAllpath. The same file changesborrowto settle its deferred withDeferred.failCause, so defects fromwithConnectiondo not leaveDeferred.awaitpending. The two new regression cases cover both defect locations and verify the failed terminal state and subsequentProviderAdapterEventStreamError. The issue's schemaRangeErrortrigger 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 testkitrelendoption 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.
…ion (upstream pingdotgg#25789) Cherry-picked from pingdotgg#25789 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 witherrorTag: Die), the OpenCode V2 adapter never failed the session.followusedEffect.option, which only catches typed failures, sofailAllwas skipped: in-flight turns never ended, the session stayedready, 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
followinpackages/provider-opencode/src/server/v2/adapter.ts: afterEffect.option, a defect also becomesNone, so it reaches the existingfailAllpath, the same as a typed reconnect failure. Interruption (the session closing mid-reconnect) still propagates and does not fail the session.borrow: the forkedwithConnectionnow settles its deferred with the full cause (catchCause/failCauseinstead ofcatch/fail). Before, a defect there leftDeferred.awaitpending forever, so the reconnect (or an initial session open) hung instead of failing.A defect is not retried (
Effect.retryonly retries typed failures), so the session fails on the first defective attempt and the next turn opens a fresh session. The schemaRangeErrorthat 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) andfails the session when borrowing the server to reconnect dies(withConnectiondies before lending). Both fail with main'sadapter.ts(32bf48f) and pass at 48ddd3e; reverting only theborrowchange fails only the second case. Full file: 85/85 pass.vp run check:changed: format, lint, knip, typecheck (6 packages), tests pass.A standalone replay of the adapter with the fix (synthetic transcript) logs the reporter's warning and then fails the session:
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