mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-27 06:47:07 +00:00
7ec0191d45
* feat(items): idempotency keys for patch writes; an unconfirmed patch resolves only through its own tab (TASK-3585) A patch may carry an idempotency key (Idempotency-Key header, or op_key). The key is claimed per (workspace, user, key) before any write-path guard, with a lease, and its answer is recorded inside the write's own transaction, guarded by the claim token: done holds exactly when the write committed, so an expired claim committed nothing and may be taken over. A retry of the same request replays the answer (Idempotent-Replayed); a key reused for another request is 422; a live claim is 409 in flight; a refused write releases the key. When an open editor received the patch and never confirmed it, the key records the patch id and a boot-scoped reference to that connection. A retry goes only to that connection, whose tab remembers the patches it applied and re-acks one it is sent again; with it gone the answer is patch_outcome_unknown with the diff since, and nothing is re-planned, since an insert-shaped edit would keep its anchor elsewhere. The CLI sends a key per invocation and retries once with it on a transport error or 5xx. MCP 0.90 adds op_key and three codes. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(cli): retry a keyed write only when the server advertises idempotency_keys (TASK-3585) An older server ignores op_key, so the CLI's single same-key retry of a 5xx could apply a patch twice against a server that serves patch but not keys. The retry now requires the idempotency_keys capability. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
21 lines
758 B
SQL
21 lines
758 B
SQL
-- Migration 110 (Postgres): idempotency keys for agent writes (TASK-3585). Counterpart to migrations/139_idempotency_keys.sql; the rationale is there.
|
|
CREATE TABLE IF NOT EXISTS idempotency_keys (
|
|
workspace_id TEXT NOT NULL,
|
|
user_id TEXT NOT NULL,
|
|
key TEXT NOT NULL,
|
|
route TEXT NOT NULL,
|
|
request_hash TEXT NOT NULL,
|
|
state TEXT NOT NULL,
|
|
claim_token TEXT NOT NULL,
|
|
lease_until TEXT,
|
|
status INTEGER,
|
|
response TEXT,
|
|
patch_id TEXT,
|
|
conn_id TEXT,
|
|
base_seq INTEGER,
|
|
base_body TEXT,
|
|
created_at TEXT NOT NULL,
|
|
PRIMARY KEY (workspace_id, user_id, key)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_idempotency_keys_created ON idempotency_keys(created_at);
|