Skip to content

cmux NEXT: expanding a tool call or thought animates and never moves your view - #23093

Merged
teamleaderleo merged 4 commits into
feat-cmux-nextfrom
chat/collapse-anchor-anim
Oct 21, 2026
Merged

teamleaderleo merged 4 commits into
feat-cmux-nextfrom
chat/collapse-anchor-anim

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Opening or closing anything in the agent chat's transcript no longer moves your view. The line you clicked (a tool group, a tool, command or MCP call, a settled run, a folded thought, a turn's "Worked for") stays on the pixel you clicked it at while what it opens lays out. Before, a chat following its reply jumped to the new latest row as soon as something opened, so the line you clicked shot up by everything it revealed.

Every one of those collapsibles now opens and closes in one motion: the body's height and opacity, easing out, with the chevron turning on the same duration. Under Reduce Motion, or with the app's animations off, it opens and closes at once.

How it holds still. A capture-phase click on a disclosure line (foldAnchor.ts) records where the line is drawn. Until its fold has played (plus 150 ms for the last measure and the rows "Worked for" inserts), each placement pass in VirtualTranscript puts that line back by moving the offset. It does that instead of following the latest row or keeping the top row. When you're following the reply and what opened pushes the latest row out of view, the view stops following (Jump to latest shows), so the reply streaming on doesn't pull you away. There's one case where the line can still move: closing something at the very end of the transcript. There's nothing below to fill the view, so the browser clamps the offset and the rows above come down by what closed, as in any scroller.

The motion. useFold (fold.ts) keeps a closing body drawn until it has slid away. If you reverse a fold midway, it starts from where it is drawn. It reads --cv-fold-duration, which conversation.css sets from the host's move duration (--agent-motion-move, AgentPaneTheme.swift: about 190 ms, and 0 under Reduce Motion or with animation off), with 180 ms when there's no host. The chevron (.cv-rotor) turns on the same token. The newtab-resize-anim lane owns shared duration tokens but hasn't published any yet. I messaged it, and this is the single alias for it to repoint. ThoughtRow drops its own 200 ms height-only animation for the shared fold. Only the reader's toggle plays it; the automatic fold still snaps.

The rows "Worked for" opens are whole virtual rows. They get the transcript's existing row entrance, not a height fold.

Changelog

  • Changed: Opening or closing a tool call, a thought or "Worked for" in agent chat animates and keeps the clicked line where it was, instead of jumping the view.

Observed / Not run

Ran locally (bun 1.4.2, webviews/):

  • bun test test/transcript-fold-anchor.test.tsx: red on base 7a4b464 (the "Worked for" line moved from 453.5 px to 235.5 px down the view), green on this head (2 pass). The test is committed first (e9418c6).
  • bun test test/transcript-fold-motion.test.tsx: 13 pass. Each collapsible plays height and opacity over the token, keeps a closing body until it finishes, and doesn't animate under Reduce Motion, with data-agent-motion="off", or with a 0 ms token. A reversed fold starts from its drawn height, and the CSS ties the token to --agent-motion-move and the chevron.
  • ThoughtRow.test.tsx (20 pass), 21 other transcript, find and tool-row jsdom suites (109 pass, 0 fail) and gallery-coverage.test.ts pass.
  • bun run check: formatting, layers and type check pass. It exits 1 on one lint warning, jsx-a11y(prefer-tag-over-role) in src/pages/history/HistoryPage.tsx:177. This PR doesn't touch that file, and the warning is the same on base 7f3a43a.

Not run locally (browser tests run only in CI here):

  • test/transcript-fold-anchor-browser.test.ts (Chromium). It checks that the clicked line moves at most 1 px on every frame of the fold, while following a streaming reply and for "Worked for", and that no fold plays under Reduce Motion.
  • The new gallery play agent-pane.transcript / fold-holds-clicked-line. At the latest row it opens Worked for, then a command, then closes it, and fails if any line moved.
  • No app build: the change is webview-only.

Agent session: cosmic-gray

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Opening or closing a tool call, thought, "Worked for", or any other collapsible in agent chat now animates and keeps the clicked line exactly where it was, instead of jumping the view.

  • Every collapsible opens and closes with one shared fold: height and opacity over --cv-fold-duration (the host's move duration, ~190 ms), with the chevron turning on the same token.
  • Under Reduce Motion or with the pane's animations off, everything opens and closes instantly.
  • When the opened content pushes the streaming reply out of view, the view stops following (Jump to latest appears); the line still holds until the fold settles.
  • A closing fold stays pinned shut until its body is removed, so the rows below don't jump the frame before React commits.
  • One exception: closing something at the very end of the transcript can still shift the view, as the browser clamps the scroll offset with nothing below to fill it.

Written for commit 5f7be0d. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits October 20, 2026 23:50
…the clicked line (red)

Followed to the latest row, opening the last turn's "Worked for" puts the view at the new latest
row, so the line the reader clicked jumps up by everything it opened (453.5px -> 235.5px here).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d1f-ca00-7e31-b882-4d3c03033ee2&host=cosmic-gray
…your view

Every transcript collapsible (tool groups, tool, command and MCP rows, a settled run, a folded
thought) opens and closes in one fold: height and opacity over --cv-fold-duration (the host's
move duration, ~190ms, 0 under Reduce Motion or with animation off), easing out, the chevron
turning on the same token (fold.ts). The clicked line stays on its pixel while its fold plays:
VirtualTranscript holds it (foldAnchor.ts), following neither the latest row nor the top row, and
stops following when what opened pushed the latest row out of view. Covers "Worked for" too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d1f-ca00-7e31-b882-4d3c03033ee2&host=cosmic-gray
@cursor

cursor Bot commented Oct 21, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot 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.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 5f7be0d: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr23093 -f ref=chat/collapse-anchor-anim -f platform=macos -f backend_mode=local

Unclear: web / react-apps-check failed: no known signature; failed step: Check webview test shards.

CI failed on 5f7be0d384 (run 39561724754 attempt 1): 4 code, 1 unknown.

Job Verdict Why
web / react-apps-check (4) code a web test failed
web / react-apps-check (1) code a web test failed
web / react-apps-check (3) code a web test failed
web / react-apps-check (2) code a web test failed
web / react-apps-check unknown no known signature; failed step: Check webview test shards

Failures:

  • seen on other PRs composer-suggested-prompt.test.tsx nothing is suggested from another folder, another worktree, a merged PR, an old chat or a busy one: failed (job)
  • seen on other PRs composer-suggested-prompt.test.tsx a folder with a trailing slash is the same checkout: failed (job)
  • seen on other PRs composer-suggested-prompt.test.tsx a chat that knows its branch takes no PR from another branch: failed (job)
  • seen on other PRs composer-suggested-prompt.test.tsx a chat with turns gets no suggestion: failed (job)
  • seen on other PRs composer-suggested-prompt.test.tsx Tab writes the suggestion without sending; Shift-Tab does not take it; Esc puts it away: failed (job)
  • seen on other PRs composer-suggested-prompt.test.tsx the chat folder's PR from the header's gh read is suggested when no session reports one: failed (job)
  • seen on other PRs quiet-access-chip.test.ts chromium: Full access draws in the model chip's color: failed (job)
  • seen on other PRs quiet-access-chip.test.ts webkit: Full access draws in the model chip's color: failed (job)
  • seen on other PRs agent-pane-ctrl-b-background.test.ts with no running call, Ctrl-B stays the composer's and asks nothing: failed (job)
  • seen on other PRs agent-pane-ctrl-b-background.test.ts a Codex chat shows no hint and keeps Ctrl-B: failed (job)
  • ... 12 more in the job logs
Matched log lines
web / react-apps-check (4): (fail) nothing is suggested from another folder, another worktree, a merged PR, an old chat or a busy one [51.57ms]
web / react-apps-check (1): (fail) with no running call, Ctrl-B stays the composer's and asks nothing [1013.27ms]
web / react-apps-check (3): (fail) @ then letters lists the chat's matching files and Return writes the path [2167.48ms]
web / react-apps-check (2): (fail) queued and steering prompts > the queue takes its own place in the stack: nothing is cut off or drawn over [1300.85ms]

Not re-run automatically: web / react-apps-check (4), web / react-apps-check (1), web / react-apps-check (3), web / react-apps-check (2), web / react-apps-check are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

red: web / Web status; NEW: green on the base 0f6199c; do not merge until green; see lane-rules
red: web / react-apps-check; no finished base run on 0f6199c to compare; do not merge until green; see lane-rules
red: web / react-apps-check (1); no finished base run on 0f6199c to compare; do not merge until green; see lane-rules
red: web / react-apps-check (2); no finished base run on 0f6199c to compare; do not merge until green; see lane-rules
red: web / react-apps-check (3); no finished base run on 0f6199c to compare; do not merge until green; see lane-rules
red: web / react-apps-check (4); no finished base run on 0f6199c to compare; do not merge until green; see lane-rules

CI fast guards failed on 5f7be0d384 (https://github.com/manaflow-ai/cmux/actions/runs/39561724754). It does not block the merge; a red guard merged into main breaks it for every open PR.
The log named no failed step; see the run.

Agents: python3 scripts/ci/guard_attribution.py fix applies the mechanical fixes locally.

Tour of 5f7be0d384 (run): no media. The tour did not run: only webview code changed (16 path(s)), which the gallery advisory run checks in Linux Chromium on the pull request (its artifact holds any captures); add the media-tour-mac label to tour it on a Mac.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by projects-62 on cosmic-gray · session

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by projects-62 on cosmic-gray · session

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-oyt23 created for this PR by the cmux coordinator.

@blacksmith-sh

blacksmith-sh Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Found 18 test failures on Blacksmith runners:

Failures

Test View Logs
test/agent-pane-ctrl-b-background.test.ts/agent-pane-ctrl-b-background.test View Logs
test/agent-pane-ctrl-b-background.test.ts/agent-pane-ctrl-b-background.test View Logs
test/agent-pane-peer-chat.test.ts/agent-pane-peer-chat.test View Logs
test/agent-pane-peer-chat.test.ts/agent-pane-peer-chat.test View Logs
test/agent-pane-queue-steer.test.ts/agent-pane-queue-steer.test View Logs
test/agent-pane-queue-steer.test.ts/agent-pane-queue-steer.test View Logs
test/agent-pane-working-counts.test.ts/agent-pane-working-counts.test View Logs
test/agent-pane-working-counts.test.ts/agent-pane-working-counts.test View Logs
test/composer-history.test.ts/composer-history.test View Logs
test/composer-history.test.ts/composer-history.test View Logs

...and 8 more test failures. View all on Blacksmith

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (claude-review-subagent): BLOCK at 66f967e

Blocking

  1. webviews/src/agent-session/acpmux/conversation/fold.ts:675-688: every animated close shows a one-frame pop at its end. The close animation has no fill, so when it finishes the box goes straight back to its natural height and opacity: 1. The body is only removed when React commits setClosing(false) from onfinish. A native finish event gives a DefaultLane update, and that commit lands after the frame the event fires in has painted. In that frame, the body is drawn at full height (or, if the row's ResizeObserver flushSync picks up the update, its row is still placed at the full measured height, leaving a gap). The rows below jump by the body's height for a frame and then snap back. I checked this with a standalone page in Playwright Chromium and WebKit: a height and opacity animation to 0 with removal scheduled via MessageChannel from onfinish. The requestAnimationFrame of the finish frame sees the element still connected at h: 200, opacity: 1 in both engines. The old ThoughtRow code had the same pattern, but this PR applies it to every collapsible (tool groups, tool runs, tool rows, command rows, MCP rows, thoughts), which is the motion this PR is about. Fix: play the close with fill: "forwards" (the reopen path already cancels running), or set node.style.height = "0px" and opacity = "0" in onfinish before setClosing(false) and clear them when it opens. Add a jsdom assertion for it (closing options carry fill: "forwards", or the box stays at 0 after finish() until it unmounts).

Notes (non-blocking)

  • fold.ts:673: the opening animates to the scrollHeight measured when it opens. Content that loads during the 190ms (highlighted code, EditDiff hunks) jumps when the fold finishes. This is minor.
  • .cv-fold { display: flow-root } keeps the bodies' margins (.cv-shell and .cv-tool-output-card have margin: 4px 0 8px) inside the row, where they could collapse out before. A row ending in an opened body is now about 8px taller. This looks intended, but check it in the gallery.
  • The anchor and hold logic in App.tsx (the folding placement branch, layoutDriven gated on foldAnchor, capture-phase click hold, release on wheel/touch/non-activating keys) reads correctly. I found no regressions for streaming follow, ended turns, or Find. Find's reveal hold (at least 600ms, tracking the match each frame) outlasts the fold. Virtualized rows re-measure through the ResizeObserver every frame of the fold, so no row version change is needed. No new strings, no Swift, no literal colors. Reduce Motion, data-agent-motion="off" and a 0ms token are all instant and tested.

Ran (scratch worktree at the head)

  • bun test test/transcript-fold-motion.test.tsx test/transcript-fold-anchor.test.tsx src/agent-session/acpmux/conversation/ThoughtRow.test.tsx: 35 pass, 0 fail.
  • bun test for TurnRows, agent-pane-mcp-tool-rows, tool-row-relative-path, transcript-density, transcript-live-runs and transcript-output-copy: 33 pass, 0 fail.
  • bun test for transcript-disclosure, transcript-find-follow, transcript-fold-anchor, transcript-hidden-follow, transcript-follow, chat-find and agent-pane-follow-live: 6 pass, 3 skipped (browser lane), 0 fail.
  • bunx tsc --noEmit -p .: clean.
  • transcript-fold-anchor-browser.test.ts did not run: the Vite warm-up timed out at 100s with the host at load 99. It is left to CI.

teamleaderleo and others added 2 commits October 21, 2026 00:21
…se-anchor-anim

# Conflicts:
#	webviews/src/agent-session/acpmux/App.tsx
The close animation has no fill, so when it ended the .cv-fold box went
back to full height and opacity for the frame before React committed
setClosing(false), and the rows below jumped. onfinish now pins the box
shut (height and opacity 0, clipped) before it asks React to remove the
body, and any later fold clears the pin first, so a box reopened in the
same frame opens from its own size. An open still lets go of the height
it measured, so content that loaded meanwhile shows at its own height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d1f-ca00-7e31-b882-4d3c03033ee2&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (claude-review-subagent): SHIP at 5f7be0d

Independent review of the whole PR diff against its merge base with feat-cmux-next (0f6199c), with most attention on the fix for the earlier BLOCK (5f7be0d).

Blocking: none.

The close pop (earlier BLOCK) is fixed

  • onfinish for a close now pins .cv-fold shut (height 0, opacity 0, overflow hidden) before it calls setClosing(false). In the frame after the fill-less animation lets go and before React's commit, the box stays at 0, so nothing flashes. The pinned box is the .cv-fold that unmounts when present goes false, so none of those inline styles outlive it.
  • Reopening in the same frame the close ends: the layout effect calls pin(node, undefined) first. running.current is already cleared, so the open starts from 0/0 and grows to scrollHeight, then clears overflow. The new test (same box, starts at 0px, no inline styles left) covers this.
  • Reopening mid-close: turning reads the animated rect height and computed opacity, cancels the old animation (its onfinish doesn't fire, and its identity guard protects it anyway), and animates from there.
  • Reduce Motion, data-agent-motion="off" or a 0 ms token: closing is never set at render, or the layout effect clears it synchronously before paint. Either way the pin is cleared first, so no overflow:hidden is left behind.
  • Find opening a closing fold: tool, command, MCP, group and run folds take the turning path. A thought snaps (toggled was already reset after the close's layout effect) and its pin is cleared. Find's reveal hold keeps the match in view: the match sits below the fold's fixed top, so the fold growing doesn't move it.

Non-blocking

  1. A cancelled fold never settles. applyAgentTheme (shared/theme.ts:87) calls cancel() on every document animation when a motion-off theme arrives. A close caught in flight then never gets onfinish, so closing stays true and running.current stays set. The body stays drawn under a closed chevron, with aria-expanded="false", until the reader toggles it again (that toggle recovers it). An open caught in flight keeps an inline overflow:hidden. This needs the setting changed within about 190 ms of a click, and the old ThoughtRow had the same gap. An animation.oncancel that settles the same way when running.current === animation would close it.
  2. An expired foldAnchor is only cleared on the next placement pass. onScroll's !foldAnchor.current treats it as live until then. It's benign in practice: the next layout pass clears it before the scroll events it causes, and a click already makes scrolls non-programmatic for READER_SCROLL_MS. Checking until in onScroll too would make that explicit.

Also checked

  • App.tsx hold: the capture-phase click hold runs before the row's handler and finishes any glide on .acpmux-thread (own animations only, not the subtree). Placement passes during the hold only put the clicked line back. Following stops only when the opened body pushes the latest row out of view. Wheel, touch and non-Enter/Space keys release the hold, and keyboard activation still holds. Listeners are removed on cleanup.
  • Merge bf2f27b kept base's comment line (wheelPassThrough). No code change.
  • Memo/version staleness: fold state is local to each row component. Row height changes reach VirtualTranscript through its ResizeObserver, and a remounted row re-measures. ToolRow diffs files while present, so a closing edit keeps its body.
  • --cv-fold-duration resolves on :root from --agent-motion-move, which applyAgentTheme sets on documentElement (composerStates.css default 190ms). The chevron transition uses the same token, only under no-preference.
  • No literal colors in the diff. No new user-facing strings (tools.more only moved; the gallery note is dev-only). REVIEW.md: tests assert the new behavior and would fail without the fix. foldMotion as a test seam follows the existing thoughtLayout pattern.

CI (glaeda status, head 5f7be0d): the fold suites pass in CI: transcript-fold-motion, transcript-fold-anchor, transcript-fold-anchor-browser and ThoughtRow.test. web / react-apps-check shards 1–3 fail on the same tests on #23136, an unrelated revert on the same base: the typecheck exit from the warning in sidebar-rail-css.test.tsx, Ctrl-B, the SSH running turn, ↑/↓ prompt history, the @ picker, queue stack and composer strip. Shard 4 fails on composer-suggested-prompt and the Full access chip color. The diff doesn't touch either, but #23136's shard 4 was still running, so it isn't confirmed on base yet.

Not run: no local tsc or bun test (blocked on this host by policy), and no live app or gallery play of fold-holds-clicked-line.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Red checks on 5f7be0d are base reds, not this PR's: every failing test in web / react-apps-check (1)-(4) also fails on unrelated #23131 (run 39561886342), e.g. composer history, @-picker, Ctrl-B hint, suggested prompt, Full access chip colour, location strip, queue stack. The typecheck step exits 1 on 0 errors / 1 base warning. The fold tests this PR adds pass. Merging after review SHIP at this head.

@teamleaderleo
teamleaderleo merged commit 8ae8fd5 into feat-cmux-next Oct 21, 2026
@teamleaderleo
teamleaderleo deleted the chat/collapse-anchor-anim branch October 21, 2026 07:41
teamleaderleo added a commit that referenced this pull request Oct 21, 2026
…ld timer

check:motion-scale was in webviews' `bun run check` but not in ci-web's
warn-mode loop (test_cmux_next_checks_workflow). foldAnchor's
FOLD_SETTLE_MS (from #23093) is a hold timer after a fold, not a
transition, so the motion-scale scan allows it by name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray
@github-actions

Copy link
Copy Markdown
Contributor

Shipped in:

teamleaderleo added a commit that referenced this pull request Oct 21, 2026
…are one short scale (#23092)

* test(newtab): a live resize reads no list row on its frames

A live window resize calls the New Tab lists' ResizeObserver every frame,
and listMotion read every row's place there (a forced layout per frame).
This pins that the rows are read once, after the size holds still.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* fix(newtab): the page lays itself out in CSS while the pane resizes

- The field sizes itself (field-sizing: content); the JS fit and its
  ResizeObserver run only in an engine without field-sizing.
- The top padding is one continuous curve in the pane's height, so the
  composer no longer jumps 55px when a resize crosses 480px tall.
- listMotion's ResizeObserver reads no row on a live resize's frames; the
  places are read once the size holds still for 120ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* feat(motion): one motion duration scale both the app and the webviews read

schemas/motion-scale/motion-scale.json holds the scale (quick 80ms, micro
120ms, standard 180ms, large 240ms, ease-out on enter).
scripts/cmux-next/gen-motion-scale.py writes its Swift (MotionScale),
CSS (--cmux-motion-*) and TypeScript (MOTION_MS) copies; CI and the
webviews check run it with --check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* Motion: put Swift and webview durations on the 80/120/180/240 scale

Every fade, spring and CSS transition now reads the shared motion scale
(schemas/motion-scale/motion-scale.json) instead of its own literal:
MotionTunables fades and springs on the Swift side, the host CSS tokens,
page literals, Tailwind classes and JS motion constants on the webview side.
Springs are critically damped and at rest within the standard step.
A static scan (webviews/test/motion-scale.test.ts) fails on any new
off-scale duration; MotionScaleTests pins the Swift side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* test(webviews): New Tab page follows a live window resize

Sweeps the New Tab page's iframe from 1100x760 to 480x400 and back, one
size per frame, and fails on a composer jump, an inline field height, a
missed frame budget or ResizeObserver work per frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* Motion: pane close test follows the faster split spring

At response 0.23 s the close is about 0.41 of its travel at 50 ms (it was
0.32 at 0.28 s), so the early-progress window moves to 0.3..0.55.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* New Tab: scroll a capped self-sizing field to the caret in WebKit

WebKit sizes the field with field-sizing but leaves a draft past the cap
scrolled where it was, so typing at the end hid the caret
(composer-draft-wrap "webkit: the New Tab field ... grows to its cap").
On a draft change with the caret at the end, scroll it into view; a
resize still runs no script.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* Thread minimap test: per-frame bound fits the 180ms shift glide

SHIFT_MS moved from 200 to the scale's standard 180ms, so the fastest
frame of the glide is ~40.8px, just over the old 40px bound. 48px still
fails a one-frame jump (~150px).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* Motion scale: run its check in ci-web's warn branch; mark the fold hold timer

check:motion-scale was in webviews' `bun run check` but not in ci-web's
warn-mode loop (test_cmux_next_checks_workflow). foldAnchor's
FOLD_SETTLE_MS (from #23093) is a hold timer after a fold, not a
transition, so the motion-scale scan allows it by name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* New Tab lists and motion scale: review fixes

- listMotion: a row arriving resizes the list itself; the observer then
  reports the size the effect just read. That no longer marks the places
  stale, so a second change right after (two tabs closed in a row) still
  animates. Test: "the list's own size change from a row arriving leaves
  the next change animated".
- motion-scale test: compare MOTION_MS as entries (TS2769 on the readonly
  literal type in `bun run typecheck`).
- RevealedMarkdown: the fresh span outlives the 180ms default-speed fade
  (standard step), so a reveal's tail no longer pops.
- Reduce Motion crossfade in the webviews follows Swift's (quick, 80ms).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* Motion scale test: type the generated-copy comparison as [string, number] pairs

Object.entries(MOTION_MS) is typed with the literal step values, so toEqual
refused the JSON's plain numbers (TS2769 in the webviews type check).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

* test(newtab): mark the resize tests' fixed waits and frame read for base's new ratchets

check:fixed-waits (#23365) and check-frame-reads joined the base's web lint after
this branch's tests were written; each wait and the sweep's frame read says why.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d26-7362-7a82-8d75-ed7d25069378&host=cosmic-gray

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant