diff --git a/webviews/src/agent-session/acpmux/conversation/TranscriptCohesion.gallery.ts b/webviews/src/agent-session/acpmux/conversation/TranscriptCohesion.gallery.ts index c802e40ca46d..3d11fb120f9f 100644 --- a/webviews/src/agent-session/acpmux/conversation/TranscriptCohesion.gallery.ts +++ b/webviews/src/agent-session/acpmux/conversation/TranscriptCohesion.gallery.ts @@ -1,5 +1,5 @@ // l10n-allow-file: synthetic transcript fixtures, not shipped UI. -// One rhythm across harnesses, without giving Claude a whole-turn fold. References: +// One rhythm across harnesses; a finished Claude turn folds under Worked for too (cmux#34774). References: // chatgpt/live/transcript-thinking-and-tool-calls-consolidation and // claude/live/transcript-agent-text-and-collapsed-tool-row. import { agentPaneEntry } from "../../../gallery/format"; @@ -93,7 +93,7 @@ export default agentPaneEntry({ }, }, claude: { - note: "Claude: each tool run has its own summary; the reply remains visible with no whole-turn Worked for.", + note: "Claude: the finished turn folds under one 22px Worked for, 16px from the reply, as Codex does.", snapshot: transcript("claude"), }, }, diff --git a/webviews/test/transcript-cohesion.test.ts b/webviews/test/transcript-cohesion.test.ts index eb3c94be4fc3..552229c9b2a0 100644 --- a/webviews/test/transcript-cohesion.test.ts +++ b/webviews/test/transcript-cohesion.test.ts @@ -173,53 +173,46 @@ await requireBrowserLane("transcript-cohesion.test.ts", async () => { .filter({ hasText: "All three focused tests pass." }) .waitFor({ timeout: 10_000 }); const headers = page.locator(".acpmux-worked > .cv-worked"); - if (variant === "claude") { - expect(await headers.count()).toBe(0); - await page - .locator(".cv-tool") - .filter({ hasText: /Read|Ran|Searched|Used/ }) - .first() - .waitFor(); - } else { - await headers.waitFor(); - await page.waitForFunction( - (open) => - document.querySelector(".acpmux-worked > .cv-worked")?.getAttribute("aria-expanded") === String(open), - variant === "codex-open", - ); - const measured = await page.evaluate(() => { - const header = document.querySelector(".acpmux-worked > .cv-worked")!; - const row = header.closest(".acpmux-row")!; - const reply = [...document.querySelectorAll(".acpmux-assistant")].find((node) => - node.textContent?.includes("All three focused tests pass."), - )!; - // Visible text marks, as the shared spacing table measures them; keep row-box - // checks too, so the estimate cannot hide a different rendered line height. - const firstLineCenter = (element: Element) => { - const range = document.createRange(); - range.selectNodeContents(element); - const rect = range.getClientRects()[0]!; - return (rect.top + rect.bottom) / 2; - }; - const box = header.getBoundingClientRect(); - const next = row.nextElementSibling!.getBoundingClientRect(); - return { - headerHeight: box.height, - nextGap: next.top - box.bottom, - replyGap: reply.getBoundingClientRect().top - box.bottom, - replyCenterGap: - firstLineCenter(reply.querySelector(".cv-md p")!) - - firstLineCenter(header.querySelector(".cv-worked__label")!), - }; - }); - console.log(`transcript-cohesion ${variant} ${label}: ${JSON.stringify(measured)}`); - if (process.env.CMUX_COHESION_MEASURE_ONLY !== "1") { - expect(measured.headerHeight).toBeCloseTo(22, 1); - if (variant === "codex-closed") { - expect(measured.replyGap).toBeCloseTo(16, 1); - expect(Math.abs(measured.replyCenterGap - 38.375)).toBeLessThan(1); - } else expect(measured.nextGap).toBeCloseTo(0, 1); - } + // A finished Claude turn folds under one Worked for too (cmux#34774), so it shares + // the closed Codex header's rhythm. + await headers.waitFor(); + await page.waitForFunction( + (open) => + document.querySelector(".acpmux-worked > .cv-worked")?.getAttribute("aria-expanded") === String(open), + variant === "codex-open", + ); + const measured = await page.evaluate(() => { + const header = document.querySelector(".acpmux-worked > .cv-worked")!; + const row = header.closest(".acpmux-row")!; + const reply = [...document.querySelectorAll(".acpmux-assistant")].find((node) => + node.textContent?.includes("All three focused tests pass."), + )!; + // Visible text marks, as the shared spacing table measures them; keep row-box + // checks too, so the estimate cannot hide a different rendered line height. + const firstLineCenter = (element: Element) => { + const range = document.createRange(); + range.selectNodeContents(element); + const rect = range.getClientRects()[0]!; + return (rect.top + rect.bottom) / 2; + }; + const box = header.getBoundingClientRect(); + const next = row.nextElementSibling!.getBoundingClientRect(); + return { + headerHeight: box.height, + nextGap: next.top - box.bottom, + replyGap: reply.getBoundingClientRect().top - box.bottom, + replyCenterGap: + firstLineCenter(reply.querySelector(".cv-md p")!) - + firstLineCenter(header.querySelector(".cv-worked__label")!), + }; + }); + console.log(`transcript-cohesion ${variant} ${label}: ${JSON.stringify(measured)}`); + if (process.env.CMUX_COHESION_MEASURE_ONLY !== "1") { + expect(measured.headerHeight).toBeCloseTo(22, 1); + if (variant !== "codex-open") { + expect(measured.replyGap).toBeCloseTo(16, 1); + expect(Math.abs(measured.replyCenterGap - 38.375)).toBeLessThan(1); + } else expect(measured.nextGap).toBeCloseTo(0, 1); } if (process.env.FAST_CHECKS_OUT) { await mkdir(process.env.FAST_CHECKS_OUT, { recursive: true });