Skip to content

🤖 fix: an open edit loses its typed changes on a workspace switch (#5801), plus two older edit races #5808

Description

@ThomasK33

Follow-ups from the final readiness check of PR #5801 (edit text lives only in the composer's memory, #5672 / #5571).

1. A workspace switch drops an open edit's typed changes (introduced by #5801, blocks it)

What happens: you open an edit, type changes (text, attachments), switch to another workspace, and come back. The edit reopens with the original message text, and the typed changes are gone.

Cause: ChatInput is keyed by workspace (ChatPane.tsx ~2011), so a switch remounts it. ChatPane keeps editingState per workspace (~381-386), so the edit itself survives the switch. The memory-only edit buffer lives in the remounted ChatInput (useComposerDraft), so the buffer does not survive. When you come back, the composer refills the edit from the original message (ChatInput/index.tsx ~1448).

On main the edit text survived a switch but replaced the unsent draft. #5801 keeps the unsent draft but loses the edit changes. The accepted tradeoff of #5801 covers reload only.

Fix idea: give the edit buffer a stable per-workspace, memory-only owner that survives the ChatInput remount (next to ChatPane's editingState, or an equivalent). It must survive workspace switches, stay out of other windows, and still disappear on reload. Failing-first test: switch away and back with edit text and an attachment, and check that the edit keeps both and the unsent draft stays intact.

2. Starting a second edit while one is open leaks the first edit's notes (pre-existing on main, not part of the #5801 repair)

beginEditingMessage does not check for an open edit (ChatPane.tsx ~416-427). The new session snapshots preEditReviews: draftReviews (index.tsx ~1444), and those are the first edit's notes. Cancelling the second edit then puts the first edit's notes on the unsent draft. Main had the same snapshot.

3. A Stop restore can race with opening an edit (pre-existing on main, narrow, not part of the #5801 repair)

A restore event that arrives before the edit opens, with its async acceptedSendIds lookup resolving after (index.tsx ~1632), skips the edit check (~1656). setInput(mergedText) (~1665) then replaces the edit buffer, and a later cancel loses the restored text. Main lost it in the same race.

Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $35.15

Activity

  1. changed the title [-]🤖 fix: edit-mode follow-ups after #5801 (workspace switch drops edit text, notes leak, Stop restore race)[/-] [+]🤖 fix: an open edit loses its typed changes on a workspace switch (#5801), plus two older edit races[/+] on Oct 6, 2026
  2. ThomasK33 commented on Oct 7, 2026

    @ThomasK33
    MemberAuthor

    Found by the normal review of #5801's repair head 72a15a919c (the fix for item 1 is on that branch). #5801 is parked. These must be fixed before it can merge:

    1. Transcript-only switch during an edit loses the edit's typed changes (introduced by 🤖 fix: an edit keeps its text in memory, so the unsent draft survives a reload and stays out of other windows #5801). ChatPane swaps ChatInput for the transcript-only notice and clears the edit target, so the memory-only buffer is orphaned. Fix idea: release the buffer into the normal draft (after the unsent draft, as releaseEndedEdit does) before the composer is replaced. Thread: 🤖 fix: an edit keeps its text in memory, so the unsent draft survives a reload and stays out of other windows #5801 (comment)
    2. A second Edit during an open edit overwrites the first edit's buffer (introduced by 🤖 fix: an edit keeps its text in memory, so the unsent draft survives a reload and stays out of other windows #5801). beginEditingMessage checks only a pending edit send, and beginEditDraft with a new id replaces the buffer. Fix idea: release the open edit first, or keep Edit disabled while an edit is open. Note: this overlaps item 2 above (the note leak on a second edit). A fix here can cover both. Thread: 🤖 fix: an edit keeps its text in memory, so the unsent draft survives a reload and stays out of other windows #5801 (comment)
    3. hasOlderHistory guard (tradeoff). An edit whose row another renderer really deleted stays open until its send is refused (history-changed). The refresh then releases the text, so nothing is lost. Fix idea: tell an unloaded row from a deleted one, using the target's history sequence against the loaded window or a backend check. Thread: 🤖 fix: an edit keeps its text in memory, so the unsent draft survives a reload and stays out of other windows #5801 (comment)

    Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $49.02

  3. ThomasK33 commented on Oct 7, 2026

    @ThomasK33
    MemberAuthor

    #5801 is parked again at e8acc69cd8, after its last allowed repair push.

    That push added one rule: an edit that loses its target without a settle keeps its text and files in the draft, after the unsent draft. It covers transcript-only, a second Edit, a deleted row and target-not-found, and it addresses item 1 and the overlap with item 2. #5801 is not merged, so nothing here is resolved on main.

    The normal review then found three new defects in the same design. The edit outlives a composer remount (a workspace switch), but some composer-local state does not survive with it:

    1. Duplicate edit send: a remounted composer can send the same edit again while the first send is in flight. sendingCount is local state, and canSend ignores the restored session's sendInFlight. 🤖 fix: an edit keeps its text in memory, so the unsent draft survives a reload and stays out of other windows #5801 (comment)
    2. Review notes: a send accepted after a switch away and back restores the notes only in the unmounted composer, so the edit's notes stay as the override. 🤖 fix: an edit keeps its text in memory, so the unsent draft survives a reload and stays out of other windows #5801 (comment)
    3. Refresh retry: a failed history refresh loses its retry state on a switch away and back, so Send stays disabled with no retry button. 🤖 fix: an edit keeps its text in memory, so the unsent draft survives a reload and stays out of other windows #5801 (comment)

    Re-plan before more code: keep all of the edit's per-edit state with one owner that survives the remount (the send in flight, the review restoration, the refresh retry), or end the edit on a switch and keep its contents in the draft with the same preservation rule. The second option is simpler: it gives up "the edit resumes after a switch" but keeps every typed change.


    Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $54.92

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions