Repository navigation
agent pane: older turns fade in as they load above the reader (cx-2lv1k) - #20633
Conversation
…l-up (cx-2lv1k) Red: nothing calls loadOlder, so scrolling up never reaches the first turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pane opened a chat on its newest 400 records and never asked for more: nothing called loadOlder, and it read acpmux's paging flag as `more` where acpmux sends `hasMore` (so missed-event catch-up also stopped after one page). Now the transcript asks for the page before its oldest record whenever the view is within two viewports of it, one request at a time with a short backoff after a failure, and attach's hasMore says when the start is already loaded. The reader's row holds its place as pages land, at offset 0 too, and when a page completes a turn cut at its edge. Each older page holds whole turns (the records before its first prompt wait for the next page) and folds on its own above the held rows, so a page costs the same however much history is loaded: re-folding every held event cost 105 ms a page at 45k events and grew without bound. Rows a rebuild makes again unchanged keep their objects, so drawn heights and memoized rows survive it. Opening asks for at most 128 KiB and each older page 256 KiB (maxBytes), so a remote session's open stays small however large its tool output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Red: the transcript scroller has no mask, so rows are cut at the header and above the composer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Leo 10-14: rows were hard-cut under the header and above the composer. The scroller now fades in under its top edge once it has left the start, and out above the composer while more lies below (New Tab's soft edge, #19791). A mask paints nothing, so rows dissolve into the pane's background or the wallpaper and nothing moves; Reduce Transparency keeps plain edges. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An older page folded while the newer rows were still held, so a turn's "Worked for" counted from the newest prompt and showed 0s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38543723901
An older page folds below the held rows, so a turn ending there now totals only the rows before them: its "Worked for" no longer counts from the newest prompt. Review follow-ups: a steer opens no turn, so a page never splits at one; a fork only an older page holds is kept; a rebuild keeps an earlier row object only when its plain fields match too; and a page in flight for the session before no longer blocks the next session's first page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bottom fade switched on for a frame on each streamed chunk (24 times in a 30-chunk reply) while the view was following it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bottom fade read the offset the last scroll event left, so each streamed chunk faded the line being written for a frame. Both edges now read what the frame draws (the following state and its offset), and Find in Chat's bar keeps the top edge plain so it stays in full ink. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- regenerated schemas/defaults/cmux-next.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38545286296
…replay/older-rows-fade
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rows from a page of older history wait at 0.35 opacity out of view and fade to full ink over the shared fade-in token the first time they intersect the transcript view, once. Opened, live and already-seen rows never take it; Reduce Motion draws them in full ink at once. Opacity only, so anchoring and measured heights are untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…replay/older-rows-fade # Conflicts: # webviews/src/agent-session/acpmux/direct.ts
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…replay/older-rows-fade
This comment has been minimized.
This comment has been minimized.
|
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)
Unclear: CI failed on
Not re-run automatically: Written by red: web / Web status; do not merge until green; see lane-rules
Agents: |
|
|
Gallery163 states changed: agent-pane.artifact-panel/html, agent-pane.edited-files/fourteen-files, agent-pane.edited-files-settings/changed, agent-pane.edited-files-settings/defaults, agent-pane.transcript/shell-grouped-commands, ... · 79 play checks failed Diff page and renders (the run's 157 more on the diff page. Live preview (follows this branch; start it with
Play checks failed (0 px anchor movement, 0 layout shift, no frame over 33 ms unless the entry gives a reason):
385 nondeterministic states differed from a second render of the same head (a clock or fixture leak) and are not counted as changes. |
|
cmux-next tour of The tour job failed before the tour ran (build or setup); the run log has the output. The tour produced no media. Tours are data in |
…replay/older-rows-fade
- vp fmt webviews/src/pages/home-channels/cloudHome.ts - cargo fmt in Native/OptChat/optchat-chief Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38651737990
|
Visual preview of 4b6b804: in the maintainers' private review feed. |
* test(transcript): stream the chat-column replies on a loaded page (red) Base flake on loaded CI runners (#20644, #20633): "keeps the view at its end" saw the text sink a few pixels, and "scrolls smoothly" saw a 24px step. The streaming tests now run with Chromium's CPU throttled 4x, the load the runners had, so every run reproduces the first. A smoothness step is measured over the time its frame took, so a loaded page that paints fewer frames is not read as a jump. red: bun test test/agent-pane-chat-column.test.ts (browser lane, builder) -> 'keeps the view at its end' fails 2/2 at movedDown Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(transcript): a followed reply moves only by what is drawn Two causes of the chat-column flake on loaded runners: - A streaming reply's text draws after the version that holds it, so the row was placed by an estimate of the new version (a line or more ahead of the text), then by its drawn height a frame later: the view scrolled ahead and back at every chunk. A row now keeps its last drawn height until its new version is drawn; growth comes from what is drawn. - The queue cleared --acpmux-queue-space at every change before setting it again; the transcript's layout pass could run between the two, read the taller view and scroll the followed reply back by a row. The space now stays while the list redraws and goes with the list. red: bun test test/agent-pane-chat-column.test.ts (loaded, builder) -> 'keeps the view at its end' fails 2/2 green: same command -> 7 pass, 0 fail, 3/3 runs; related transcript and queue browser tests 31/31 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(transcript): every scroll step of a streamed reply glides, at any frame rate From the #20697 review: dividing a step by its frame's time let a snap through on a slow frame, and a fixed px-per-painted-frame bound depends on frame timing (a loaded frame holds two lines of growth). The check now reads, per frame, how far the followed row moved under the thread's glide and the glides the thread started since the frame before: a move the glides do not account for is a step drawn at once. Checked: with glide() disabled the test fails at snapped(); with it, the file passes 8/8 three times on a 4x-throttled page (builder). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(transcript): a drawn height places its row until the next version is drawn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(transcript): the live-resize chat column runs on a loaded page (red) The #20467 test 'a pane resized at every frame keeps its last line at the bottom' failed on a loaded CI runner (#20697 react-apps-check, https://github.com/manaflow-ai/cmux/actions/runs/38614942014/job/116065309559: one frame with the last line 341px off). The chat-column tests now all run at 6x CPU throttle. red: bun test test/agent-pane-chat-column.test.ts -t 'pane resized' (builder) -> 16 of 16 fail Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(transcript): a frame is what the page painted, not a resize read before its paint The chat-column watcher samples each frame in a task after its animation frame. On a loaded page a viewport resize can land between that frame and the sample: the read forces a layout at the new width (the reply rewrapped 341px taller, the spacer and offset still placed for the old width) that the page never painted, and the next frame shows it settled. The rendering steps apply a resize before animation-frame callbacks and no task runs between them and the paint, so a frame paints at the viewport its callback saw; a sample whose viewport changed since is not a frame and is skipped. The assertions are unchanged. red: bun test test/agent-pane-chat-column.test.ts -t 'pane resized' (6x, builder) -> 16 of 16 fail green: same -> 0 of 16 fail; whole file 8/8 at 6x (5 runs); bun run check clean Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at f3002cd - vp fmt webviews/src/pages/home-channels/HomeChannelsPage.tsx Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38637927193 * chore(next): PR autofix at 1b2ed1c - vp fmt webviews/src/pages/home-channels/cloudHome.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38647133983 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
|
Found 1 test failure on Blacksmith runners: Failure
|
[Medium impact] The PR appears safe to merge, with the previously reported fallback issue remaining non-blocking. Findings
SummaryOlder history rows fade from 35% to full opacity when first seen.
Reviews (2) · Last reviewed commit: "Merge remote-tracking branch 'origin/fea..." · Reviewed by Greptile |
| if (typeof IntersectionObserver === "undefined") { | ||
| shown(); | ||
| return () => {}; | ||
| } |
There was a problem hiding this comment.
If IntersectionObserver is unavailable, this fallback calls shown() but never sets data-older-shown. The mounted RowFrame keeps acpmux-row--older, so the messages remain at 35% opacity. Set the attribute in this branch too, so the fallback restores full ink.
| if (typeof IntersectionObserver === "undefined") { | |
| shown(); | |
| return () => {}; | |
| } | |
| if (typeof IntersectionObserver === "undefined") { | |
| node.dataset.olderShown = "true"; | |
| shown(); | |
| return () => {}; | |
| } |
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. |
|
Ran the webview tests by hand, because CI's The fade test passes alongside the memoized RowFrame from #21960. A correctness review of the merged diff found nothing blocking. |
|
Merging with only base reds failing, none of which touch this PR's files: the markdown eager-JS budget (1,407,890/1,400,000, web / react-apps-check), the release-notary guard (being fixed in #22015), and four cmux-next checks (state roots in cmux-tui remote_host/config.rs, sync NSWorkspace in HomeHostView.swift, untranslated sidebar.doc.refused strings, raw font sizes in HomeFirstRunSwitchCard/TerminalSizedForChip). The fast tier was cancelled while it sat in the macOS queue. This PR changes only webviews, and its webview tests were run by hand (see above). |
|
Shipped in:
|
…in (#22205) * test: feat-cmux-next pushes run the web checks, routed by the whole push (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: feat-cmux-next pushes run the web checks again, routed by the whole push cmux-next-web.yml lost its push trigger on 2026-10-10 (cx-g34i). Since then a web red a direct push brings goes unseen until a pull request trips over it, and a pull request's new web red passes as a base red because the base has no web run to compare with (#20633 merged a new lint red next to the eager JS budget red). The trigger is back with no paths filter: ci-web's scope job now routes from everything the push brought (event.before), not its last commit, so a push with no web path runs only the scope and status jobs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: feat-cmux-next pushes run cmux-next checks again; warn on an unfetchable push base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#22208) * test: the red-checks line tells a new red from a base red, step by step (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: the red-checks line tells a new red from a base red, step by step #20633 merged with react-apps-check red because the eager JS budget red was a known base red; the job had also failed its lint step on the PR's own new test, and the base passed that step. The red-checks line now compares each red check with the base commit's run of it: failed step names plus failure annotations. A failure the base lacks is NEW and blocks; the same failure is a base red and does not; no finished base run cannot excuse it. The cmux-next checks job joins the tracked checks and writes one annotation per red sub-check, so a new red sub-check is not hidden behind its one summary step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: red-checks base comparison: a cancelled base excuses nothing; base read errors block; sub-check names match across outcomes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…reds (#22118) * fix(next): clear the webviews type-scale and text-focus base reds - syncMotion.gallery.css (c611de1) set three raw font sizes; they use the type scale tokens (body, heading, title). - CookieImportConsentPanel (60807d3) made a selectable label without focusRingType = .none. Both checks (bun run check:type-scale, check:text-focus) fail at the feat-cmux-next tip and pass here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(webviews): format settings icons.tsx (vp fmt base red from 91424a7) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(next): clear the webviews theme-colors, elevation, ui-rules and system-blue base reds - theme-colors: the markdown.theme paper colors (bb58f0f) are fixed by design and marked theme-fixed; prototypes/ is skipped as the comment says (the pattern only matched a prototype/ folder). - subtle-elevation: the subagents prototype sheet casts --elevation-2. - ui-rules: the code editor's keydown listener only reads Monaco's chord state (91424a7), marked ui-allow. - check-system-blue: the cookie consent panel's requester link uses Palette.accent, not .controlAccentColor (60807d3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(next): re-resolve the cookie consent requester tint in the theme hook Review of #22118: reading Palette.accent once at build time froze the tint across theme changes (check-theme-scope rule 1). ThemeChangeView runs the hook on window attach and on appearance change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(webviews): warm the older-rows-fade dev server before the first load check:browser-lanes has been red on feat-cmux-next since 4b5c7ad (#20633): the new test starts an in-process Vite server without warming it, so its first page.goto pays for the cold module graph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(webviews): clear the sync-motion lint warnings that fail vp check react-apps-check has been red on feat-cmux-next since c611de1 (sync motion): vp check fails on warnings, and syncMotion.ts used new Array(n) while useSyncListMotion's exhaustive-deps suppression sat on the useMemo call instead of the dependency array it reports on. Same behavior; bun run check passes on Huge Blue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(next): clear the webviews test reds the lint red hid With check:browser-lanes green, react-apps-check runs the suites and shows reds that were already on feat-cmux-next: - settings categories: two Settings layouts both placed the Markdown Viewer group (General beside Diff Viewer, and Code Editor), and Agent Input (browser.showAgentCursor) had no home. Markdown Viewer stays in General; Agent Input joins Browser after Bookmarks (Swift layout and export). - settings editors: editor.rulers is the first page-visible number_list row. The page now draws a number token field (in range, Return or comma adds). - tooltip contrast: #21785 dropped the pages' fallback tint to 60% (the floor); the host sends the per-theme tint (about 0.7 dark). The test draws with the host's tint, computed as TooltipSurface.tintAlpha does. - static status loops: the agent notice's harness spinner had no Static rule. - composer plain footer / mode keys: plain is the default since #22050; the tests turn it off where they check the chip look. - hairline rims: the four raw 0.5px rims in files this PR touches use var(--cmux-hairline). - markdown wide tables: gfm leaves out columnResizing, so no table ever had the .tableWrapper the scroll CSS targets; the editor installs TableView itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(next): wide markdown tables scroll sideways on the first wheel step The TableView wrapper is the scroller, and scrollers.ts marks a scrolling element with data-cmux-scrolling. ProseMirror read that attribute change on the table node view's dom as an edit and redrew the table, resetting scrollLeft to 0, so a sideways wheel never moved it. The table view now ignores attribute changes on its wrapper. The code-line test scrolls the code block into view first: it sits below the 14-column table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(webviews): vp fmt the #20297 update-card files (base fmt red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 62a0f5b - regenerated schemas/settings-export/settings-schema.sources.sha256 - regenerated cmux-tui/crates/cmux-app-host/generated/scopes.json Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39348548509 * fix(webviews): clear the markdown WidthField lint warnings that fail vp check (base red from 7d0f57d) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>






cx-2lv1k, Leo's paging addendum (1): "fade new rows in subtly at the top edge."
What changes
I tried three variants in Chromium: A 160 ms from 0, B 240 ms with a 40 ms stagger from 0, and C 180 ms from 35%. I picked C. A and B read as rows blinking in. With C, text is legible on the first frame and settles calmly.
Evidence
webviews/test/agent-pane-older-rows-fade.test.tsloads the real pane in Chromium with a long chat and scrolls up across a page boundary.tscis clean.vp fmt --checkandvp lintare clean on the changed files.tscis clean on 8998da8.In the app (cmux NEXT DEV builds, before and after)
Both builds come from the same tree: Before is feat-cmux-next at e26f5fa, After is this PR's head 8998da8 (that base merged in). Each opens the same imported 160-turn finished chat at its latest turn, presses Home to reach the top of the first page (the older page loads above with the reader's place held), then presses Page Up about once a second.
Light: the moment an older row comes into view.
Dark:
Paging up across the older page, light: I checked these frame by frame.
Full quality: older-rows-fade-light-scroll-up.mp4
Dark:
Full quality: older-rows-fade-dark-scroll-up.mp4
Notes on the recordings:
Extra: Chromium renders of the page alone
These are Chromium renders of the agent pane page served by a stand-in daemon, made before the in-app captures above. Left: rows already settled. Right: 60 ms after an older page lands, still on its way to full ink.
Dark
Light
Scrolling up across two older pages (variant C): I watched this recording frame by frame.
Full quality: older-rows-fade-scroll-up.mp4
Changelog
🤖 Generated with Claude Code