Repository navigation
Keep clipboard ownership while a native paste is unresolved #78
Description
Current status — implementation landed in #67
Merged as 8fb8ccf from signed head eff5e49. Literal insertion extends the existing shared clipboard gate with content-free unresolved-ownership metadata. Returning unknown does not admit another automated write. A fresh operation can resolve ownership from exact read-only receiver evidence or termination of the original process generation. Delivery, consumption, cleanup, and ownership have separate outcomes; no input is replayed to resolve uncertainty. The implementation retains unresolved ownership across GUI restart without persisting private clipboard contents; the live crash/restart cases below remain unverified.
Verified on the final signed build
- Two distinct signed native clients exercised a real 10-second trusted-paste delay. A returned unknown with ownership reserved; B refused without input and without changing the clipboard generation. A consumed only its own payload once. A fresh B request then resolved A through native read-only proof and completed once. This is two native callers, not two channels. The first observer stopped when its state file appeared before the matching event log; a narrow continuation verified the original event and ran only the remaining fresh B request. A was never resent. Evidence:
/tmp/ace-literal-ownership.9JB9tN/validation-active/result.jsonandvalidation-resume/result.json. - A real pi/Anthropic channel was stopped during a trusted paste that had actually begun waiting in its receiver. The durable result retained the partial-input warning; the original paste arrived exactly once afterward. Restarting the idle channel worker replayed exact tool/results/images with unchanged provider usage and no new input. This does not establish native completed/consumed/released fields for the stopped result. Evidence:
/tmp/ace-literal-channel.5gwa0r/stop/validation-stop/result.json. - Completed insertion and the actual Ace composer proved observed consumption, clipboard restoration, and released ownership. Disposable receivers/vaults were settled and closed; final cleanup left no fixture apps and preserved the current clipboard generation.
Still open
Validate separate channel callers, native-client death, response loss, GUI/helper crash and restart while input is pending, exact receiver-process termination/PID-reuse recovery, and newer human clipboard changes on this final implementation. Public persistent clipboard writes (#122, #142, #147) already go through the same unresolved-paste gate; any future temporary paste in githubnext/desktop-tools#3 must too. Hosted insertion and another physical machine remain broader #65/#8 work. Earlier proofs from other input paths are not evidence for these remaining cases.
Original problem
Keep shared clipboard ownership while a native paste is unresolved.
Source review of the literal insertion work in #67 found that ClipboardPasteTransactionGate.withExclusiveTransaction releases its in-process flag and file lock when the request closure returns. Literal insertion can return unknown, or finish after Stop/client death, while a previously dispatched Cmd+V may still be waiting in the receiver's event queue. It deliberately retains the replacement clipboard instead of restoring private prior contents, but a second channel can immediately acquire the same gate and replace that payload.
The resulting sequence is: channel A queues a paste into a slow receiver; A's verification ends without proving consumption; channel B writes its own temporary payload; A's receiver resumes and pastes B's text. Telling A's agent to inspect before retrying does not coordinate B. This is a source-derived failure path; the cross-channel race has not been reproduced in a live smoke test.
The relevant code is the new LiteralInsert.swift and PeekabooBridgeLiteralInsert.swift in apps/desktop/native/patches/peekaboo-insert.patch, together with Peekaboo's existing ClipboardPasteTransactionGate.swift. The literal insertion prerequisite and the public clipboard work (originally #75, now githubnext/desktop-tools#3) need the same ownership rule. Track this under full computer use in #8.
Acceptance
- Extend the existing clipboard transaction gate/ownership mechanism; do not introduce an independent second lock. Other Ace clipboard mutations cannot replace a payload whose native consumption remains unresolved.
- Preserve that reservation across an
unknownresult, Stop, client death, and response loss. Report delivery, consumption, clipboard cleanup, and unresolved ownership separately. Never replay the input to resolve uncertainty. - A timer expiring, the caller returning, or keys being released is not proof that Cmd+V consumed the clipboard. Resolve ownership using actual receiver evidence or evidence that the original receiver can no longer consume the queued input, including termination of its exact process generation; PID reuse must not release a reservation for a different generation.
- Define what GUI/helper restart and crash recovery do with an unresolved reservation. Do not silently admit a new automated clipboard write because the previous connection or lock holder disappeared. Recovery must not persist private clipboard contents or insert them into logs or model history.
- Preserve newer ordinary human clipboard changes. Human copy/paste remains external interference; do not claim the gate controls it or overwrite newer contents to recover an older reservation.
- Validate with real native receivers and separate channel callers: delayed consumption beyond the normal verification deadline, Stop, native-client death, response loss, and relevant GUI/helper restart. A second attempted automated clipboard mutation must not cause the first receiver to consume the second operation's payload. After verified resolution, subsequent operations should proceed normally without duplicate input.
Related: #8, #67, githubnext/desktop-tools#3, #76. (#75 was closed as superseded.)
Activity
iamnbutler commentedon Oct 13, 2026
Unresolved-paste clipboard ownership shipped in #67. Crash/restart validation is engine work and continues in githubnext/desktop-tools (#213). Closing in the pre-Universe cleanup.