-- 持久任务、步骤、尝试、独立作用域租约和有序事件。 -- 模型预算与原文生命周期随所属实现接入;用于当前开发基线。 DO $migration$ DECLARE namespace text; BEGIN FOREACH namespace IN ARRAY ARRAY['public', 'evaluation'] LOOP EXECUTE format($ddl$ CREATE TABLE %1$I.muse_task ( task_id uuid PRIMARY KEY, run_purpose public.muse_purpose NOT NULL, command_id text NOT NULL, author_id text NOT NULL, request_hash text NOT NULL, frozen_input jsonb NOT NULL, flow_id text NOT NULL, flow_version text NOT NULL, flow_snapshot jsonb NOT NULL, state text NOT NULL CHECK (state IN ('queued','running','paused','reconciling','failed','cancelled','completed')), scope_key text, scope_generation bigint, last_sequence bigint NOT NULL DEFAULT 0, created_at timestamptz NOT NULL DEFAULT clock_timestamp(), updated_at timestamptz NOT NULL DEFAULT clock_timestamp(), UNIQUE (run_purpose, author_id, command_id) ); CREATE TABLE %1$I.muse_task_control ( run_purpose public.muse_purpose NOT NULL, author_id text NOT NULL, command_id text NOT NULL, task_id uuid NOT NULL REFERENCES %1$I.muse_task(task_id), request_hash text NOT NULL, receipt jsonb, PRIMARY KEY (run_purpose, author_id, command_id) ); CREATE TABLE %1$I.muse_step ( task_id uuid NOT NULL REFERENCES %1$I.muse_task(task_id), step_id text NOT NULL, processor_id text NOT NULL, processor_version text NOT NULL, dependencies text[] NOT NULL, state text NOT NULL CHECK (state IN ('pending','running','completed','failed','unknown')), current_attempt uuid, checkpoint jsonb NOT NULL DEFAULT '{}', result jsonb, PRIMARY KEY (task_id, step_id) ); CREATE TABLE %1$I.muse_attempt ( attempt_id uuid PRIMARY KEY, task_id uuid NOT NULL, step_id text NOT NULL, worker_id text NOT NULL, lease_token uuid NOT NULL, lease_until timestamptz NOT NULL, scope_generation bigint, heartbeat_at timestamptz NOT NULL DEFAULT clock_timestamp(), state text NOT NULL CHECK (state IN ('running','expired','paused','cancelled','completed','failed','unknown')), call_state text NOT NULL DEFAULT 'not_sent' CHECK (call_state IN ('not_sent','sent','unknown','saved')), call_reference text, result jsonb, failure_code text, created_at timestamptz NOT NULL DEFAULT clock_timestamp(), FOREIGN KEY (task_id, step_id) REFERENCES %1$I.muse_step(task_id, step_id) ); CREATE TABLE %1$I.muse_task_scope_lease ( run_purpose public.muse_purpose NOT NULL, scope_key text NOT NULL, holder_task_id uuid, generation bigint NOT NULL CHECK (generation > 0), lease_until timestamptz NOT NULL, PRIMARY KEY (run_purpose, scope_key) ); CREATE TABLE %1$I.muse_task_event ( event_id uuid PRIMARY KEY, task_id uuid NOT NULL REFERENCES %1$I.muse_task(task_id), step_id text, attempt_id uuid, sequence bigint NOT NULL, event_type text NOT NULL, occurred_at timestamptz NOT NULL DEFAULT clock_timestamp(), payload_version integer NOT NULL, payload jsonb NOT NULL, payload_hash text NOT NULL, UNIQUE(task_id, sequence) ); CREATE INDEX ON %1$I.muse_task (run_purpose, state, created_at); CREATE INDEX ON %1$I.muse_step (state, task_id); CREATE INDEX ON %1$I.muse_attempt (task_id, state, lease_until); $ddl$, namespace); END LOOP; END $migration$; -- 预算与配置:额度账户串行化预留,金额事实留在逐调用账本。 -- 原文:授权和租约先持久化,完整归档事务同时写入清单与字节。 DO $raw_lifecycle$ DECLARE namespace text; BEGIN FOREACH namespace IN ARRAY ARRAY['public', 'evaluation'] LOOP EXECUTE format($ddl$ CREATE TABLE %1$I.muse_raw_namespace ( singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton), namespace_id uuid NOT NULL DEFAULT gen_random_uuid() ); INSERT INTO %1$I.muse_raw_namespace (singleton) VALUES (true); CREATE TABLE %1$I.muse_raw_orphan_cleanup ( run_purpose public.muse_purpose NOT NULL, object_id uuid NOT NULL, receipt_id uuid NOT NULL DEFAULT gen_random_uuid(), state text NOT NULL CHECK (state IN ('pending','completed')), removed boolean, completed_at timestamptz, PRIMARY KEY (run_purpose,object_id) ); CREATE TABLE %1$I.muse_raw_authorization ( authorization_id uuid PRIMARY KEY, task_id uuid NOT NULL REFERENCES %1$I.muse_task(task_id), command_id text NOT NULL, approved_by text NOT NULL, source_version text NOT NULL, content_hashes text[] NOT NULL CHECK (cardinality(content_hashes)>0), purpose text NOT NULL, retention_mode text NOT NULL CHECK (retention_mode IN ('temporary','archive','persistent')), approved_at timestamptz NOT NULL, valid_until timestamptz NOT NULL, request_hash text NOT NULL, revoked boolean NOT NULL DEFAULT false, call_id text, call_request_hash text, response_hash text, parent_authorization_id uuid REFERENCES %1$I.muse_raw_authorization(authorization_id), attempt_id uuid REFERENCES %1$I.muse_attempt(attempt_id), derivation_kind text CHECK (derivation_kind IN ('model','tool')), evidence_refs uuid[] NOT NULL DEFAULT '{}', CHECK ((call_id IS NULL) = (call_request_hash IS NULL)), CHECK (response_hash IS NULL OR call_id IS NOT NULL), UNIQUE(task_id,command_id) ); CREATE TABLE %1$I.muse_role_session_authorization ( authorization_id uuid PRIMARY KEY REFERENCES %1$I.muse_raw_authorization(authorization_id), step_id text NOT NULL, stage text NOT NULL, initial_request_hash text NOT NULL, frozen_input_hash text NOT NULL, max_model_calls integer NOT NULL CHECK (max_model_calls>0), max_tool_calls integer NOT NULL CHECK (max_tool_calls>=0), policy_hash text NOT NULL ); CREATE TABLE %1$I.muse_raw_lease ( lease_id uuid PRIMARY KEY, task_id uuid NOT NULL REFERENCES %1$I.muse_task(task_id), authorization_id uuid NOT NULL REFERENCES %1$I.muse_raw_authorization(authorization_id), command_id text NOT NULL, created_at timestamptz NOT NULL, retain_until timestamptz NOT NULL, state text NOT NULL CHECK (state IN ('open','closed','migrating','migrated')), archive_id uuid, archive_authorization_id uuid REFERENCES %1$I.muse_raw_authorization(authorization_id), cleanup_receipt uuid, failure_code text, UNIQUE(task_id,command_id), CHECK (retain_until>created_at AND retain_until<=created_at+interval '24 hours') ); CREATE TABLE %1$I.muse_raw_archive ( archive_id uuid PRIMARY KEY, lease_id uuid UNIQUE REFERENCES %1$I.muse_raw_lease(lease_id), legacy_ref text UNIQUE, legacy_manifest jsonb, CHECK ((lease_id IS NULL) <> (legacy_ref IS NULL)), authorization_id uuid NOT NULL REFERENCES %1$I.muse_raw_authorization(authorization_id), tree_hash text NOT NULL, entry_count integer NOT NULL CHECK (entry_count>0), total_bytes bigint NOT NULL CHECK (total_bytes>=0), receipt_id uuid NOT NULL, created_at timestamptz NOT NULL ); CREATE TABLE %1$I.muse_raw_archive_item ( archive_id uuid NOT NULL REFERENCES %1$I.muse_raw_archive(archive_id), content_hash text NOT NULL, content bytea NOT NULL, PRIMARY KEY(archive_id,content_hash) ); CREATE TABLE %1$I.muse_runtime_evidence ( evidence_id uuid PRIMARY KEY, task_id uuid NOT NULL REFERENCES %1$I.muse_task(task_id), attempt_id uuid NOT NULL REFERENCES %1$I.muse_attempt(attempt_id), kind text NOT NULL CHECK (kind IN ('model_input','model_response','tool_result','failure')), reference_id text NOT NULL, content_hash text NOT NULL, content bytea, authorization_id uuid REFERENCES %1$I.muse_raw_authorization(authorization_id), outcome text NOT NULL CHECK (outcome IN ('completed','failed','partial')), metadata jsonb NOT NULL, revision integer NOT NULL DEFAULT 1, created_at timestamptz NOT NULL DEFAULT clock_timestamp(), UNIQUE(attempt_id,kind,reference_id), CHECK (content IS NULL OR authorization_id IS NOT NULL) ); $ddl$, namespace); EXECUTE format('REVOKE INSERT,UPDATE,DELETE ON %I.muse_raw_namespace FROM muse_app,muse_eval', namespace); END LOOP; END $raw_lifecycle$; DO $budget_config$ DECLARE namespace text; BEGIN FOREACH namespace IN ARRAY ARRAY['public', 'evaluation'] LOOP EXECUTE format($ddl$ CREATE TABLE %1$I.muse_budget_account ( run_purpose public.muse_purpose NOT NULL, account_id text NOT NULL, policy_version text NOT NULL, policy jsonb NOT NULL, policy_hash text NOT NULL, PRIMARY KEY (run_purpose, account_id) ); CREATE TABLE %1$I.muse_task_budget ( task_id uuid PRIMARY KEY REFERENCES %1$I.muse_task(task_id), account_id text NOT NULL, plan jsonb NOT NULL, plan_hash text NOT NULL, stopped boolean NOT NULL DEFAULT false ); CREATE TABLE %1$I.muse_budget_reservation ( run_purpose public.muse_purpose NOT NULL, call_id text NOT NULL, account_id text NOT NULL, task_id uuid NOT NULL REFERENCES %1$I.muse_task(task_id), attempt_id uuid NOT NULL REFERENCES %1$I.muse_attempt(attempt_id), role_id text NOT NULL, request_hash text NOT NULL, state text NOT NULL CHECK (state IN ('reserved','in_flight','unknown','settled','released')), reserved_amount numeric(24,6) NOT NULL CHECK (reserved_amount >= 0), actual_amount numeric(24,6) CHECK (actual_amount >= 0), window_start timestamptz NOT NULL, window_end timestamptz NOT NULL, expires_at timestamptz NOT NULL, sent_at timestamptz, receipt_id text, reason text, over_budget boolean NOT NULL DEFAULT false, PRIMARY KEY (run_purpose, call_id), CHECK ((state = 'settled') = (actual_amount IS NOT NULL)) ); CREATE INDEX ON %1$I.muse_budget_reservation (run_purpose,account_id,window_start); CREATE INDEX ON %1$I.muse_budget_reservation (task_id,role_id); CREATE TABLE %1$I.muse_runtime_config_version ( run_purpose public.muse_purpose NOT NULL, config_id text NOT NULL, version text NOT NULL, content jsonb NOT NULL, content_hash text NOT NULL, created_at timestamptz NOT NULL DEFAULT clock_timestamp(), PRIMARY KEY (run_purpose,config_id,version) ); CREATE TABLE %1$I.muse_runtime_config_validation ( receipt_id uuid PRIMARY KEY, run_purpose public.muse_purpose NOT NULL, config_id text NOT NULL, version text NOT NULL, content_hash text NOT NULL, validator_id text NOT NULL, evidence_refs jsonb NOT NULL, validated_at timestamptz NOT NULL DEFAULT clock_timestamp(), FOREIGN KEY (run_purpose,config_id,version) REFERENCES %1$I.muse_runtime_config_version(run_purpose,config_id,version) ); CREATE TABLE %1$I.muse_runtime_config_active ( run_purpose public.muse_purpose NOT NULL, config_id text NOT NULL, version text, validation_receipt uuid REFERENCES %1$I.muse_runtime_config_validation(receipt_id), approval_ref text, generation bigint NOT NULL DEFAULT 0, PRIMARY KEY (run_purpose,config_id) ); CREATE TABLE %1$I.muse_task_config_binding ( task_id uuid PRIMARY KEY REFERENCES %1$I.muse_task(task_id), config_id text NOT NULL, version text NOT NULL, content_hash text NOT NULL, content jsonb NOT NULL, validation_receipt uuid NOT NULL REFERENCES %1$I.muse_runtime_config_validation(receipt_id) ); $ddl$, namespace); END LOOP; END $budget_config$;