chatd ask: wire-level correlation between a queue entry and its materialized message
- Dominant language
- TypeScript
- Stars
- 3
- Forks
- 0
- Avg merge
- 29m
- Merged PRs (30d)
- 127
Description
## Context
#114 shipped a **client-side** attribution gate for queued submissions: when `POST /chats/{id}/messages` returns `queued: true`, the SDK withholds attribution until the queue entry materializes as the turn's own user message. Because nothing on the wire links `queued_message.id` (queue-entry id space) to the `chat_messages` id it eventually becomes, the gate correlates by:
1. **structural content equality** — the queue entry's `content` and the materialized message's `content` are produced by the same server-side parse/strip (`db2sdk.chatMessageParts`), so a canonicalized comparison is exact today;
2. **FIFO confirmation** — a matching user `message` snapshot becomes the anchor *candidate*, confirmed when the next `queue_update` (which carries the full queue) no longer lists our entry; a candidate observed while our entry is still listed is discarded as an earlier identical-content entry's materialization.
## Residual ambiguity (why a wire correlation is still wanted)
Two entries with **byte-identical content** from concurrent clients can still be mis-anchored in one window: a reconnect that spans *both* promotions replays both user-message snapshots but only the connect-time queue state — the per-promotion `queue_update`s that would have disambiguated them are collapsed into one. The gate then anchors on the newest matching snapshot, which may be the other client's twin. Content matching is also inherently coupled to the server's content encoding staying replay-stable.
## Ask
Expose the correlation chatd already has in hand at promotion time (`FinishTurn`/`FinishInterruption`/`PromoteQueuedMessage` insert the message and delete the queue entry in one transaction):
- **Preferred:** stamp the materialized user message (or its `message` stream event) with the queue-entry id it came from — e.g. `queued_message_id` on `codersdk.ChatMessage` or on the stream envelope; or
- allocate and return the future message id in `CreateChatMessageResponse.queued_message`; or
- extend `queue_update` with the promotion pairing (`queued_message_id` → `message_id`).
Any of these lets the SDK anchor exactly, delete the content-matching heuristic, and close the identical-twin window.
## Downstream context
coder/tss runs many turns against long-lived chats where corrective follow-up turns are submitted precisely while the previous run is dying — the population where queued submissions and identical retried prompts are common.
---
_Generated with [`mux`](https://github.com/coder/mux) • Model: `anthropic:claude-fable-5` • Thinking: `xhigh`_
Contributor guide
Assessment
This issue has not been assessed yet.