Files
UHD_Media_Tool/packages/db/migrations/0010_agent.ts
T
rootandClaude Fable 5.1 cc8b3a7df4 feat(db,contracts): full v0.1 data model migrations and shared zod contracts (W1-1)
- migrations 0002-0012 split by domain (foundation/instances/content/identity/
  sources/assets/policy/execution/agent/ops/organization): 41 tables, uuid pk,
  created_at/updated_at + touch trigger, text+CHECK status sets, pgcrypto/pg_trgm
- key constraints: source_release(site_id, site_release_id), observation(feed_id, guid),
  external_identity accepted partial unique, download_task(instance_id, torrent_hash),
  one active acquisition_plan per slot, one active path_binding per entity/season,
  asset_location root+path uniqueness, organization_record change_seq/change_xid cursor
- secret table (ciphertext/nonce/kdf) + secret_ref columns; outbox dispatch fields (ADR-002)
- src/types.ts generated from the migrated schema (scripts/gen-types.ts), drift-checked in tests;
  int8 -> number, date -> string parsers; migrator accepts migrationTableSchema
- contracts: Row/Create/Update schemas per domain, public organization-record API
  (changeSeq cursor), GlobalSettings, CapabilityDescriptor + 14 capability IO schemas,
  typed SSE events, Api endpoint table
- tests: migration up/down round trip on real PG in an isolated schema, constraint checks,
  contracts<->db column/enum sync, positive/negative parse for every exported schema

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 18:11:37 +08:00

126 lines
4.9 KiB
TypeScript

import type { Kysely } from "kysely";
import { dropTables, entityTable, execDdl, oneOf } from "../src/migration-helpers.ts";
// 人工/AI 域:decision(待处理中心)、approval、automation_grant、agent_run、artifact(REQ §10、§11.3、§11.4)
// 提案不直接晋升事实;审批绑定 plan ID + payload hash + expected revision;授权先落库再唤醒任务。
// biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型
export async function up(db: Kysely<any>): Promise<void> {
await execDdl(
db,
`
${entityTable(
"agent_run",
`
task_id uuid references task (id) on delete set null,
parent_run_id uuid references agent_run (id) on delete set null,
trigger text not null ${oneOf("trigger", ["user", "event", "schedule", "subagent"])},
goal text not null,
status text not null default 'queued' ${oneOf("status", ["queued", "running", "waiting", "succeeded", "failed", "cancelled", "budget_exceeded"])},
provider text,
model text,
thinking_level text,
scope jsonb not null default '{}'::jsonb,
budget jsonb not null default '{}'::jsonb,
usage jsonb not null default '{}'::jsonb,
evidence_version text,
session_state jsonb,
summary text,
tool_call_count integer not null default 0,
last_event_seq bigint not null default 0,
error jsonb,
cancel_requested_at timestamptz,
started_at timestamptz,
finished_at timestamptz,
created_by text`,
)}
create index agent_run_status_idx on agent_run (status);
create index agent_run_task_idx on agent_run (task_id) where task_id is not null;
create index agent_run_created_idx on agent_run (created_at desc);
${entityTable(
"artifact",
`
kind text not null ${oneOf("kind", ["evidence", "plan", "proposal", "report", "snapshot", "log"])},
agent_run_id uuid references agent_run (id) on delete set null,
task_id uuid references task (id) on delete set null,
subject_type text,
subject_id uuid,
title text not null,
mime_type text not null default 'application/json',
content jsonb not null default '{}'::jsonb,
content_hash text not null,
size_bytes bigint,
expires_at timestamptz`,
)}
create index artifact_run_idx on artifact (agent_run_id) where agent_run_id is not null;
create index artifact_subject_idx on artifact (subject_type, subject_id) where subject_id is not null;
${entityTable(
"decision",
`
kind text not null ${oneOf("kind", ["identity_ambiguous", "download_stalled", "download_failed", "path_conflict", "space_insufficient", "approval_required", "metadata_conflict", "source_unreachable", "other"])},
status text not null default 'open' ${oneOf("status", ["open", "investigating", "awaiting_user", "resolved", "dismissed", "expired"])},
severity text not null default 'warning' ${oneOf("severity", ["info", "warning", "critical"])},
title text not null,
summary text,
subject_type text,
subject_id uuid,
dedupe_key text not null,
evidence jsonb not null default '{}'::jsonb,
options jsonb not null default '[]'::jsonb,
resolution jsonb,
task_id uuid references task (id) on delete set null,
agent_run_id uuid references agent_run (id) on delete set null,
attempts integer not null default 0,
next_review_at timestamptz,
resolved_by text,
resolved_at timestamptz`,
)}
create unique index decision_dedupe_open_key on decision (dedupe_key) where status in ('open', 'investigating', 'awaiting_user');
create index decision_status_idx on decision (status, created_at desc);
create index decision_next_review_idx on decision (next_review_at) where next_review_at is not null;
${entityTable(
"approval",
`
plan_type text not null,
plan_id uuid not null,
payload_hash text not null,
expected_revision integer not null,
scope jsonb not null default '{}'::jsonb,
status text not null default 'pending' ${oneOf("status", ["pending", "approved", "rejected", "revoked", "expired", "consumed"])},
decision_id uuid references decision (id) on delete set null,
requested_by text not null,
decided_by text,
decided_at timestamptz,
expires_at timestamptz,
reason text`,
)}
create index approval_plan_idx on approval (plan_type, plan_id);
create index approval_pending_idx on approval (created_at) where status = 'pending';
${entityTable(
"automation_grant",
`
action text not null,
policy_revision_id uuid references policy_revision (id) on delete set null,
scope jsonb not null default '{}'::jsonb,
budget jsonb not null default '{}'::jsonb,
status text not null default 'active' ${oneOf("status", ["active", "revoked", "expired"])},
granted_by text not null,
reason text,
expires_at timestamptz,
revoked_at timestamptz,
revoked_by text`,
)}
create index automation_grant_active_idx on automation_grant (action) where status = 'active';
`,
);
}
// biome-ignore lint/suspicious/noExplicitAny: 同上
export async function down(db: Kysely<any>): Promise<void> {
await execDdl(db, dropTables(["automation_grant", "approval", "decision", "artifact", "agent_run"]));
}