Repository navigation
Closed
Labels
bugSomething isn't workingSomething isn't workingrustPull requests that update rust codePull requests that update rust code
Description
Problem
In #201, the review of how a send names its message spun past land-pr's convergence rule. Five review rounds found 12 cases where the window sends a message twice, treats a new message as an old one, or loses or keeps a draft by mistake. One redesign (b35114b) failed review too, so the PR stopped fixing in place.
Root cause
Two parties own the same draft and the same outgoing message.
- The window (src/studio/StudioApp.tsx) keeps a cache of drafts, a debounce save queue, and per-screen revisions and edit counts. It also builds the outgoing message itself: text, picture imports, and request id.
- The sidecar stores the drafts and moves the start draft into a new project by matching its text. It removes duplicate sends by request id within one conversation, and it removes a draft only by revision.
Every identity model on the window side had to guess whether its copy still matched the stored draft when a send began. That guess breaks across async saves, project creation, screen changes, a saved state that arrives late, and pastes that land late.
| Round | Window model | Cases it missed |
|---|---|---|
| 47918da | object identity | restored pictures get a new request id. A first send leaves its moved start draft in the store |
| 27f2c04 | picture paths | a picture taken out and put back at the same path, with a changed file, reuses the old id |
| 9168046 | saved revision with a fallback | a failed draft save reuses the old revision. A start draft changed during project creation takes the first message's revision |
| a6c2c80 | edit count | a moved newer draft reuses the old count. A picture-only retry from the start screen makes a second project. A late paste is lost |
| b35114b | revision, known only while unchanged | an autosave and the send's own save race, so an unchanged message sends twice. A start-screen retry overwrites the project's newer draft. A late saved state restores pictures under a sent revision. A picture-only first message never moves, because the move matches text and not revision |
Direction
Give the draft and the outgoing message one owner, the sidecar. Keep the window's part synchronous and small.
- The sidecar sends a stored draft revision in one commit. One call creates the project for a start-screen send, moves the draft by revision, copies its pictures, commits the message as
draft-<rev>, and removes the draft. Sent again with the same revision, it answers with the project it already used. - The window knows only whether the composer changed since its last completed save. It never builds a request id. It never runs two saves of one screen at once.
- The 12 cases above become window and sidecar tests, written first.
Not in scope
- The non-draft fixes from the same round: the quit wait,
~/.local/binfor uv, the toolchain check limit, and the pictures cleanup. Each has its own test.
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingrustPull requests that update rust codePull requests that update rust code
Activity
pullfrog commentedon Nov 7, 2026
Implementation plan
main:mainstill has the olderdrafts.setandchat.sendcontracts, while feat(studio): the window works on the sidecar's committed chats, and the claude -p runner is gone #201 introduces the revision and window save machinery this issue addresses. Add regression tests first for the 13 cases, including delayed saves and pastes, picture-only drafts, project switches, and lost responses.draft-<rev>), and conditional draft removal together; persist the revision-to-project result so a retry after a lost response or restart returns the original project. Keep picture copying and failure recovery consistent with that commit, and never overwrite a newer draft.StudioApp.tsxand its IPC wrappers to serialize saves per screen, track edits since the last completed save, and send only the saved revision. Guard late save and paste completions against screen changes and newer edits.No duplicate was confirmed. #201 is the prerequisite and review history; #193 concerns a separate project preview defect.
gpt-6.1-terra| 𝕏AojdevStudio commentedon Nov 7, 2026
The one-owner design is built at b4c9bc2, on #201's branch. It is not pushed. The gate is green: 298 window tests, 118 sidecar tests, and TLC matches every recorded verdict with all 10 mutants failing.
Sol's review of the round, 0aa8402..b4c9bc2, found no duplicate send and no wrong-content send. It did find three P2 draft bugs at the edges:
savedrevision and never saves again. (src/studio/StudioApp.tsxsend catch, about line 440)takeState, about line 186)onQuitFlush, about line 318, andsrc-tauri/src/studio/quit.rs:15)Each fix would be small:
savedrevision, so the next send saves again.The PR's rule for this round was to stop and report, not patch, so none of these are applied.
AojdevStudio commentedon Nov 8, 2026
The fix round for the three edge findings is commit 964383e, not pushed. Sol's review of
b4c9bc2..964383efound four P2s. Three come from the fixes themselves:sentRevsintakeState). The first saved state arrives late, holding picture A at revision 1. Meanwhile the person sends text without A at revision 2. The filter then skips A, though A never went out.new. When the send answers, the window carries the same text to the project. The start screen's stored copy stays.madeFornames the pasted picture. The cleanup at start checks current drafts only, so it deletes the picture after a day, and the resumed send then fails.Recommendation for the next fix round:
madeFordrafts' pictures in the start-up cleanup. That closes 4.fix(studio): the sidecar owns the draft and the send, and a send name…
AojdevStudio commentedon Nov 8, 2026
The narrower fix round is pushed as 361b3c5, #201's head. The gate is green: 300 window tests, 120 sidecar tests, and TLC matches every recorded verdict, with all 10 mutants failing.
Sol's review of
964383e..361b3c5found no P1 or P2. It found two P3s, both shipped as known:src/studio/StudioApp.tsx:181)startedDrafts()returns every recorded start draft, completed sends included. So the start-up cleanup keeps a first message's original pasted pictures forever, after the send has copied them into the project. It costs disk space and brings back no draft. (sidecar/src/store.ts:289)Both are listed in the A to L report for Astra. A small follow-up would fix 2: drop a recorded draft once its message is committed. It would fix 1 by having the start picture merge take part only in the first state read.
AojdevStudio commentedon Nov 8, 2026
The two P3s above also live in #207, which stays open after #201 closes this issue.
feat(studio): the window works on the sidecar's committed chats, and …