Files
multica/server/migrations/182_chat_draft_restore.up.sql
YYClaw 9eddcaff10 fix(chat): defer cancellation-time finalization until the task transcript is stable (#5246)
A quick Stop before the agent's first token no longer races a late reply. Started-but-empty cancellations defer the empty/non-empty judgment until the daemon acks its transcript flush (or a grace-period sweeper fires), then settle to a single outcome. Empty outcomes persist a durable, creator-authorized draft restore (fetched/consumed via a dedicated endpoint, reconnect-safe and at-most-once) instead of broadcasting the prompt over the workspace bus.

Closes #5219
2026-07-15 00:52:27 +08:00

29 lines
1.4 KiB
SQL

-- Durable draft restore for deferred cancellations (#5219). When a cancelled
-- chat task's transcript settles as empty, the triggering user message is
-- deleted and its content must return to the creator's composer. The
-- chat:cancel_finalized broadcast is best-effort, so the restore is persisted
-- here and served by a creator-authorized endpoint: a client that was offline
-- across the event fetches it on the next session open and consumes it
-- (DELETE) once applied.
--
-- No foreign keys: new tables enforce their relationships in the application
-- layer (MUL-3515). DeleteChatSession prunes this table inside its transaction,
-- alongside the channel_* tables it already prunes there.
--
-- id is the deleted user chat message's id: globally unique (it was a
-- chat_message PK), stable for client-side dedup, and one restore per task is
-- guaranteed by the atomic deferred-finalize claim.
--
-- The chat_session_id lookup index lives in migration 183: every production
-- index is built CONCURRENTLY in its own single-statement file.
CREATE TABLE chat_draft_restore (
id UUID PRIMARY KEY,
chat_session_id UUID NOT NULL,
task_id UUID NOT NULL,
content TEXT NOT NULL,
-- Detached attachment rows the restored draft re-binds; resolved to full
-- attachment responses (URL policy included) at read time.
attachment_ids UUID[] NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);