-- Durable diagnostic attempts; this migration registers no MCP action. BEGIN; CREATE TABLE server_probe_executions ( receipt_id uuid PRIMARY KEY, binding_proof text NOT NULL CHECK(binding_proof ~ '^[a-f0-9]{64}$'), identity_kind text NOT NULL CHECK(identity_kind IN ('mcp','rest')), execution_id uuid NOT NULL, actor_id text NOT NULL CHECK(length(actor_id) BETWEEN 1 AND 200), authentication text NOT NULL CHECK(authentication IN ('mcp','jwt','local')), mcp_connection_id uuid REFERENCES mcp_connections(id), mcp_credential_id uuid REFERENCES mcp_credentials(id), request_id text, authority_issued_at bigint NOT NULL CHECK(authority_issued_at>=0), authority_expires_at timestamptz NOT NULL, source_server_id integer NOT NULL CHECK(source_server_id>0), destination_server_id integer CHECK(destination_server_id>0), tool text NOT NULL CHECK(tool IN ('ping','traceroute','bandwidth','dns','route','mtu')), state text NOT NULL DEFAULT 'claimed' CHECK(state IN ('claimed','completed','failed','cancelled')), attempted_stages integer CHECK(attempted_stages BETWEEN 0 AND 11), completed_stages integer CHECK(completed_stages BETWEEN 0 AND attempted_stages), receipt_ciphertext text CHECK(octet_length(receipt_ciphertext)<=262144), receipt_proof text CHECK(receipt_proof ~ '^[a-f0-9]{64}$'), created_at timestamptz NOT NULL DEFAULT clock_timestamp(), finished_at timestamptz, UNIQUE(identity_kind,execution_id), CHECK((identity_kind='mcp' AND authentication='mcp' AND mcp_connection_id IS NOT NULL AND mcp_credential_id IS NOT NULL AND request_id IS NULL) OR (identity_kind='rest' AND authentication IN ('jwt','local') AND mcp_connection_id IS NULL AND mcp_credential_id IS NULL AND request_id IS NOT NULL AND length(request_id) BETWEEN 1 AND 200)), CHECK((tool='bandwidth')=(destination_server_id IS NOT NULL)), CHECK((state='claimed' AND receipt_ciphertext IS NULL AND receipt_proof IS NULL AND finished_at IS NULL AND attempted_stages IS NULL AND completed_stages IS NULL) OR (state<>'claimed' AND receipt_ciphertext IS NOT NULL AND receipt_proof IS NOT NULL AND finished_at IS NOT NULL AND attempted_stages IS NOT NULL AND completed_stages IS NOT NULL)) ); CREATE TABLE server_probe_execution_stages ( receipt_id uuid NOT NULL REFERENCES server_probe_executions(receipt_id), stage_index integer NOT NULL CHECK(stage_index BETWEEN 1 AND 11), kind text NOT NULL CHECK(kind IN ('source-dns-A','native-ping','native-traceroute','native-bandwidth','native-route-read', 'manager-dns-A','manager-dns-AAAA','manager-dns-MX','manager-dns-NS','manager-dns-TXT','manager-dns-CNAME','manager-dns-PTR', 'native-mtu-1500','native-mtu-1492','native-mtu-1480','native-mtu-1476','native-mtu-1472','native-mtu-1468','native-mtu-1400','native-mtu-1280','native-mtu-1024','native-mtu-576')), timeout_ms integer NOT NULL CHECK(timeout_ms BETWEEN 1 AND 120000), state text NOT NULL DEFAULT 'intent' CHECK(state IN ('intent','received')), outcome text CHECK(outcome IN ('received','source-unavailable')), created_at timestamptz NOT NULL DEFAULT clock_timestamp(), received_at timestamptz, PRIMARY KEY(receipt_id,stage_index), CHECK((state='intent' AND outcome IS NULL AND received_at IS NULL) OR (state='received' AND outcome IS NOT NULL AND received_at IS NOT NULL)) ); CREATE TABLE server_probe_execution_quarantines ( receipt_id uuid PRIMARY KEY, binding_proof text NOT NULL CHECK(binding_proof ~ '^[a-f0-9]{64}$'), identity_kind text NOT NULL CHECK(identity_kind IN ('mcp','rest')), execution_id uuid NOT NULL, identity_proof text NOT NULL CHECK(identity_proof ~ '^[a-f0-9]{64}$'), error_code text NOT NULL CHECK(error_code ~ '^[A-Z_]{1,64}$'), attempted_stages integer NOT NULL CHECK(attempted_stages BETWEEN 0 AND 11), completed_stages integer NOT NULL CHECK(completed_stages BETWEEN 0 AND attempted_stages), created_at timestamptz NOT NULL DEFAULT clock_timestamp(), UNIQUE(identity_kind,execution_id) ); CREATE FUNCTION server_probe_execution_immutable() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF TG_OP='DELETE' THEN RAISE EXCEPTION 'probe execution journal is append only'; END IF; IF OLD.state<>'claimed' OR (to_jsonb(OLD)-ARRAY['state','attempted_stages','completed_stages','receipt_ciphertext','receipt_proof','finished_at']) IS DISTINCT FROM (to_jsonb(NEW)-ARRAY['state','attempted_stages','completed_stages','receipt_ciphertext','receipt_proof','finished_at']) OR NEW.state='claimed' THEN RAISE EXCEPTION 'probe execution identity or terminal receipt is immutable'; END IF; IF EXISTS(SELECT 1 FROM server_probe_execution_quarantines WHERE receipt_id=OLD.receipt_id) THEN RAISE EXCEPTION 'probe execution quarantined'; END IF; RETURN NEW; END $$; CREATE TRIGGER server_probe_execution_immutable BEFORE UPDATE OR DELETE ON server_probe_executions FOR EACH ROW EXECUTE FUNCTION server_probe_execution_immutable(); CREATE FUNCTION server_probe_stage_immutable() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF TG_OP='DELETE' THEN RAISE EXCEPTION 'probe stage journal is append only'; END IF; PERFORM receipt_id FROM server_probe_executions WHERE receipt_id=NEW.receipt_id AND state='claimed' FOR UPDATE; IF NOT FOUND OR EXISTS(SELECT 1 FROM server_probe_execution_quarantines WHERE receipt_id=NEW.receipt_id) THEN RAISE EXCEPTION 'probe attempt is not executable'; END IF; IF TG_OP='INSERT' AND (NEW.stage_index<>(SELECT COALESCE(max(stage_index),0)+1 FROM server_probe_execution_stages WHERE receipt_id=NEW.receipt_id) OR EXISTS(SELECT 1 FROM server_probe_execution_stages WHERE receipt_id=NEW.receipt_id AND state<>'received')) THEN RAISE EXCEPTION 'probe stages must be serial and contiguous'; END IF; IF TG_OP='UPDATE' AND (OLD.state<>'intent' OR NEW.state<>'received' OR (to_jsonb(OLD)-ARRAY['state','outcome','received_at']) IS DISTINCT FROM (to_jsonb(NEW)-ARRAY['state','outcome','received_at'])) THEN RAISE EXCEPTION 'probe stage terminal state is immutable'; END IF; RETURN NEW; END $$; CREATE TRIGGER server_probe_stage_immutable BEFORE INSERT OR UPDATE OR DELETE ON server_probe_execution_stages FOR EACH ROW EXECUTE FUNCTION server_probe_stage_immutable(); CREATE FUNCTION server_probe_quarantine_immutable() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'probe quarantine is immutable'; END $$; CREATE TRIGGER server_probe_quarantine_immutable BEFORE UPDATE OR DELETE ON server_probe_execution_quarantines FOR EACH ROW EXECUTE FUNCTION server_probe_quarantine_immutable(); INSERT INTO schema_migrations(id) VALUES ('0035_server_probe_journal') ON CONFLICT (id) DO NOTHING; COMMIT;