Skip to content

cmux NEXT: a new chat's text left when its tab opens another chat comes back in the window's next New Tab page - #32298

Merged
teamleaderleo merged 12 commits into
feat-cmux-nextfrom
lane/new-chat-draft-survives-switch
Nov 2, 2026
Merged

teamleaderleo merged 12 commits into
feat-cmux-nextfrom
lane/new-chat-draft-survives-switch

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Fix-forward for #32276, which was found in the review of #32131. Fixes #32276.

What was lost

Picking another chat from a new chat's tab cleared what the new chat held. That covers the sidebar, New Tab's chat list (chat.select) and the spare page's adopt (chat.adopt). The host keeps a new chat's text with its tab only until the tab has a session (AgentUnsentDrafts.wire clears it on every onSessionChange), and a pick and the new chat's own start reach the host as the same chat.persistSession. So two things were lost:

Now

  • Page: before the pick's persistSession, the page sends chat.leftover {text} with the new chat's kept, held and typed text. The held prompts leave the hold, so none of them is sent later into any chat.
  • Host: AgentUnsentDrafts.leave(_:inWindow:) keeps the text in the window's single slot. The slot sits in the same on-disk file as the tabs' drafts (the relaunch seed's store), so it survives closing the tab and quitting the app. A second leftover is added after the first and never overwrites it. The window comes from the tab's workspace (WindowManager.windowID(ofWorkspace:)).
  • New Tab: every web New Tab page made in the window gets the slot's text as newTab.draft, which its field shows as an editable draft. That covers Cmd-T, a split, a workspace's first page, a restored page, and a chat that becomes a New Tab page (AgentPaneModel.newTabForPage). Nothing sends it. The slot gives up only what a page of its own window reports it showed (chat.leftoverTaken), so a page whose tab never opens loses nothing.
  • A pick from that page: while the field holds a leftover (as edited), a pick from the page leaves that text again. A query typed to find a chat isn't left.

The optional native New Tab page (tabs.nativeNewTabPage, off by default) doesn't take the slot, so the text waits for the next web page. This change adds no navigation change and flips no default.

Tests

These were committed before each fix:

  • UnsentDraftTests.aNewChatsTextLeftWhenItsTabOpensAnotherChatWaitsForTheWindowsNextNewChat:
    • a pick clears the tab's own copy but not the slot, and a chat with a session leaves nothing;
    • a second leftover adds to the first, and the slot survives a relaunch;
    • reading the slot gives nothing up; a page's chat.leftoverTaken gives up what it showed and keeps what came after;
    • a page given none reads its window's, and another window's identical slot is untouched.
  • agent-pane-unsent-draft.test.ts:
    • a new chat's typed text reaches chat.leftover on chat.select;
    • a New Tab page shows newTab.draft and acknowledges it once, sending nothing;
    • on both templates, an unedited or edited leftover is left again on a pick;
    • a typed query is not left.
  • new-tab-leftover-draft.test.ts: the New Tab page reads newTab.draft, and a blank one counts as none.
  • trust-held-prompts.test.tsx:
    • a pick pauses the new chat's held prompts until it lands, then takes them, and a failed pick resumes them;
    • a prompt whose start the pick cancelled is taken with the rest, whether it settles before the pick lands or after.

Command: cmux-ci test --setup playwright -- bash -c 'cd webviews && bun test test/agent-pane-unsent-draft.test.ts test/new-tab-leftover-draft.test.ts test/agent-pane-trust-holds-prompts.test.ts test/trust-held-prompts.test.tsx'

Observed / Not run

  • Observed:
    • at 079dc7f, the command above: 38 pass, 0 fail;
    • trust-held-prompts.test.tsx locally: red without each fix (17/2, then 19/1), green with it (20 pass);
    • PR CI at b719142: UnsentDraftTests and AgentPaneRequestDescriptionTests pass in cmux-next swift test.
  • Swift test reds that aren't this PR's: ActionCatalogTests and ActionSurfaceParityTests (newTab.default, reopenClosedBrowserPanel, export freshness). They come from base's cmux NEXT: vertical tabs per workspace or for all workspaces #32127 and its autofix; this PR changes no actions.
  • Not run: the red half of the browser tests on the fleet. cmux-ci test runs only the PR head, so the red commits were not run there.

Follow-up filed: #32443, for two New Tab pages that open before either reports showing the leftover.

Risk

Normal: drafts and persistence. The defaults guard flags NewTabPage.open and .split only because their source changed. No setting or default changes. The slot is a reserved key (left-in-new-chat:<window>) in agent-unsent-drafts.json, which no tab id can collide with. Nothing in this change sends a prompt. Chips aren't carried: text only, as with the tab's existing unsent draft.

🤖 Generated with Claude Code

Agent session: agent session


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 loss of a new chat's typed text and prompts held for a trust answer when its tab opens another chat; the text now comes back in the window's next New Tab page as an editable draft.

Bug Fixes

  • The page sends chat.leftover before the switch, so nothing is sent into any later chat and held prompts leave the hold.
  • The host keeps the text in a per-window on-disk slot beside the tabs' drafts; a second leftover appends, and the slot survives closing the tab and quitting the app.
  • The slot gives up only what a page reports it showed (chat.leftoverTaken) and only to its own window's pages; a page that never opens leaves it for the next one. Every New Tab page made (Cmd-T, split, a workspace's first or restored) receives it as newTab.draft, shown as an editable draft; a pick from a page holding one leaves it again, edits included, while a query typed to find a chat is not left.

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

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits November 2, 2026 13:04
…r the window's next new chat (red, cmux#32276)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
…es back in the window's next New Tab page

A new chat whose tab opens another chat (the sidebar's pick, chat.select or
chat.adopt) hands its kept, held and typed text to the host (chat.leftover)
before the switch, and its held prompts leave the hold, so none is sent
after. The host keeps it in the window's one slot beside the tabs' drafts on
disk (a second leftover adds to the first), and the window's next New Tab
page takes it once as its field's draft (newTab.draft). Fixes #32276.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 079dc7f: 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=pr32298 -f ref=lane/new-chat-draft-survives-switch -f platform=macos -f backend_mode=local

Gallery before/after for 079dc7f: 16 states rendered, 1 images differ, 1335 more touched states not rendered. Images are in the run's artifact, not on this public PR; the independent review of this head reads them on its own, so the PR needs no hand-made screenshots of these states.

gh run download 41485573392 -R manaflow-ai/cmux -n gallery-advisory-32298-079dc7f7f883e291858ff603280d206411534a48 (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 Light unchanged 0% own App.tsx
agent-pane.chat-width/wide-blocks Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-edge/short-edge Apple System Colors Light changed 0% own App.tsx
agent-pane.composer-edge/short-edge Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-edge/wide-edge Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-edge/wide-edge Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-edge/no-edge Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-edge/no-edge Apple System Colors unchanged 0% own App.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-rest-gap/gap-40 Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-40 Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-56 Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-56 Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-72 Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-rest-gap/gap-72 Apple System Colors unchanged 0% own App.tsx
agent-pane.continuation-spacing/shipped Apple System Colors Light unchanged 0% own App.tsx
agent-pane.continuation-spacing/shipped Apple System Colors unchanged 0% own App.tsx
agent-pane.continuation-spacing/two-thirds Apple System Colors Light unchanged 0% own App.tsx
agent-pane.continuation-spacing/two-thirds Apple System Colors unchanged 0% own App.tsx
agent-pane.continuation-spacing/half-tucked Apple System Colors Light unchanged 0% own App.tsx
agent-pane.continuation-spacing/half-tucked Apple System Colors unchanged 0% own App.tsx
agent-pane.continuation-spacing/before Apple System Colors Light unchanged 0% own App.tsx
agent-pane.continuation-spacing/before Apple System Colors unchanged 0% own App.tsx
agent-pane.copy-controls/output Apple System Colors Light unchanged 0% own App.tsx
agent-pane.copy-controls/output Apple System Colors unchanged 0% own App.tsx

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

Passes: CI passes on 079dc7f7f8.

CI passes on 079dc7f7f8 (run 41485573370 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.

web and size checks: green

Default changes

This pull request changes 2 defaults at 079dc7f7f883 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextApp/NewTabPage+Open.swift:open: "794a531551729d4a0c810e491cc4ed43cc869c56df59cc10a3ce19d05234e85f" -> "13ed70d0b29d93b5a00d2d16d9c09a418e851644950c5441979b30abd395470f"
  • tunable-source.CmuxNextApp/NewTabPage+Split.swift:split: "c9092bcc67ec3f2177415fc884d50f4e496baf87dfe0b9377ae40dc3b02e85e4" -> "8f848f8875eae69a336cd7ac7ccab9798ed6694d5d66a34c20dd1a9cb4f535c9"

The newest verdict on this commit is a BLOCK from review (codex gpt-6.1-sol high, sweep, via the review router; full diff from merge base 0384bf2fb7 to this head).
Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Review (<reviewer>): SHIP at 079dc7f7f883e291858ff603280d206411534a48, from a member, not a self-review (the newest verdict naming the head decides; a later BLOCK beats an earlier SHIP), or with an approving review on this commit from @lawrencecchen or @austinywang (the call owners in .github/defaults-call-owners.json, never the author). A receipt posted as a review re-runs this check; after a plain comment, re-run it. The needs a call label alone does not pass, and a new push needs a new receipt.

Merge receipt: merged as ae802cfe75bc with these defaults changed, WITHOUT a SHIP receipt or an approving call owner review on its head.

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

Shipped in:

@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, router-review): BLOCK at ee5b663

BLOCK at ee5b663
Visual verdict: no images; Leo tries the build

  1. [P1] [blocking] Recheck selection after saving the leftover — webviews/src/agent-session/acpmux/App.tsx:10947. While A awaits leave(), another selection can attach and persist B. A then resumes and persists itself, leaving the native tab associated with A while displaying B. A delayed-reply reproduction using this handler produces persistence order B→A; base produces A→B. Revalidate selection ownership after the new await, including in chat.adopt.

  2. [P1] [follow-up] Preserve the consumed draft across quit — Packages/macOS/CmuxNext/Sources/CmuxNextApp/NewTabPage+Open.swift:67. takeLeftover deletes the durable copy, but the receiving New Tab keeps its text only in component state. Its edits do not post chat.unsentDraft, and pane.wakeState reads only the chat composer. Recover text into New Tab, quit without sending, and relaunch: the recovered draft is gone. Transfer it into durable tab storage when consuming the slot and persist subsequent edits.

  3. [P2] [follow-up] Capture the recovered draft UI — webviews/src/agent-session/acpmux/App.tsx:12404. Supply an after image showing the recovered text in the editable New Tab field.

Follow-ups:

  • Persist the recovered New Tab draft and cover quit/relaunch.
  • Add the missing visual capture.

…a later pick still persists last

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol xhigh, router-review): BLOCK at 2e04ed7

BLOCK at 2e04ed7

Visual verdict: no images; Leo tries the build

  1. [P1][blocking] AgentPaneNewTab.draft is a stored property without a default, but the custom initializer never assigns it (AgentPaneNewTab.swift:46-49,105-128). Swift compilation fails with an uninitialized stored property error.

  2. [P1][blocking] The leftover is consumed before opening the tab (NewTabPage+Open.swift:64-67). Restoration only handles a synchronous openAgentTab failure (NewTabPage+Open.swift:85-90); asynchronous tab-creation failures occur after openAgentTab returns true and have no callback here, so the draft is lost.

  3. [P1][blocking] takeLeftover is only called from NewTabPage.open (NewTabPage+Open.swift:64-67). First, restored, and split web New Tab pages are constructed through firstPageNewTab, firstPage, or NewTabPage+Split directly, so the next page in those flows never receives the leftover.

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
teamleaderleo and others added 2 commits November 2, 2026 13:55
…hows it

A page that never shows (its tab failed to open) leaves the leftover for the
next New Tab page; a page reports it showed it (chat.leftoverTaken), and a page
the host gave none reads its window's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
… every New Tab page

Review at 2e04ed7 (router, gpt-6.1-sol): the slot was emptied before the tab
opened, so an open that failed later lost it, and only Cmd-T pages got it.
Now a page's context carries the window's leftover wherever it is made (Cmd-T,
a split, a workspace's first page, a restored one, via newTabForPage), and the
slot gives up only what a page reports it showed (chat.leftoverTaken).
AgentPaneNewTab.draft is optional, so it defaults to nil.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol high, sweep, via the review router; full diff from merge base 0384bf2 to this head): BLOCK at cc74fa3

[P2] [blocking] Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentUnsentDrafts.swift:109 - tookLeftover scans every window slot and clears the first matching text, so identical leftovers in two windows can delete the wrong window’s draft - include the window/slot identifier in chat.leftoverTaken and scope removal to it.
[P2] [blocking] Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentUnsentDrafts.swift:99 - concatenating leftovers can exceed maximumCharacters; set rejects the write, but the web app has already cleared the composer and held prompts, losing the new text - check persistence success and retain unsaved content until it is stored safely.
[P1] [blocking] webviews/src/agent-session/acpmux/App.tsx:10950 - the draft is captured before an asynchronous selection/adoption, then all current held prompts are cleared after it; edits or prompts added during the wait are omitted and lost, and an adoption callback may persist the session before chat.leftover, causing native handling to ignore it - serialize the handoff and re-read/commit the latest draft atomically before session persistence.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, router-review): BLOCK at cc74fa3

BLOCK at cc74fa3

Visual verdict: no images; Leo tries the build

  1. [P1] [blocking] App.tsx:9165-9169,12420-12425: a recovered newTab.draft is shown but never copied into newChatDraft. If the user immediately picks another chat without editing, chat.select/chat.adopt sends no chat.leftover, and the already-taken draft is lost. Classic NewTabPage also has no typing callback. Track the active New Tab field’s text in the leave path and add no-edit pick/adopt tests.

  2. [P1] [blocking] AgentUnsentDrafts.swift:79,109-115: tookLeftover searches every window’s slot and removes the first matching or prefix-matching text. Identical drafts in two windows can therefore clear the wrong window’s persisted leftover. Pass the originating window/tab through the callback and consume only that slot; add a cross-window collision test.

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
…t shows; the slot is the page's window's

Review at cc74fa3 (router, gpt-6-astra):
- A leftover shown on a New Tab page, then a pick from the page with no edit,
  sent no chat.leftover and was lost. The page keeps the field's text while it
  holds a leftover (as edited, both templates) and a pick leaves it again; a
  query typed to find a chat is not left.
- chat.leftoverTaken searched every window's slot. It now gives up only the
  page's own window's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
@cursor

cursor Bot commented Nov 2, 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 added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, sweep, via the review router; full diff from merge base 0384bf2 to this head): BLOCK at b719142

[P2] [blocking] Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentUnsentDrafts.swift:102 - Appending multiple leftovers can exceed maximumCharacters; set rejects the combined value, but the caller still clears the tab draft and held prompts, losing the newly appended text - check the return value and retain or split the text before clearing the source.
[P2] [follow-up] Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentPaneModel.swift:349 - newTabForPage reads the window slot without reserving it, so concurrent New Tab handshakes can receive the same leftover before either sends chat.leftoverTaken, duplicating the draft - atomically claim the slot with a handoff token and restore it only if that page fails to open.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex, router-review): SHIP at b719142

Reviewer: codex gpt-6-astra high, fast tier.

Follow-ups: 2. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward.

SHIP at b719142

Visual verdict: unchanged in all available before/after pairs.

  1. [P1][follow-up] Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentPaneView+NewTab.swift:34-37 promotes a first/restored page with show(page), omitting model.newTabForPage. If the view has already handshaken before promotion, its leftover slot is never included in the page context, so that page misses the draft.

  2. [P1][follow-up] Packages/macOS/CmuxNext/Sources/CmuxNextApp/NewTabPage+Open.swift:64-66 and AgentPaneModel.swift:349-352 read the window slot without claiming it. Two New Tab pages opened before the first chat.leftoverTaken can both receive and display the same draft, allowing duplicate sends.

Follow-ups:

  • [P1] Include the leftover when becomeNewTab shows a page after handshake.
  • [P1] Add an atomic claim/reservation so only one concurrent New Tab page receives a leftover.

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
…until it lands

Review at 94f283e (router, gpt-6.1-sol): while chat.select awaited the picked
chat, an answered trust question could send a new chat's held prompt into it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
teamleaderleo and others added 2 commits November 2, 2026 16:34
…ands

Review at 94f283e (router, gpt-6.1-sol): chat.select / chat.adopt awaited the
picked chat before taking the new chat's held prompts, so a trust answer in
between could send one into the picked chat, and the leftover could repeat it.
The pick now pauses new-chat sends synchronously (pauseNewChat), takes the
held prompts once it lands (one whose start it cancelled included) and builds
the leftover from what it took; a failed or superseded pick only resumes.

trust-held-prompts.test.tsx: 17 pass / 2 fail without this, 19 pass with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, router-review): BLOCK at dffb7d9

BLOCK at dffb7d9

Visual verdict: no images; Leo tries the build.

  1. [P1][blocking] A held prompt already being sent is removed from now.current.held and stored only in going at trustHeld.ts:164-170. If the chat pick completes before that send rejects with movedOn, App.tsx:9179-9187 takes only now.current.held and posts the leftover; the later catch re-adds the prompt at trustHeld.ts:195-202, after the old chat has been cleared. That prompt is then neither included in the leftover nor eligible for the selected session, so a timing race loses user text. Include/drain the in-flight going entry or defer finalizing the leftover until it settles.

Follow-ups: [P2][follow-up] No after screenshots were supplied for this UI change.

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
…ttles takes that prompt too

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, sweep, via the review router; full diff from merge base 0384bf2 to this head): BLOCK at 94f283e2e8ff1a5e03f146e0ada30153b9e7accd

[P1] [blocking] webviews/src/agent-session/acpmux/App.tsx:9173 - Trust-held prompts removed from held while in-flight live in going, which newChatLeftover and takeNewChat ignore. Switching chats during that send clears the local state, so the prompt can be requeued after cleanup or lost instead of reaching chat.leftover. - Atomically fence the switch and transfer both in-flight and held prompts into the leftover before clearing them.
[P1] [blocking] Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentUnsentDrafts.swift:113 - tookLeftover accepts an unversioned text acknowledgement and strips any matching prefix from the current slot. Since newTab.draft remains in the native page after acknowledgement and chat.leftoverTaken has no session/generation guard, a stale remount can consume part of a newer leftover (and deleted text can reappear after reload). - Clear the page draft after the first take and bind acknowledgements to an opaque slot generation/exact payload, rejecting stale acknowledgements.

Review at dffb7d9 (router, gpt-6-astra): a start the pick cancelled could
settle after the pick landed; takeNewChat took only the held ones, so the
going prompt missed the leftover and came back held for a chat no longer
shown. takeNewChat now takes it as release does (marked released: its late
settle puts nothing back).

trust-held-prompts.test.tsx: 19 pass / 1 fail without this, 20 pass with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-786825ad708e439b96f4
@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex, router-review): SHIP at 079dc7f

Reviewer: codex gpt-6-astra high, fast tier.

Follow-ups: 2. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward.

SHIP at 079dc7f

Visual verdict: retained before/after gallery pairs are byte-identical; the leftover-draft state is not shown.

  1. [P1][follow-up] webviews/src/agent-session/acpmux/newtab/adoption.ts:96-113: if newTab.context arrives before the leftover exists, the later handshake’s newTab.draft is discarded because withHandshakeNewTab merges only cwd and actions. The current New Tab page stays blank while the slot waits for a later page.

  2. [P1][follow-up] webviews/src/agent-session/acpmux/App.tsx:12458-12463: when a page previously used the stand-in composer during a host error, its first New Tab mount still sees composerStoodIn.current === true and skips takeNewChatLeftover(). A draft supplied by the successful handshake is therefore not shown or acknowledged on that page.

Follow-ups:

  • [P1][follow-up] Merge handshake newTab.draft into an already-installed early context.
  • [P1][follow-up] Ensure stand-in recovery also takes the New Tab leftover draft.

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
cmux-bot[bot]
cmux-bot Bot previously approved these changes Nov 2, 2026

@cmux-bot cmux-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmux-bot approves 079dc7f: an independent review passed this exact head (router-review receipt by teamleaderleo). A push needs a new review; a later BLOCK at this head dismisses this approval.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol high, sweep, via the review router; full diff from merge base 0384bf2 to this head): BLOCK at 079dc7f

[P2] [blocking] files/webviews/src/agent-session/acpmux/trustHeld.ts:327 - takeNewChat() removes held prompts but returns only their text, dropping every ComposerAttachment; switching away from a new chat with a trust-held attachment permanently loses that user data - carry attachment metadata through the leftover draft/persistence path, or restore the full entries before clearing the hold.
[P2] [follow-up] files/webviews/src/agent-session/acpmux/App.tsx:10962 - concurrent chat.select/chat.adopt requests each capture and later append the same new-chat draft, so rapid double-picks duplicate the text in the next New Tab draft - serialize selection or make the leave operation one-shot per new-chat generation.

@cmux-bot
cmux-bot Bot dismissed their stale review November 2, 2026 17:49

A newer verdict blocks 079dc7f (a wait as new as the SHIP or newer: comment by teamleaderleo: Review (codex gpt-6.1-sol high, sweep, via the review rout).

@teamleaderleo
teamleaderleo merged commit ae802cf into feat-cmux-next Nov 2, 2026
276 of 289 checks passed
@teamleaderleo
teamleaderleo deleted the lane/new-chat-draft-survives-switch branch November 2, 2026 18:25
cmux-bot Bot pushed a commit that referenced this pull request Nov 2, 2026
…dingTab:) (tip arch red from ae802cf) (#32521)

ae802cf (#32298) added 12 CmuxNextApp lines for a new chat's
leftover (cmux#32276), which put the app_lines row over the last green
arch tip. The tab -> pane -> workspace chain it added (and four copies
of it already in the App) is now one DaemonStore method,
workspace(holdingTab:), and the leftover's docs move to
AgentUnsentDrafts in CmuxNextAgentPane. Behavior is the same: the
method runs the same three store lookups.

WorkspaceHoldingTabTests covers the new method (a tab's workspace, a
moved tab's new one, an unknown tab).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Nov 2, 2026
…ative-tools-d

Resolve AgentPageProvider.swift: keep base chat.leftover/chat.leftoverTaken (#32298) and this PR's pane.tabRowTools.openMenu in the request-method list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-159afad10a5ab45ea16c
@lawrencecchen

Copy link
Copy Markdown
Contributor

Swift logic follow-up (tip watcher swift-logic row, STATUS 13027 "SWIFT LOGIC CULPRITS"; lead order).

This PR raised swift_logic_lines by +61 at its merge commit ae802cf: scripts/cmux-next/swift-logic-lines.py before and after the merge, with the same table (the tip's, c6be943). The largest declarations of the rise:

  • class AgentUnsentDrafts in Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentUnsentDrafts.swift: +47 lines counted as Swift logic (its row counts it as logic)
  • struct AgentPaneNewTab in Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentPaneNewTab.swift: +4 lines counted as Swift logic (its row counts it as logic)
  • class AgentPaneModel in Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentPaneModel.swift: +4 lines counted as Swift logic (its row counts it as logic)
  • extension NewTabPage in Packages/macOS/CmuxNext/Sources/CmuxNextApp/NewTabPage+Split.swift: +2 lines counted as Swift logic (its row counts it as logic)

plans/cmux-next/layer-ownership.md says Rust owns every state, list and rule and Swift is the platform shell. Please move the new logic of this PR in a follow-up: to Rust (the crate that owns the area; the owner lists in STATUS 12147-12165 name the target per area), or at least out of the app into its package. If a declaration above is platform code (AppKit, Core Animation, OS calls, strings, tokens, DEBUG tooling), reply here and the table gets a PLATFORM row with your reason instead.

The swift-logic row is a report, not a gate: nothing blocks on this comment.

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 079dc7f7 Deployed Nov 2, 2026 by teamleaderleo via cmux-tui tree preflight #102057
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants