From 041686b2731ae632f38383be0c97106bdaa29a01 Mon Sep 17 00:00:00 2001 From: Omri Katz <9701896+omridevk@users.noreply.github.com> Date: Sat, 15 Aug 2026 12:46:41 +0300 Subject: [PATCH 1/2] =?UTF-8?q?chore:=20#508=20follow-ups=20=E2=80=94=20sc?= =?UTF-8?q?ope=20session=20invalidation,=20drop=20stale=20fallow=20publicP?= =?UTF-8?q?ackages=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit invalidateSessions invalidated the whole sessions router key, so every pane add/close/new-session refetched the warm sessions.resolve query in the root chrome as well as the list it actually changes. The warm resolve keys off the latest session row, so it already refetches on its own when that row moves; the extra round-trips were pure waste (measured: 3 resolves per quick add/close flow instead of 1). .fallowrc.json listed @conciv/harness-testkit under publicPackages, but the package is private and absent from PUBLIC_PACKAGES. Removing the entry surfaced two exports in run-events.ts that only have in-file callers; they are now module private. Co-Authored-By: Claude Fable 5 --- .changeset/scoped-session-invalidation.md | 5 ++++ .fallowrc.json | 1 - apps/conciv/src/data/app-data.ts | 2 +- .../test/quick-add-pane.browser.test.tsx | 24 +++++++++++++++++++ packages/harness-testkit/src/run-events.ts | 4 ++-- 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 .changeset/scoped-session-invalidation.md diff --git a/.changeset/scoped-session-invalidation.md b/.changeset/scoped-session-invalidation.md new file mode 100644 index 000000000..ab50ccdbb --- /dev/null +++ b/.changeset/scoped-session-invalidation.md @@ -0,0 +1,5 @@ +--- +'@conciv/embed': patch +--- + +Scope widget session invalidation to the session list, so adding, closing or creating a pane no longer re-resolves the warm session over the wire. diff --git a/.fallowrc.json b/.fallowrc.json index 64a3af315..ccb3c8166 100644 --- a/.fallowrc.json +++ b/.fallowrc.json @@ -106,7 +106,6 @@ "@conciv/extension-whiteboard", "@conciv/grab", "@conciv/harness", - "@conciv/harness-testkit", "@conciv/it", "@conciv/mascot", "@conciv/plugin", diff --git a/apps/conciv/src/data/app-data.ts b/apps/conciv/src/data/app-data.ts index 3ee0bbf66..018a45749 100644 --- a/apps/conciv/src/data/app-data.ts +++ b/apps/conciv/src/data/app-data.ts @@ -11,6 +11,6 @@ export function makeAppData(rpc: RpcClient, queryClient: QueryClient): AppData { const utils = makeQueryUtils(rpc) return { utils, - invalidateSessions: () => void queryClient.invalidateQueries({queryKey: utils.sessions.key()}), + invalidateSessions: () => void queryClient.invalidateQueries({queryKey: utils.sessions.list.key()}), } } diff --git a/apps/conciv/test/quick-add-pane.browser.test.tsx b/apps/conciv/test/quick-add-pane.browser.test.tsx index 6d54c3cdc..671373242 100644 --- a/apps/conciv/test/quick-add-pane.browser.test.tsx +++ b/apps/conciv/test/quick-add-pane.browser.test.tsx @@ -8,6 +8,7 @@ import {trackedFaults} from './helpers/tracked-faults.js' import {expectRetryRecovers} from './helpers/retry-recovery.js' const RESOLVE_PATH = ['sessions', 'resolve'] +const LIST_PATH = ['sessions', 'list'] const core = {base: ''} const harness = createShellHarness(() => core.base) @@ -63,3 +64,26 @@ test('rapid double-trigger creates exactly one pane', async () => { await expect.element(closePane().nth(1), {timeout: 8000}).toBeVisible() await expect.element(closePane().nth(2)).not.toBeInTheDocument() }, 30_000) + +test('adding and closing a pane never re-resolves the warm session', async () => { + const rpc = coreRpc(core.base) + const sessionId = await createSession(rpc) + const mountMark = await coreControl.rpcMark() + harness.mountShell(`/quick?panes=${sessionId}&focus=0`) + await expect.element(editor(), {timeout: 8000}).toBeVisible() + await coreControl.awaitRpcCall(RESOLVE_PATH, mountMark) + const resolvesAfterWarmUp = await coreControl.rpcCallCount(RESOLVE_PATH) + + const addMark = await coreControl.rpcMark() + await page.getByRole('button', {name: 'Split pane (Mod+D)'}).click() + await expect.element(closePane().nth(1), {timeout: 8000}).toBeVisible() + await coreControl.awaitRpcCall(LIST_PATH, addMark) + + const closeMark = await coreControl.rpcMark() + await closePane().nth(1).click() + await expect.element(closePane().nth(1)).not.toBeInTheDocument() + await coreControl.awaitRpcCall(LIST_PATH, closeMark) + await rpc.sessions.list() + + expect((await coreControl.rpcCallCount(RESOLVE_PATH)) - resolvesAfterWarmUp).toBe(1) +}, 30_000) diff --git a/packages/harness-testkit/src/run-events.ts b/packages/harness-testkit/src/run-events.ts index 56df7e3be..b11b66ed0 100644 --- a/packages/harness-testkit/src/run-events.ts +++ b/packages/harness-testkit/src/run-events.ts @@ -26,7 +26,7 @@ function parseArgs(raw: string): unknown { } } -export function renderedMessages(all: StreamChunk[]): unknown[] { +function renderedMessages(all: StreamChunk[]): unknown[] { const processor = new StreamProcessor({}) for (const chunk of all) processor.processChunk(chunk) return processor.getMessages() @@ -64,7 +64,7 @@ export function collectToolCalls(all: StreamChunk[], name?: string): SeenToolCal .map((part) => ({toolCallId: part.id, name: part.name, input: parseArgs(part.arguments)})) } -export function snapshotText(all: StreamChunk[]): string { +function snapshotText(all: StreamChunk[]): string { return partsOf(all, 'assistant') .flatMap((part) => { const parsed = TextPartSchema.safeParse(part) From 5edee472c517dbebac15c6dc73950c2d32791d27 Mon Sep 17 00:00:00 2001 From: Omri Katz <9701896+omridevk@users.noreply.github.com> Date: Sat, 15 Aug 2026 12:57:30 +0300 Subject: [PATCH 2/2] test(conciv): #509 assert list refetch status in the warm-session guard Co-Authored-By: Claude Fable 5 --- apps/conciv/test/quick-add-pane.browser.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/conciv/test/quick-add-pane.browser.test.tsx b/apps/conciv/test/quick-add-pane.browser.test.tsx index 671373242..a0466ae37 100644 --- a/apps/conciv/test/quick-add-pane.browser.test.tsx +++ b/apps/conciv/test/quick-add-pane.browser.test.tsx @@ -77,12 +77,12 @@ test('adding and closing a pane never re-resolves the warm session', async () => const addMark = await coreControl.rpcMark() await page.getByRole('button', {name: 'Split pane (Mod+D)'}).click() await expect.element(closePane().nth(1), {timeout: 8000}).toBeVisible() - await coreControl.awaitRpcCall(LIST_PATH, addMark) + expect(await coreControl.awaitRpcCall(LIST_PATH, addMark)).toBe(200) const closeMark = await coreControl.rpcMark() await closePane().nth(1).click() await expect.element(closePane().nth(1)).not.toBeInTheDocument() - await coreControl.awaitRpcCall(LIST_PATH, closeMark) + expect(await coreControl.awaitRpcCall(LIST_PATH, closeMark)).toBe(200) await rpc.sessions.list() expect((await coreControl.rpcCallCount(RESOLVE_PATH)) - resolvesAfterWarmUp).toBe(1)