Files
krow_backend/migrations/000009_confirmation_replay.up.sql
2026-08-28 12:21:44 +05:30

59 lines
2.9 KiB
SQL

-- ============================================================================
-- Krow — store what a confirmation authorised, not just its fingerprint
--
-- 000007 stored a HASH of the approved call and not the call itself, with this
-- reasoning: "The arguments themselves are hashed rather than stored... hashing
-- them means this table never becomes a second copy of whatever the agent was
-- about to write."
--
-- That reasoning was wrong twice over, and this migration is the correction.
--
-- WRONG ON PRIVACY
--
-- The arguments are already stored. `agent_runs.entries` records every tool
-- call with its inputs verbatim, so the privacy this column was protecting had
-- already been given away by the trajectory — and a tool call is
-- `{"job_posting_id": "...", "worker_email": "..."}`, which is a reference to
-- rows the caller could already read, not document content.
--
-- WRONG ON CORRECTNESS, WHICH IS THE REAL PROBLEM
--
-- With only a hash, honouring an approval means re-running the model and hoping
-- it makes the same tool call again, so the hash matches. It frequently does
-- not: a model is not deterministic, and on a resumed turn it may reasonably
-- ask a clarifying question instead. Observed in practice — a person clicked
-- Approve, the model asked which of two roles was meant, the token was never
-- presented, and nothing happened. No error, no write, no explanation.
--
-- A confirmation is a person authorising a SPECIFIC ACT. The system must be
-- able to perform that act. Storing the arguments is what makes the approval
-- mean something rather than being a wish that the model cooperates.
--
-- The fingerprint stays. inputs_hash is still what a re-derived call is matched
-- against, so the older path — model reproduces the call, hash matches — keeps
-- working; the new column is what makes the direct path possible.
-- ============================================================================
SET search_path = public;
ALTER TABLE agent_confirmations
-- The arguments the approval authorises, exactly as they were fingerprinted.
-- Nullable because rows written before this migration have no copy, and a
-- backfill would have to invent one. Those tokens keep the old behaviour and
-- expire within the TTL anyway.
ADD COLUMN inputs jsonb,
-- Which agent proposed it. Not used to authorise — the principal and the
-- tenant do that — but a direct replay runs a tool outside any agent's
-- resolved tool list, and "which agent's spec offered this" is the question
-- an audit of that will ask.
ADD COLUMN agent_id text NOT NULL DEFAULT '';
ALTER TABLE agent_confirmations
ADD CONSTRAINT agent_confirmations_inputs_is_object
CHECK (inputs IS NULL OR jsonb_typeof(inputs) = 'object');
COMMENT ON COLUMN agent_confirmations.inputs IS
'The arguments this approval authorises. Replayed directly when the token is redeemed, so '
'honouring an approval does not depend on a model reproducing the same tool call.';