Skip to content

fix(drafts): adopt legacy state atomically and preserve clear ownership - #26642

Draft
teamleaderleo wants to merge 21 commits into
feat-cmux-nextfrom
lane/nx-draft-persistence
Draft

teamleaderleo wants to merge 21 commits into
feat-cmux-nextfrom
lane/nx-draft-persistence

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Legacy draft adoption could leave partial attachments or resurrect an intentional clear after a copy or publication failure. Keep draft state under its stable logical-channel root, adopt only exact supported legacy identities, and preserve every current destination draft, including empty clear values.

Migration stages the current root and each artifact, retains per-artifact completion markers and current ownership, and publishes through one Darwin renamex_np exchange/exclusive rename. Failed publication leaves canonical data intact. Attachment writers persist independent per-chat ownership before moving files, clearing, error cleanup or pruning; those markers survive outside deleted chat folders and prevent both preexisting and newly created chats from reappearing on a retry. Wake consumption/save records ownership before mutation. Unsent drafts retain empty-key and moved-from tombstones; ordered saves use the injected app BackgroundWork.files owner with a shutdown hold, and seed/hasDraft ignore empty tombstones. Once quit is irrevocably committed and all session-end/retry steps finish, the unsent store fences new producers and awaits its ordered files lane before browser shutdown. Cancelled quits remain writable, and the shared background owner remains open for the final Home flush.

The startup barrier completes adoption before draft readers or wake restoration. Regressions retain sibling/leaf copy failures, failed publication with missing/empty/current roots, current and late-created chat clears, ownership-write failure, unrelated malformed artifacts, consumed wake state, unsent clears/moves, shutdown/relaunch, a blocked files lane for Keep and End with text/empty clears, late callbacks during finalization, cancelled-quit writability, channel isolation and backward-compatible draft schemas. Native test sources are authored; runtime behavior remains unverified while native execution is on HOLD.

Exact head: 87d8459a652168f33482c2012f9203e20156df2a. Actual feat-cmux-next merge base: 9445568053d73aaed41afefe1e7afa0dd9246aee. Foundation diff: 14 files, 796 insertions and 35 deletions (831 total). This is slightly above the initial approximately 800-line budget because the quit durability repair retains 71 native regression-source lines for blocked-save, late-callback and cancelled-quit behavior. Those regressions are in distinct source commit 30bd9c9ea1d; the quit wiring is commit 87d8459a652. The off-main unsent owner remains isolated in commit 6b3634097d3.

Dependent text/hydration draft #26842 is frozen at b37323992f8e3e5e21627e49408761b4ffca4e64, still based on the previous foundation head 30d5897, pending one rebase onto this repaired head. Its relative diff is 335 lines. It contains daemon/native text recovery, provider wiring, and the first-session web handshake repair. NewTab/Quick stack on that text lane; queue uses this foundation's markCurrent API.

Validation: exact-head prepush gate against the merge base reports no new violations; diff check is clean. The foundation has no web source diff; the unchanged web tree passed the full web check. The dependent text route passed its exact-head web-lint wrapper and 36 focused composer tests/67 assertions. Native compilation and tests remain UNEXECUTED/HOLD under #26809/HQ4779. Fresh whole-diff exact-head review and native verification remain required; the composer P0 root session owns the final primary review, required-check reconciliation and guarded landing.

Agent session: agent session

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 87d8459: 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=pr26642 -f ref=lane/nx-draft-persistence -f platform=macos -f backend_mode=local

Passes: CI passes on 87d8459a65.

CI passes on 87d8459a65 (run 40677873018 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

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

gh run download 40671255756 -R manaflow-ai/cmux -n gallery-advisory-26642-a51f0545f2fb0abcd2da041065ed17c7e8ebc22a (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/new-chat Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer/new-chat Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer/side-session Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer/side-session Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer/new-chat-suggest-open Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer/new-chat-suggest-open Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer/new-chat-suggest-failing Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer/new-chat-suggest-failing Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer/new-chat-suggest-draft Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer/new-chat-suggest-draft Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer/new-chat-reasoning Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer/new-chat-reasoning Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer/agent-home Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer/agent-home Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer/agent-home-path Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer/agent-home-path Apple System Colors unchanged 0% own Composer.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-row/claude-auto Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer-row/claude-auto Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer-row/long-model Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer-row/long-model Apple System Colors unchanged 0% own Composer.tsx
agent-pane.composer-row/leo-report Apple System Colors Light unchanged 0% own Composer.tsx
agent-pane.composer-row/leo-report Apple System Colors unchanged 0% own Composer.tsx

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

@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Oct 28, 2026
@teamleaderleo
teamleaderleo force-pushed the lane/nx-draft-persistence branch from 2e39dc9 to 3ceb95c Compare October 28, 2026 04:10
@teamleaderleo
teamleaderleo force-pushed the lane/nx-draft-persistence branch 2 times, most recently from 52f425e to 600202e Compare October 28, 2026 04:12
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

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

@blacksmith-sh

blacksmith-sh Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Found 5 test failures on Blacksmith runners:

Failures

Test View Logs
build_only must be a conjunctive exclusion on the helper, signing, and publication jobs
, and must not gate the unsigned app build/
build_only must be a conjunctive exclusion on the helper, signing, and publication jobs
, and must not gate the unsigned app build
View Logs
nightly.yml must derive the embedded key and sign every appcast through the helper/
nightly.yml must derive the embedded key and sign every appcast through the helper
View Logs
test_prepare_runs_on_linux_and_executes_no_mach_o (main.NightlyPooledRoutingTests.t
est_prepare_runs_on_linux_and_executes_no_mach_o)/
test_prepare_runs_on_linux_and_executes_no_mach_o (main.NightlyPooledRoutingTests.t
est_prepare_runs_on_linux_and_executes_no_mach_o)
View Logs
test_the_next_feed_keeps_its_newest_nightly_item_before_it_goes_live (main.Workflow
Tests.test_the_next_feed_keeps_its_newest_nightly_item_before_it_goes_live)/
test_the_next_feed_keeps_its_newest_nightly_item_before_it_goes_live (main.Workflow
Tests.test_the_next_feed_keeps_its_newest_nightly_item_before_it_goes_live)
View Logs
test_the_nightly_is_covered (main.NightlyStepCoverageTests.test_the_nightly_is_cove
red)/
test_the_nightly_is_covered (main.NightlyStepCoverageTests.test_the_nightly_is_cove
red)
View Logs

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, next-review): BLOCK at 600202e

  • Compile blocker — Packages/macOS/CmuxNext/Sources/CmuxNextCompat/DraftStateMigration.swift:58: An extra } closes the homes loop before sessions is used, leaving it out of scope and subsequent statements outside the function. Lines 69–70 also use invalid optional-binding syntax in a for … where clause. The target cannot compile.
  • Stale drafts restored — webviews/src/agent-session/acpmux/App.tsx:7592: An authoritative empty daemon draft falls back to the local mirror. If another client clears or sends the draft, this client restores its stale text. Use the mirror when the daemon read fails, and honor successful empty results.

Leo: drafts must survive an update and relaunch, including attachments.

Agent-Session: unknown
Agent-Session: nx-composer-draft-persistence
Preserve current per-tab and per-session values, import only missing legacy drafts, and keep draft text requests on the injected files lane. Complete migration before wake and service readers start.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-8284337bbcbcfb8957d8
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@teamleaderleo teamleaderleo changed the title fix(composer): retain drafts across app updates fix(composer): retain drafts through relaunch and legacy adoption Oct 28, 2026
@cursor

cursor Bot commented Oct 28, 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 changed the title fix(composer): retain drafts through relaunch and legacy adoption fix(drafts): adopt legacy state atomically and preserve clear ownership Oct 28, 2026
Source-only regression under native HOLD #26809/HQ4779. The finalization API is introduced by the following repair commit.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-8284337bbcbcfb8957d8
After all session-end and retry steps, fence unsent draft mutations on the main actor, then await the existing ordered files-lane flush. Cancelled quits never reach this committed boundary; the shared background owner remains open for the final Home flush.

Agent-Session: https://cmux.com/deeplink/agent?id=aid-8284337bbcbcfb8957d8
@github-actions

Copy link
Copy Markdown
Contributor

Default changes

This pull request changes 1 default at 87d8459a6521 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextApp/Quit/QuitCompletion.swift:run: "f89c92764a68830eab7e9227b679147df46cbe128ece3b46131af9609379ae54" -> "1958f57910b98b249d4280b39a45995f9852a85181d6b7409c33100dcc031fd4"

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 87d8459a652168f33482c2012f9203e20156df2a, 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.

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Heads-up: #26963 touches the same draft persistence code (AgentPaneDraftAttachments.swift / AgentPaneRelaunchWake.swift). It removes the 64 MiB draft-chip cap and the 128 MiB relaunch cap, so unsent chips over those sizes are no longer lost after a relaunch, and it moves chip text to its own file. Whichever lands second will need a rebase.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra, router-review): BLOCK at 87d8459

GraphQL: API rate limit already exceeded for user ID 13091533.
BLOCK at 87d8459

Visual verdict: no images supplied (range review); the visual verdict must come separately

  1. [P1] [blocking] AppDelegate.swift:88 — Startup open requests can disappear. Launch now returns to AppKit while migration runs, before services exist or the URL handler is installed. During this interval, application(_:open:) silently drops requests through routeOpenedURL’s nil-services guard, and Handoff returns false. Previously, initialization completed before returning. Register handlers before suspending and queue requests until services are ready.

  2. [P1] [blocking] DraftStateMigration.swift:125 — Partial wake migration permanently loses attachment restoration. If wake JSON copies successfully but copying its attachment files fails, migration publishes the JSON alone. Launch then calls readAndRemove, which marks both artifacts adopted, drops chips whose files are missing, and deletes the JSON. Subsequent migrations skip those attachments permanently. This loses pasted images in sessionless chats, which have no session attachment-store fallback. Migrate and settle the wake JSON and its attachment directory together, rolling both back on failure.

Static review completed; native tests could not run here because this box has Linux and no Swift toolchain.

exit=1

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

Copy link
Copy Markdown
Collaborator Author

At current head 87d8459a652168f33482c2012f9203e20156df2a, the exact-head Astra review is BLOCK: startup can return to AppKit while draft migration runs, before services or the URL handler exist, so application(_:open:)/Handoff requests can be silently dropped. Register handlers before suspending or queue requests until services are ready; then rerun native validation and obtain a fresh exact-head review.

1 similar comment
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

At current head 87d8459a652168f33482c2012f9203e20156df2a, the exact-head Astra review is BLOCK: startup can return to AppKit while draft migration runs, before services or the URL handler exist, so application(_:open:)/Handoff requests can be silently dropped. Register handlers before suspending or queue requests until services are ready; then rerun native validation and obtain a fresh exact-head review.

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 87d8459a Deployed Oct 28, 2026 by teamleaderleo via wait for same-key tree publisher #71532
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.

1 participant