Skip to content

Agent chat: closing the queue at the latest row keeps the last row on the composer - #24182

Merged
teamleaderleo merged 14 commits into
feat-cmux-nextfrom
composer-look-queue-scroll
Oct 23, 2026
Merged

teamleaderleo merged 14 commits into
feat-cmux-nextfrom
composer-look-queue-scroll

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Leo, 2026-10-21: "there's something just a bit awkward about the UI of this queuing and steering and expanding and, like, scrolling. It doesn't scroll to the very bottom. I mean, it's almost like it's allowed to, but then it just shoots back up ... it cuts off at the bottom."

Leo-ask: ask-a3f974b779
Leo-ask: ask-5ea5632ee9 (the new lines in the composer make the scrollbar jump)
Leo-ask: ask-a532e95ee7 (the wheel beside the composer should just scroll)

What was wrong

When you clicked Show less on a long queue at the latest message, the last row stayed a fold row (about 22 px) above the composer for a second. Then the rows dropped down onto it. Scrolling down in that second did nothing, because the view was already at its end.

Root cause: VirtualTranscript.noteQueue (webviews/src/agent-session/acpmux/App.tsx:1824 on feat-cmux-next 1f4437e) collects the prompt ids of the .acpmux-queued cards in the bottom stack. Any id that disappears is treated as a sent prompt on its way into the transcript (heldFor / queueLeft), and the room under the last row is kept for it (floor, FLOOR_HOLD_MS = 1 s). Closing the fold unmounts rows 3 to N (ComposerQueue.tsx, visible = shown.slice(0, steering + FOLD_SHOWS)), so every hidden row looked like a card that had left. The view held a stack's worth of room that no prompt would ever fill, then glided down when the hold ran out.

Fix

  • ComposerQueue puts the ids its fold hides on the list as data-folded-ids.
  • noteQueue counts those prompts as still queued.

Closing the fold now shrinks the room in the same frame, just as opening it grows the room. A card that really leaves (Steer, a sent prompt) still keeps its room as before.

What I checked and left alone

Changelog

  • Fixed: Closing a long queue's "Show less" at the latest message keeps the last row on the composer instead of leaving a gap that drops a second later.

Test

New webviews/test/agent-pane-queue-scroll-bottom.test.ts, run in Chromium and WebKit. It has its own stand-in acpmux, one chat of 40 turns plus a running one, and six queued prompts. Every read is of a painted frame (support/paintedFrames.ts).

cd webviews && CMUX_BROWSER_TESTS=1 bun test test/agent-pane-queue-scroll-bottom.test.ts
  • Red on base (feat-cmux-next 87bf8e9 plus the test commit): 6 pass, 2 fail. "the queue closed at the latest row ..." fails in both engines: the frames after the click hold the last row at gap 46.25 px against its rest of 24.25 px (45.25 against 23.25 in WebKit).
  • Green on head: 8 pass, 0 fail.

The four cases:

  1. Queue opened, then wheel scrolled to the end: the last row is whole above the stack in every frame for 500 ms.
  2. Queue closed at the latest row: no frame in 1.5 s keeps the room.
  3. A new line in the composer: fromEnd and scrollTop stay the same, both at the latest row and scrolled up.
  4. The wheel left and right of the queue, its fold bar and the card: the pointer reaches the transcript, which scrolls both ways.

Observed / Not run

Observed on huge-blue, with the head over feat-cmux-next 87bf8e9:

  • bun run check passes. One base file, test/subagent-stopped-after-cancel.test.ts, has a formatting issue on base, and I masked it for the run.
  • With CMUX_BROWSER_TESTS=1, these pass on the head: agent-pane-queue-collapse 13/13, agent-pane-queue-steer 7/7, agent-pane-queue 6/6, agent-pane-bottom-stack 2/2, agent-pane-scrollbar-full-height 10/10, agent-pane-permission-queue 2/2 and the new file 8/8.
  • agent-pane-dock-gutters and agent-pane-wheel-pass-through time out in beforeAll on huge-blue. Their shared papercutPane waits for every finite animation to end, and the running turn's line never settles there. This happens on base too, before any change. The new test gets its gutter coverage through its own fixture.

Not run: the app itself (no tagged build) and an independent review.

No capture: webview-only change. The before and after frames (300 ms after Show less) are kept privately by the lane.

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

Fixes the agent chat transcript holding phantom gaps after closing "Show less" on a long queue, and when a queued prompt runs on another client while its card is out of sight.

  • ComposerQueue reports the prompts its fold hides as still queued (data-folded-ids), so closing the fold shrinks the room under the last row in the same frame instead of holding it for about a second.
  • VirtualTranscript re-notes the queued prompts on each queue change, not only on resize, so a prompt run elsewhere while folded or past the list's cap leaves no phantom room when the stack shrinks later.
  • noteQueue now tracks the chat and stack it noted, so switching to a chat with its own queue no longer holds room for the previous chat's prompts.
  • Queue prompt IDs reach VirtualTranscript through a memoized snapshot (queueIds), so the notes re-run only when the queue changes.

Tests

New browser test covers closing the queue at the latest row, opening and scrolling, prompts run elsewhere, switching chats, newlines in the composer, and the wheel beside the composer; it passes in Chromium and WebKit, with the queue-close case failing on base.

Written for commit a8ade6a. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits October 22, 2026 03:50
… glides away

A browser test of the transcript end under the queue and the composer (Leo 2026-10-21:
"It doesn't scroll to the very bottom ... it cuts off at the bottom"): the queue opened and
scrolled to its end, the queue closed at the latest row, a new line in the composer, and the
wheel beside the composer. Red on base: closing the fold holds the last row a fold row above the
stack for a second, then drops it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16027-99fc-73f0-9482-5a4babfe1b0a&host=cosmic-gray
… the composer

Closing "Show less" on a long queue hides its rows past the fold, and the transcript took each
hidden row for a queued card that left the stack (a prompt on its way to the transcript). It kept
the room for it under the last row (VirtualTranscript floor) for FLOOR_HOLD_MS: the last row hung
a fold row above the stack for a second, then the rows dropped to the composer (Leo 2026-10-21:
"it's almost like it's allowed to, but then it just shoots back up ... it cuts off at the
bottom"). The queue names the prompts its fold hides (data-folded-ids) and noteQueue counts them
as still queued, so closing the fold shrinks the room in the same frame, as opening grows it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16027-99fc-73f0-9482-5a4babfe1b0a&host=cosmic-gray
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

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

Review a8ade6a: 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=pr24182 -f ref=composer-look-queue-scroll -f platform=macos -f backend_mode=local

Gallery before/after for a8ade6a: 16 states rendered, 6 images differ, 709 more touched states not rendered. Images are in the run's artifact, not on this public PR.

gh run download 40033928153 -R manaflow-ai/cmux -n gallery-advisory-24182-a8ade6a5cd01bf848020b3ac656197cecc63606b (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.chat-width/standard Apple System Colors Light unchanged 0% own App.tsx
agent-pane.chat-width/standard Apple System Colors unchanged 0% own App.tsx
agent-pane.chat-width/wide Apple System Colors Light unchanged 0% own App.tsx
agent-pane.chat-width/wide Apple System Colors unchanged 0% own App.tsx
agent-pane.chat-width/wide-blocks Apple System Colors changed 23.4% own App.tsx
agent-pane.chat-width/wide-blocks Apple System Colors Light changed 1.53% own App.tsx
agent-pane.composer/new-chat Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer/side-session Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer/side-session Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat-suggest-open Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat-suggest-open Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat-suggest-failing Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat-suggest-failing Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat-suggest-draft Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat-suggest-draft Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat-reasoning Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer/new-chat-reasoning Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer/agent-home Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer/agent-home Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer/agent-home-path Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer/agent-home-path Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer-floats/scrolled-to-end Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-floats/scrolled-to-end Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-floats/composer-grown Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-floats/composer-grown Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-turn-cycle/idle Apple System Colors Light unchanged 0% own ComposerQueue.tsx
agent-pane.composer-turn-cycle/idle Apple System Colors unchanged 0% own ComposerQueue.tsx
agent-pane.composer-turn-cycle/running Apple System Colors changed 0.0294% own ComposerQueue.tsx
agent-pane.composer-turn-cycle/running Apple System Colors Light changed 0.0023% own ComposerQueue.tsx
agent-pane.composer-turn-cycle/subagents-one Apple System Colors Light changed 0.0553% own ComposerQueue.tsx
agent-pane.composer-turn-cycle/subagents-one Apple System Colors changed 0.0357% own ComposerQueue.tsx

Pick other states with a Gallery: entry.id, entry.id/variant line in the PR body.

Passes: CI passes on a8ade6a5cd.

CI passes on a8ade6a5cd (run 40033928330 attempt 1).

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: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: red check: Companion workflows (+6 more) is not red on the base 73c3d0d; do not merge until green; see lane-rules

Tour of a8ade6a5cd (run): no media. The tour did not run: only webview code changed (3 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, then re-add media-tour, to tour it on a Mac.

@teamleaderleo teamleaderleo added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 22, 2026
@teamleaderleo

teamleaderleo commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator Author

Owned by cx3-s5-adopt on air-blue

@blacksmith-sh

blacksmith-sh Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Found 13 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmp3rhmkrns/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmpotxjva1g/summary-fail.json (live):/summary-fail.json (live): View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
convention violations found (ERROR lines above)./
convention violations found (ERROR lines above).
View Logs
test_a_pull_request_that_changes_the_shortcut_inputs_still_rewrites_them (main.Sett
ingsOnlyArtifactLeavesTheActionFollowers.test_a_pull_request_that_changes_the_shortcut_
inputs_still_rewrites_them) (job='repair')/
test_a_pull_request_that_changes_the_shortcut_inputs_still_rewrites_them (main.Sett
ingsOnlyArtifactLeavesTheActionFollowers.test_a_pull_request_that_changes_the_shortcut_
inputs_still_rewrites_them) (job='repair')
View Logs
test_base_passes (main.NoticesPairTests.test_base_passes)/
test_base_passes (main.NoticesPairTests.test_base_passes)
View Logs
test_regenerated_action_exports_bring_the_followers (main.SettingsOnlyArtifactLeave
sTheActionFollowers.test_regenerated_action_exports_bring_the_followers) (job='repair')
/test_regenerated_action_exports_bring_the_followers (main.SettingsOnlyArtifactLeav
esTheActionFollowers.test_regenerated_action_exports_bring_the_followers) (job='repair'
)
View Logs

...and 3 more test failures. View all on Blacksmith: run 40033928036, run 40033928201

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol): BLOCK at b6af5cf

Blocking finding: webviews/src/agent-session/acpmux/App.tsx:1830-1838 only refreshes queuedIds from the DOM inside the dock/transcript ResizeObserver callbacks. With a folded queue of more than three prompts, removing or dequeuing a prompt that is in the data-folded-ids portion (for example, another client runs it) changes only that attribute while the two visible rows and the capped list height stay unchanged, so no observer runs and the old ID remains in queuedIds. A later Show more/Show less or composer resize then calls noteQueue, sees that stale hidden ID in left, and adds it to heldFor/sets queueLeft even though no visible card left; for a dequeued prompt this reserves the floor and can show the same phantom gap above the composer for FLOOR_HOLD_MS before it glides away. The new test covers folding a static queue, but not a hidden queue update with unchanged dimensions.

Non-blocking findings: none.

Checked the exact two-commit diff against merge-base 87bf8e9656c51c4bca23313d4e98f63c763babfd, surrounding queue/floor lifecycle and sizing code, queue model/direct event handling, CSS, and the added browser test; no builds or test suites run.

1 similar comment
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol): BLOCK at b6af5cf

Blocking finding: webviews/src/agent-session/acpmux/App.tsx:1830-1838 only refreshes queuedIds from the DOM inside the dock/transcript ResizeObserver callbacks. With a folded queue of more than three prompts, removing or dequeuing a prompt that is in the data-folded-ids portion (for example, another client runs it) changes only that attribute while the two visible rows and the capped list height stay unchanged, so no observer runs and the old ID remains in queuedIds. A later Show more/Show less or composer resize then calls noteQueue, sees that stale hidden ID in left, and adds it to heldFor/sets queueLeft even though no visible card left; for a dequeued prompt this reserves the floor and can show the same phantom gap above the composer for FLOOR_HOLD_MS before it glides away. The new test covers folding a static queue, but not a hidden queue update with unchanged dimensions.

Non-blocking findings: none.

Checked the exact two-commit diff against merge-base 87bf8e9656c51c4bca23313d4e98f63c763babfd, surrounding queue/floor lifecycle and sizing code, queue model/direct event handling, CSS, and the added browser test; no builds or test suites run.

teamleaderleo and others added 2 commits October 22, 2026 07:13
…s no room above the stack

Codex review of #24182: a prompt the fold hides (or past an opened list's cap), run by another
client, changes no size, so neither size observer noted it. The next resize that shrank the stack
took it for a card that left and kept FLOOR_HOLD_MS of room above the stack.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16027-99fc-73f0-9482-5a4babfe1b0a&host=cosmic-gray
…n a resize

VirtualTranscript noted the queued prompts only from its two ResizeObservers. A queued prompt run
by another client while its card is out of sight (folded, or past the opened list's cap) changes
no size, so its id stayed in queuedIds; the next Show more/Show less or composer resize counted it
as a card that left and held a phantom gap above the composer for FLOOR_HOLD_MS. The snapshot's
queue now reaches VirtualTranscript, and a layout effect keyed on it calls noteQueue in the commit
that draws the change. No new observer or timer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16027-99fc-73f0-9482-5a4babfe1b0a&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol): BLOCK at 71d0781

Blocking finding — webviews/src/agent-session/acpmux/App.tsx:1839-1846 (with the clear at 2741): switch from chat A with queued prompt IDs to chat B with a different, same-height queue. The new [queue] layout effect calls noteQueue after B commits, but queuedIds still contains A's IDs, so they are classified as left, added to heldFor, and set queueLeft. The session switch makes kept false; the placement pass therefore reaches line 2741 while queueLeft is still true and skips clearing heldFor. The two-frame callback only mutates refs and schedules no render, so those stale A IDs survive into B. When a B prompt later leaves, keptFor is falsely true and the transcript holds phantom floor space under B's last row for FLOOR_HOLD_MS, then glides down. Reset the queue bookkeeping on a session/dock change, or otherwise clear these IDs after the transition is known not to be a sent prompt.

Non-blocking findings: none.

Checked the merge-base diff, full changed files, queue fold and queue-change paths, prompt withdrawal/send handling, call sites, and the exact head; the prior folded-prompt gap is covered by data-folded-ids and the new layout effect.

teamleaderleo and others added 2 commits October 22, 2026 07:50
…m for the last chat's queue

Codex review of #24182 at 71d0781: switched to a chat with its own queue, the last chat's queued prompts read as cards that left and stayed in heldFor, so a prompt withdrawn later held room above the stack for FLOOR_HOLD_MS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16027-99fc-73f0-9482-5a4babfe1b0a&host=cosmic-gray
noteQueue keeps the chat and the stack it noted queuedIds in. In another chat or stack it starts over: queuedIds from what is drawn, heldFor cleared, queueLeft false, and no prompt counts as having left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16027-99fc-73f0-9482-5a4babfe1b0a&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next guards / nightly-guards / workflow-guard-tests / release-notary is red on 6 of 10 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol): SHIP at c8d5ea5

No blocking findings.
Non-blocking findings: none.
Checked the merge-base diff (App.tsx, ComposerQueue.tsx, and the browser fixture), queue/session/dock transitions including the prior stale-state path, folded-id handling, queue snapshot update paths, and the added browser coverage. The final gh head read was rate-limited; one bounded ref fetch still resolved the PR ref to this unchanged head, with no new commits.

@teamleaderleo teamleaderleo added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Oct 22, 2026
@cursor

cursor Bot commented Oct 22, 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Orphaned: no activity for 14 h, and no lane holds a lease on it. Adopted by the orphan sweep: merged feat-cmux-next in at cffed29. A later pass queues it for the merge hub if it is reviewed, small and red only on base reds.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › Checks job structure is red on 17 of 17 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@cursor

cursor Bot commented Oct 23, 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.

@teamleaderleo
teamleaderleo merged commit 314c3c7 into feat-cmux-next Oct 23, 2026
140 of 145 checks passed
@teamleaderleo
teamleaderleo deleted the composer-look-queue-scroll branch October 23, 2026 23:29
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant