Repository navigation
fix(tray): align status and controls with the composer - #29885
Conversation
|
Review (subagent): SHIP at 4dff66a The validation fixes are coherent: scroll-margin-block 2px addresses fractional clipping, visible status expectation matches the named behavior, layout coverage checks computed tray outset and rejects hardcoded margin, and the highlight links this fresh PR. No blocking findings. |
There was a problem hiding this comment.
1 issue found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="webviews/src/agent-session/acpmux/subagents/subagents.css">
<violation number="1" location="webviews/src/agent-session/acpmux/subagents/subagents.css:715">
P2: Below 168px, the narrow grid still needs 168px after the status track reaches 0px, so its overflowing columns diverge from the absolutely positioned Stop slot and can clip the trailing controls. Reserve a minimum width or shrink/reflow the fixed duration/control tracks together instead of contracting only the status track.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| .acpmux-running-tray .acpmux-agent-line > .acpmux-agent-line__button { | ||
| /* At the smallest split widths, only the status track contracts. The track remains the | ||
| same width on every row; duration and the composer-aligned controls never get pushed out. */ | ||
| --acpmux-tray-status-width: clamp(0px, calc(100cqw - var(--acpmux-tray-time-width) - var(--acpmux-tray-stop-width) - var(--acpmux-tray-chevron-width) - 4 * var(--acpmux-tray-gap) - 2 * var(--acpmux-tray-inset)), 74px); |
There was a problem hiding this comment.
P2: Below 168px, the narrow grid still needs 168px after the status track reaches 0px, so its overflowing columns diverge from the absolutely positioned Stop slot and can clip the trailing controls. Reserve a minimum width or shrink/reflow the fixed duration/control tracks together instead of contracting only the status track.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/agent-session/acpmux/subagents/subagents.css, line 715:
<comment>Below 168px, the narrow grid still needs 168px after the status track reaches 0px, so its overflowing columns diverge from the absolutely positioned Stop slot and can clip the trailing controls. Reserve a minimum width or shrink/reflow the fixed duration/control tracks together instead of contracting only the status track.</comment>
<file context>
@@ -673,62 +707,39 @@ button.cv-subagent > :last-child {
.acpmux-running-tray .acpmux-agent-line > .acpmux-agent-line__button {
+ /* At the smallest split widths, only the status track contracts. The track remains the
+ same width on every row; duration and the composer-aligned controls never get pushed out. */
+ --acpmux-tray-status-width: clamp(0px, calc(100cqw - var(--acpmux-tray-time-width) - var(--acpmux-tray-stop-width) - var(--acpmux-tray-chevron-width) - 4 * var(--acpmux-tray-gap) - 2 * var(--acpmux-tray-inset)), 74px);
position: relative;
- display: grid;
</file context>
|
Review (subagent): SHIP at 66f1d1bd8dd7c6c046c2f146d2ea5eedb005d0d9 The one-line scroll-padding-block: 2px on the tray list complements the existing Stop scroll margin and addresses the ~0.45px bottom overflow from the owned-fleet columns checks without weakening tolerance or changing unrelated behavior. |
There was a problem hiding this comment.
2 issues found across 4 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="webviews/test/subagent-tray-layout.test.ts">
<violation number="1" location="webviews/test/subagent-tray-layout.test.ts:11">
P2: This assertion no longer verifies the shared outer inset on both sides or that `--acpmux-tray-outset` is applied to the margin; `toContain` is satisfied by the declaration itself. Match the complete four-value margin so future alignment regressions fail this test.</violation>
</file>
<file name="webviews/test/subagent-tray-columns.test.ts">
<violation number="1" location="webviews/test/subagent-tray-columns.test.ts:554">
P3: This assertion only verifies one state element, so rows can still lose their visible status word while the test passes. Assert that every tray row has a non-empty state element.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| expect(rule).toMatch(/margin:\s*0\s+calc\(var\(--cv-inset-end,/); | ||
| expect(rule).toContain("--acpmux-tray-outset"); |
There was a problem hiding this comment.
P2: This assertion no longer verifies the shared outer inset on both sides or that --acpmux-tray-outset is applied to the margin; toContain is satisfied by the declaration itself. Match the complete four-value margin so future alignment regressions fail this test.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/subagent-tray-layout.test.ts, line 11:
<comment>This assertion no longer verifies the shared outer inset on both sides or that `--acpmux-tray-outset` is applied to the margin; `toContain` is satisfied by the declaration itself. Match the complete four-value margin so future alignment regressions fail this test.</comment>
<file context>
@@ -8,8 +8,9 @@ test("the bottom-stack tray is flush with the composer and keeps the shared oute
// --cv-inset-end where the pane sets it, #26068).
- expect(rule).toMatch(/margin:\s*0\s+var\(--cv-inset-end,\s*var\(--cv-inset\)\)\s+0\s+var\(--cv-inset\)\s*;/);
- expect(rule).not.toMatch(/8px/);
+ expect(rule).toMatch(/margin:\s*0\s+calc\(var\(--cv-inset-end,/);
+ expect(rule).toContain("--acpmux-tray-outset");
+ expect(rule).not.toMatch(/margin:[^;]*8px/);
</file context>
| expect(rule).toMatch(/margin:\s*0\s+calc\(var\(--cv-inset-end,/); | |
| expect(rule).toContain("--acpmux-tray-outset"); | |
| expect(rule).toMatch(/margin:\s*0\s+calc\(var\(--cv-inset-end,\s*var\(--cv-inset\)\)\s*-\s*var\(--acpmux-tray-outset\)\)\s+0\s+calc\(var\(--cv-inset\)\s*-\s*var\(--acpmux-tray-outset\)\)\s*;/); |
| // Running lines say no Running: the spinner is their state (the next describe's anatomy). | ||
| expect(await page.locator(".acpmux-running-tray__list .acpmux-summary-agent__state").count()).toBe(0); | ||
| // Running lines keep their visible state word in the fixed status track, alongside ended rows. | ||
| expect(await page.locator(".acpmux-running-tray__list .acpmux-summary-agent__state").count()).toBeGreaterThan(0); |
There was a problem hiding this comment.
P3: This assertion only verifies one state element, so rows can still lose their visible status word while the test passes. Assert that every tray row has a non-empty state element.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/subagent-tray-columns.test.ts, line 554:
<comment>This assertion only verifies one state element, so rows can still lose their visible status word while the test passes. Assert that every tray row has a non-empty state element.</comment>
<file context>
@@ -550,8 +550,8 @@ await requireBrowserLane("subagent-tray-columns.test.ts", async () => {
- // Running lines say no Running: the spinner is their state (the next describe's anatomy).
- expect(await page.locator(".acpmux-running-tray__list .acpmux-summary-agent__state").count()).toBe(0);
+ // Running lines keep their visible state word in the fixed status track, alongside ended rows.
+ expect(await page.locator(".acpmux-running-tray__list .acpmux-summary-agent__state").count()).toBeGreaterThan(0);
} finally {
await page.close();
</file context>
| expect(await page.locator(".acpmux-running-tray__list .acpmux-summary-agent__state").count()).toBeGreaterThan(0); | |
| expect( | |
| await page.locator(".acpmux-running-tray__list .acpmux-agent-line").evaluateAll((rows) => | |
| rows.every((row) => Boolean(row.querySelector<HTMLElement>(".acpmux-summary-agent__state")?.textContent?.trim())), | |
| ), | |
| ).toBe(true); |
|
Review (subagent): SHIP at bf97c8a A populated tray list now retains one complete row height, preventing fractional flex shrink from placing Stop outside the scroll viewport; empty lists still collapse. Scoped CSS only, no tolerance changes. |
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (subagent): SHIP at fa9c254\n\nThe final narrow-row adjustment replaces the fractional list floor with a 0.5px upward Stop-slot correction, preserving the shared geometry contract. All seven owned-fleet tray suites are green; no blocking findings. |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Gallery before/after for
States
Pick other states with a red: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: Shipped in:
|
* fix(next): the running tray starts folded to its header, and holds the person's choice per chat Closes #28875 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit b0cef69) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * test(next): open the running tray where a test reads its lines; fixtures for between turns A headed tray starts folded (#28875): the tests that read its lines open it as the person does, by its header, and the motion edges remember chat-a as opened. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 49315c7) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * fix(next): the tray's header takes focus when it folds under a focused line; browser tests open it Review of #28875: a lone line gaining a header folds the list, which goes inert under a focused line or Stop; focus now moves to the header. Reading a chat's choice refreshes its place in the bounded memory. The browser tests that read the tray's lines open it by its header (test/support/openRunningTray.ts); the glyph check uses a one-line variant, the panel's closed play opens the tray. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 0eb37de) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * fix(next): a subagent line's icons and title keep the row's 8px icon gap The kind icon (agent.fork) sat inline against the title with no gap, and in a narrow tray the title started at 22px, flush against the 14px state icon. Both now keep the summary row's 8px icon gap (--acpmux-line-icon-gap). Browser regression in test/subagent-tray-columns.test.ts measures both gaps, wide and narrow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 9543b29) * fix(next): the narrow tray keeps its 8px state-icon gap; tests wait for the fold to settle The narrow layout's title already sat 8px past the state icon (the button's padding is the icon's left); only the kind icon's gap to the title was missing. openRunningTray waits for the fold to let go of its clip, so a focus or a scroll measures the settled tray. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 114d49d) * test(next): a tray folding with motion off moves focus from its line to the header; focus elsewhere stays Fails before the fix: with no motion the fold leaves in the same commit, and focus falls to the body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 2624cd3) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * fix(next): the tray's header takes focus when a motionless fold removes the focused line Review of #28875: with Reduce Motion or the motion switch off the fold leaves in the same commit as the fold, taking the focused line with it, so the layout effect saw the body and moved nothing. Whether focus is in the list is now kept by focus and blur events; a blur to another control clears it, a blur to nothing (removal, inert) does not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 284a554) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * fix(tray): rename the header button ref after the feat-cmux-next merge feat-cmux-next's #29264 added `const [head]` (the header look arm) to SubagentTray; this PR's fold-focus ref was also `head`, so the merged file declared it twice. The ref is now `headButton`. test/subagent-tray.test.tsx 39/39 and subagent-tray-motion 11/11 pass. (cherry picked from commit aca7fb3) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * fix(tray): icon-gap tests and CSS follow #29608, which removed the kind glyph feat-cmux-next's #29608 (f66a92e) took the fork glyph off subagent lines, so this PR's two "8px icon gap" browser tests waited for .acpmux-agent-line__kind-icon and timed out after the merge (review of aca7fb3). They now check the state icon to title gap (8px, wide and narrow) and that no kind icon renders; the kind-icon margin rule that styled nothing is gone. CMUX_BROWSER_TESTS=1 bun test test/subagent-tray-columns.test.ts: 12 pass, 0 fail. (cherry picked from commit 1ab971c) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * perf(agent-pane): skip hidden subagent tray rows when folded (cherry picked from commit b4fbe35) * test(agent-pane): 300 collapsed agents construct no hidden lines (cherry picked from commit 691560b) * test(tray): avoid 300 hidden row reads across repeated collapsed renders (cherry picked from commit d47573e) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * perf(agent-pane): index 300 siblings without copying arrays (cherry picked from commit 4a9f422) Agent-Session: https://cmux.com/deeplink/agent?id=aid-08e2cc96b9b79e73b8e4 * test(agent-pane): keep 300 sibling rows and cycle fallback (cherry picked from commit 01a768b) * fix(agent-pane): every part over the composer on the box's edges and radius, one gap; the tray's chevron at 22 Leo, 2026-10-30: "the stupid right indent misalignemnt". ui-think-tank's rule, one column, one gap, nothing removed: - The running tray's header ended in an empty 24px Stop slot, so its chevron sat about 46px from the right (43 in a narrow tray) against Send at 22. The header has no Stop slot now; every row ends 12px in with a 20px mark box, so the chevron (header, line, View all) centres 22px from the right, and a line's Stop (or its empty column) centres 42px from the right. Narrow rows keep the same columns. - At composer columns under 298px the box and its quiet row reach 8px past the column; every stack part now follows (--acpmux-stack-start/end on the dock write the same step out, since the composer's container query cannot reach its siblings). - The tray (10px), the opened pull requests and the recap's card (12px) take the box's radius token, now defined on the dock as well. - The recap, the legacy PR bars, the host's line and the agents pill drop their own bottom padding and take the stack's edges; the PR fallback row and the in-transcript tray take --cv-inset-end on the right; one dock rule gives the stack token between parts. The recap's card joins the glass like the tray. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639 * fix(tray): align fixed status and action tracks with the composer Agent-Session: https://cmux.com/deeplink/agent?id=aid-dcb1d77e7d3efe26a42d * fix(tray): keep workflow progress out of the status track Agent-Session: https://cmux.com/deeplink/agent?id=aid-dcb1d77e7d3efe26a42d * fix(tray): keep action columns inside the narrowest panes Agent-Session: https://cmux.com/deeplink/agent?id=aid-dcb1d77e7d3efe26a42d * fix(web): center tray controls across row heights Agent-Session: https://cmux.com/deeplink/agent?id=aid-dcb1d77e7d3efe26a42d --------- Co-authored-by: Austin Wang <38676809+austinywang@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-dcb1d77e7d3efe26a42d
fa9c254 to
ad92b85
Compare
|
Review (subagent): BLOCK at ee5eea9 [blocking] The base merge changes SubagentTray to context-menu-only Stop and removes the row Stop buttons, but this PR still requires one row Stop in subagent-tray-composer-geometry.test.ts:86 and clicks the removed process Stop button in subagent-tray.test.tsx:685 (also visible Stop assertions at lines 823–825). Those tests cannot pass with the merged renderer. Resolve the row-control contract and rerun the tray suites before landing. |
|
Review (subagent): BLOCK at 8ee9ee0 [blocking] Restored row Stop buttons fix the prior geometry/unit mismatch, but the merged-base trailing suite still requires zero Stop buttons (subagent-tray-trailing.test.ts:96) and asserts the empty slot hits the row button. The row-menu gallery also throws if any row Stop exists (SubagentTray.gallery.ts:470–471). Reconcile these assertions with the requested visible row Stop plus retained context menu, then rerun the tray suites. No runtime defect found in the restored after props. |
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="webviews/src/agent-session/acpmux/subagents/SubagentTray.tsx">
<violation number="1" location="webviews/src/agent-session/acpmux/subagents/SubagentTray.tsx:484">
P2: The row Stop and the context-menu Stop now keep separate state. Clicking the row button leaves the menu's Stop enabled and unmarked, and a failed row stop does not switch the menu item to the failed label. Route both through the same `stops` state, or drop one of the two entry points.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| // A narrow tray's second line is its time and controls: the stats wrap under the title. | ||
| progressAt={row === "below" || narrow ? "below" : "meta"} | ||
| onOpen={() => onOpen(item.agent.id)} | ||
| after={ |
There was a problem hiding this comment.
P2: The row Stop and the context-menu Stop now keep separate state. Clicking the row button leaves the menu's Stop enabled and unmarked, and a failed row stop does not switch the menu item to the failed label. Route both through the same stops state, or drop one of the two entry points.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/agent-session/acpmux/subagents/SubagentTray.tsx, line 484:
<comment>The row Stop and the context-menu Stop now keep separate state. Clicking the row button leaves the menu's Stop enabled and unmarked, and a failed row stop does not switch the menu item to the failed label. Route both through the same `stops` state, or drop one of the two entry points.</comment>
<file context>
@@ -480,6 +481,11 @@ export const SubagentTray = memo(function SubagentTray({
// A narrow tray's second line is its time and controls: the stats wrap under the title.
progressAt={row === "below" || narrow ? "below" : "meta"}
onOpen={() => onOpen(item.agent.id)}
+ after={
+ stop &&
+ item.agent.state === "running" &&
</file context>
|
Review (subagent): BLOCK at 29f887a [blocking] The trailing test still maps all rows and requires the hit at the Stop-slot center to belong to the row button (subagent-tray-trailing.test.ts:117–127). A restored Stop is a sibling outside that button, so running rows necessarily fail. Select the Stop button as the expected hit target when present, otherwise the row button, keeping the all-row reachability assertion. The previous zero-Stop and gallery conflicts are resolved. |
|
Review (subagent): SHIP at 7a5afbb The previous blocking test/render mismatch is resolved: populated slots require their Stop button as the hit target, while empty slots require the row button. The all-row reachability assertion and geometry tolerances remain intact. No further blocking findings; finished webview checks remain required before landing. |
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="webviews/src/agent-session/acpmux/subagents/SubagentTray.tsx">
<violation number="1" location="webviews/src/agent-session/acpmux/subagents/SubagentTray.tsx:9">
P3: Use the plural verb for this compound subject: change `has` to `have` and remove the unnecessary commas around `and` for readability.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| // its line's context menu (a right-click, or Shift-F10 and the menu key on the focused line), never | ||
| // a Stop on every line: a control repeated down the rows is a block on Leo's visual rule (#28533's | ||
| // review, on a tray with a Stop per line). An agent another one spawned sits right under it. | ||
| // (processTerminal.ts), a chat. A running subagent, and a command the registry lists, has a Stop |
There was a problem hiding this comment.
P3: Use the plural verb for this compound subject: change has to have and remove the unnecessary commas around and for readability.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/agent-session/acpmux/subagents/SubagentTray.tsx, line 9:
<comment>Use the plural verb for this compound subject: change `has` to `have` and remove the unnecessary commas around `and` for readability.</comment>
<file context>
@@ -6,10 +6,9 @@
-// its line's context menu (a right-click, or Shift-F10 and the menu key on the focused line), never
-// a Stop on every line: a control repeated down the rows is a block on Leo's visual rule (#28533's
-// review, on a tray with a Stop per line). An agent another one spawned sits right under it.
+// (processTerminal.ts), a chat. A running subagent, and a command the registry lists, has a Stop
+// square in the fixed row track and the same action in its context menu (a right-click, or Shift-F10
+// and the menu key on the focused line). An agent another one spawned sits right under it.
</file context>
| // (processTerminal.ts), a chat. A running subagent, and a command the registry lists, has a Stop | |
| // (processTerminal.ts), a chat. A running subagent and a command the registry lists have a Stop |
|
Review (subagent): SHIP at 22f197f Reviewed the two-line test cleanup: removing blanket animation.finish calls avoids trying to finish infinite animations, and the shared tray helper still settles finite fold motion. Previous blocking hit-target mismatch remains fixed. No blocking findings. The reported owned-fleet step 3e515a passed all seven tray suites at this head; required webview verdicts still apply. |
Fixes #27908. Fixes #28875.
Takes back #29877: re-land tray alignment after the base restore.
This fresh PR re-lands the tray alignment on base after #29877 restored the pre-alignment tree; it carries the verified geometry and release-highlight fixes from #29819.
The running tray above the composer keeps its duration, status, Stop and disclosure on shared fixed tracks, including an empty Stop slot for ended rows. Its controls align with the default composer's Stop and microphone, using equal gaps and matching insets. Workflow progress stays beside the title so every status word starts at the same x.
Leo, 2026-10-31:
Earlier: “align this right side's chevrons”, “IT'S SO MISALIGNED”.
Carries the needed work from #28587, #29030, #27930 and #29250, preserving commit authorship. #27930's folding is superseded by #29030's per-chat memory, and its Stop-before-chevron layout already landed through #29264. The newer one-glyph rows remain. The tray starts folded, retains the person's per-chat choice, and constructs no hidden rows after its fold completes.
Takes back #29276: this latest request explicitly calls for aligned status words, so the tray shows its status in a fixed column; other row consumers retain their current presentation.
Design: running tray, updated in leo-workspace #2038.
subagent-tray.test.tsxobservable name-read regression carried from #29250Validation: fleet browser geometry and web compilation will run on this fresh head before merge. The geometry test compares Running, Done and Cancelled rows against the composer with a 0.5px tolerance. Required webview shards must complete before merge.
Risk: contained tray layout and folding. Existing fold focus, per-chat memory and hidden-row behavior retain regression coverage. The fold animation owns its existing cleanup; no new timers or observers.
No capture: geometry is checked in Chromium; screenshots are not a landing gate.
Agent session: agent session
🤖 Generated with Claude Code