-- 数据演进:隔离目标身份与迁移来源/回执;不代替任何业务域的实体或候选表。 CREATE TABLE public.muse_legacy_target ( singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton), target_id uuid NOT NULL UNIQUE, system_identifier text NOT NULL, data_directory text NOT NULL, host text NOT NULL, port integer NOT NULL CHECK (port BETWEEN 1 AND 65535), database_name text NOT NULL, database_oid oid NOT NULL, role_name text NOT NULL CHECK (role_name='muse_app'), run_purpose public.muse_purpose NOT NULL CHECK (run_purpose='production'), created_at timestamptz NOT NULL DEFAULT clock_timestamp() ); -- 应用角色不能把任意已有库自行标为隔离目标。 REVOKE ALL ON public.muse_legacy_target FROM muse_app, muse_eval; GRANT SELECT ON public.muse_legacy_target TO muse_app; CREATE TABLE public.muse_legacy_import_record ( author_id text NOT NULL, run_purpose public.muse_purpose NOT NULL CHECK (run_purpose='production'), source_key text NOT NULL CHECK (length(source_key)>0), source_hash text NOT NULL CHECK (source_hash ~ '^[0-9a-f]{64}$'), mapping_hash text NOT NULL CHECK (mapping_hash ~ '^[0-9a-f]{64}$'), original jsonb NOT NULL CHECK (jsonb_typeof(original)='object'), command_id text NOT NULL, route jsonb NOT NULL CHECK (jsonb_typeof(route)='object'), frozen_request jsonb, state text NOT NULL DEFAULT 'reserved' CHECK (state IN ('reserved','mapped','historical','quarantined')), reason_code text NOT NULL DEFAULT '', targets jsonb NOT NULL DEFAULT '[]'::jsonb CHECK (jsonb_typeof(targets)='array'), receipt jsonb, created_at timestamptz NOT NULL DEFAULT clock_timestamp(), updated_at timestamptz NOT NULL DEFAULT clock_timestamp(), PRIMARY KEY (author_id, source_key), UNIQUE (author_id, command_id), CHECK (state <> 'mapped' OR (frozen_request IS NOT NULL AND receipt IS NOT NULL AND jsonb_array_length(targets)>0)), CHECK (state = 'mapped' OR (receipt IS NULL AND targets='[]'::jsonb)) ); REVOKE DELETE ON public.muse_legacy_import_record FROM muse_app; CREATE FUNCTION public.muse_guard_legacy_import_record() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF (NEW.author_id, NEW.run_purpose, NEW.source_key, NEW.source_hash, NEW.mapping_hash, NEW.original, NEW.command_id, NEW.route) IS DISTINCT FROM (OLD.author_id, OLD.run_purpose, OLD.source_key, OLD.source_hash, OLD.mapping_hash, OLD.original, OLD.command_id, OLD.route) THEN RAISE EXCEPTION '迁移来源、映射与命令身份不可改写'; END IF; IF OLD.frozen_request IS NOT NULL AND NEW.frozen_request IS DISTINCT FROM OLD.frozen_request THEN RAISE EXCEPTION '迁移目标请求已经冻结'; END IF; IF OLD.state <> 'reserved' AND (NEW.state, NEW.reason_code, NEW.targets, NEW.receipt, NEW.frozen_request) IS DISTINCT FROM (OLD.state, OLD.reason_code, OLD.targets, OLD.receipt, OLD.frozen_request) THEN RAISE EXCEPTION '迁移终态及回执不可改写'; END IF; NEW.updated_at := clock_timestamp(); RETURN NEW; END; $$; CREATE TRIGGER muse_legacy_import_record_guard BEFORE UPDATE ON public.muse_legacy_import_record FOR EACH ROW EXECUTE FUNCTION public.muse_guard_legacy_import_record();