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..a0466ae37 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() + 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() + expect(await coreControl.awaitRpcCall(LIST_PATH, closeMark)).toBe(200) + 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)