muse-agent-example/数据库/迁移/V0004__任务运行与证据.sql
zizi f76c3cd04a docs(架构): 归档R2历史留痕并清理过程计划与实施分期标签
- 归档并收敛 R2 历史留痕至 docs/实现回顾/R2改造历史留痕.md,删除已退出生命周期的改造计划、旧文件处置及验证过程文档
- 现行测试用例身份收敛至 tests/用例清单.json(1358条扁平登记),适配 conftest、索引维护与测试执行验证
- 清理源码、配置、SQL迁移头、测试夹具及规则文档中的 Wxx 实施分期标签与过时过程描述
- 同步重新打包构建资源清单,通过全量离线测试、模块边界、类型检查与索引双向强核验
2026-09-16 19:09:14 +08:00

291 lines
14 KiB
SQL

-- 持久任务、步骤、尝试、独立作用域租约和有序事件。
-- 模型预算与原文生命周期随所属实现接入;用于当前开发基线。
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$;