Summary
attach_file and propose_plan both persist a coderd-side chat attachment via StoreFile. Neither is idempotent, so a replayed tool call can create a duplicate attachment.
Where
coderd/x/chatd/chattool/attachfile.go:59-77
coderd/x/chatd/chattool/proposeplan.go:98-126
When a replay happens
A resumed turn replays tool calls that history still shows as unresolved. Interrupts and edits do not produce those, because both commit synthetic cancellation results, which marks the calls handled. The window that remains is a worker that dies or an attempt that is retried between running a tool and committing its result, including a lost response.
Why this is separate from CODAGT-757
The stack in #27369-#27372 gives the workspace agent a run-once reservation mechanism, and execute uses it via a client token sent with StartProcess. These two tools involve no agent token at all: the duplicated side effect is a coderd-layer write. Fixing them needs idempotency at the StoreFile layer or an equivalent key on the attachment, not the agent mechanism.
Once #27370 lands, every local tool receives the identity of the call it is running (chat ID, assistant message row ID, provider tool-call ID), so a fix has a stable key available without new plumbing.
Impact
Low. A duplicate attachment is visible to the user and consumes storage, but nothing is destroyed and no command re-runs.
Filed by Mux, an AI coding agent, operating on Mike's behalf.
Summary
attach_fileandpropose_planboth persist a coderd-side chat attachment viaStoreFile. Neither is idempotent, so a replayed tool call can create a duplicate attachment.Where
coderd/x/chatd/chattool/attachfile.go:59-77coderd/x/chatd/chattool/proposeplan.go:98-126When a replay happens
A resumed turn replays tool calls that history still shows as unresolved. Interrupts and edits do not produce those, because both commit synthetic cancellation results, which marks the calls handled. The window that remains is a worker that dies or an attempt that is retried between running a tool and committing its result, including a lost response.
Why this is separate from CODAGT-757
The stack in #27369-#27372 gives the workspace agent a run-once reservation mechanism, and
executeuses it via a client token sent withStartProcess. These two tools involve no agent token at all: the duplicated side effect is a coderd-layer write. Fixing them needs idempotency at theStoreFilelayer or an equivalent key on the attachment, not the agent mechanism.Once #27370 lands, every local tool receives the identity of the call it is running (chat ID, assistant message row ID, provider tool-call ID), so a fix has a stable key available without new plumbing.
Impact
Low. A duplicate attachment is visible to the user and consumes storage, but nothing is destroyed and no command re-runs.