Why: A busy 409 used to enqueue a new id, so the retry created a second user message after the server had already stored the first.
Evidence: vitest run passed, 13 files and 69 tests, including the outbox retry case.
Impact: Data layer only. sendMessage and outbox flush reuse the queued message id as requestId. No screen changes.
Refs: Dev feature/pi-durable-borrow
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: a busy conversation rejected further input, and the file list lived
only behind the workspace overlay.
Evidence: npx tsc --noEmit and vitest 42 tests, including outbox
append/edit/promote. The queue uses Collapsible and design tokens.
The files tab reuses ArtifactsPanel.
Impact: while a run is active, Enter queues the draft (edit, delete, or
send-now). Finished and failed runs drain the queue. HTTP 409 also
enqueues instead of only toasting. Backend serialization is unchanged.
Refs: task feature/input-queue
Co-authored-by: Cursor <cursoragent@cursor.com>