From be6d1cae1eb879de91ec8c730566e5e096a2dabc Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 09:07:01 +0000 Subject: [PATCH 1/2] test(client-runtime): shell subscription resubscribes after a stream defect Fails on main: a defect on the shell stream ends the forked subscription, so a later session never resubscribes and the sidebar stays frozen (#4589). AI-assisted; verified with the tests and tools listed above. --- .../client-runtime/src/state/shell-sync.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/client-runtime/src/state/shell-sync.test.ts b/packages/client-runtime/src/state/shell-sync.test.ts index 062db03809cfc..1cfe20b403ee8 100644 --- a/packages/client-runtime/src/state/shell-sync.test.ts +++ b/packages/client-runtime/src/state/shell-sync.test.ts @@ -7,6 +7,7 @@ import { type ThreadPullRequestLink, } from "@t3tools/contracts"; import { describe, expect, it } from "@effect/vitest"; +import * as Cause from "effect/Cause"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; @@ -1314,4 +1315,18 @@ describe("environment shell cold start", () => { yield* h.liveAt(HTTP_SEQUENCE + 1); }), ); + + it.effect("resubscribes on the next session after a stream defect (#4589)", () => + Effect.gen(function* () { + const h = yield* makeColdStart(RECENT_ORIGIN); + const first = yield* Queue.take(h.subscriptions); + yield* Queue.offer(first.events, { kind: "synchronized" }); + yield* h.liveAt(CACHED_SEQUENCE); + + yield* Queue.failCause(first.events, Cause.die(new Error("shell stream defect"))); + yield* h.reconnect; + const resumed = yield* Queue.take(h.subscriptions); + expect(resumed.input).toMatchObject({ afterSequence: CACHED_SEQUENCE }); + }), + ); }); From 25db61e8b32eecabc9f248c4a20454bf73fc6f50 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 09:15:12 +0000 Subject: [PATCH 2/2] fix(client-runtime): the sidebar thread list resubscribes after a shell stream defect The environment shell subscription had no onDefect handler, so a defect failed the whole stream and no later session or wakeup resubscribed it. Report the defect through setStreamError so the subscription parks until the next session or wakeup and the stale list shows an error meanwhile. Fixes pingdotgg/t3code#4589 AI-assisted; verified with the tests and tools listed above. --- packages/client-runtime/src/state/shell.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client-runtime/src/state/shell.ts b/packages/client-runtime/src/state/shell.ts index 808fd9fdece56..b62b1a7aa49f5 100644 --- a/packages/client-runtime/src/state/shell.ts +++ b/packages/client-runtime/src/state/shell.ts @@ -538,6 +538,7 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make") }; }), { + onDefect: (cause) => setStreamError(Cause.squash(cause)), onExpectedFailure: (cause) => setStreamError(Cause.squash(cause)), retryExpectedFailureAfter: "250 millis", resubscribe: resubscriptions,