From 00aa5e323878c505112c7b9f450f3cd702456754 Mon Sep 17 00:00:00 2001 From: zizi Date: Mon, 21 Sep 2026 21:09:28 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E4=BC=98=E5=8C=96(=E4=BA=A4=E4=BB=98?= =?UTF-8?q?=E8=BF=9E=E8=BD=BD):=20=E5=85=A8=E4=B9=A6=E6=95=B4=E7=90=86?= =?UTF-8?q?=E9=87=87=E7=94=A8=E6=89=B9=E9=87=8F=E5=BD=92=E5=B1=9E=E4=B8=8E?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E6=AD=A3=E6=96=87=E8=AF=BB=E5=8F=96=E5=B9=B6?= =?UTF-8?q?=E7=A7=BB=E5=87=BA=E7=BA=AF=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/muse/交付连载/全书整理.py | 19 ++- src/muse/交付连载/接口.py | 5 +- src/muse/作品规划/存储.py | 13 ++ src/muse/作品规划/接口.py | 23 ++++ src/muse/正文写作/存储.py | 16 +++ src/muse/正文写作/接口.py | 33 +++++- tests/单元/test_全书工作面批量读取.py | 163 ++++++++++++++++++++++++++ tests/用例清单.json | 64 ++++++++++ 8 files changed, 330 insertions(+), 6 deletions(-) create mode 100644 tests/单元/test_全书工作面批量读取.py diff --git a/src/muse/交付连载/全书整理.py b/src/muse/交付连载/全书整理.py index 0788c5b..527e66c 100644 --- a/src/muse/交付连载/全书整理.py +++ b/src/muse/交付连载/全书整理.py @@ -10,18 +10,26 @@ from muse.正文写作.接口 import ( 准备派生候选, 可见文本, 应用选段, + 批量读取当前正文依据, 段落哈希, 段落文本, - 读取当前正文依据, 读取正文依据, ) -def 全书工作面(连, author, work_id, *, names=None, exceptions=()): +def 读取全书数据(连, author, work_id): + """同事务批量获取目录与全书当前正文依据。""" directory = 读取作品范围(连, author, work_id) + chapter_ids = [c["chapter_id"] for c in directory["chapters"]] + body_map = 批量读取当前正文依据(连, author, work_id, chapter_ids) + return directory, body_map + + +def 整理全书工作面(work_id, directory, body_map, *, names=None, exceptions=()): + """纯内存整理工作面结构、段落偏移与文字疑点,不占用数据库连接。""" chapters, problems = [], [] for chapter in directory["chapters"]: - body = 读取当前正文依据(连, author, chapter["chapter_id"]) + body = body_map.get(chapter["chapter_id"]) if body is None: chapters.append({**chapter, "state": "missing", "revision": None}) problems.append({"chapter_id": chapter["chapter_id"], "kind": "missing_body"}) @@ -67,6 +75,11 @@ def 全书工作面(连, author, work_id, *, names=None, exceptions=()): } +def 全书工作面(连, author, work_id, *, names=None, exceptions=()): + directory, body_map = 读取全书数据(连, author, work_id) + return 整理全书工作面(work_id, directory, body_map, names=names, exceptions=exceptions) + + def 跨章候选身份(author, req, chapter): return str( uuid5( diff --git a/src/muse/交付连载/接口.py b/src/muse/交付连载/接口.py index 32a26eb..6856dc8 100644 --- a/src/muse/交付连载/接口.py +++ b/src/muse/交付连载/接口.py @@ -49,11 +49,12 @@ class 交付服务: raise 交付错误("SCOPE_DENIED", "交付需要生产用途的本作者身份") def 全书回看(self, 身份, work_id, *, names=None, exceptions=()): - from muse.交付连载.全书整理 import 全书工作面 + from muse.交付连载.全书整理 import 整理全书工作面, 读取全书数据 self.核对身份(身份) with self.数据库.连接(只读=True) as 连: - return 全书工作面(连, 身份.作者, work_id, names=names, exceptions=exceptions) + directory, body_map = 读取全书数据(连, 身份.作者, work_id) + return 整理全书工作面(work_id, directory, body_map, names=names, exceptions=exceptions) def 提出跨章修订(self, 身份, 命令ID, 请求: 全书修订): self.核对身份(身份) diff --git a/src/muse/作品规划/存储.py b/src/muse/作品规划/存储.py index bcf4295..a883b2a 100644 --- a/src/muse/作品规划/存储.py +++ b/src/muse/作品规划/存储.py @@ -242,6 +242,19 @@ class 作品存储: .fetchone() ) + def 批量读取章节归属(self, chapter_ids: list[str]) -> list[dict]: + if not chapter_ids: + return [] + return ( + self.连.cursor(row_factory=dict_row) + .execute( + "SELECT c.chapter_id,c.work_id,c.title,c.position,w.author_id,w.directory_revision " + "FROM muse_chapter c JOIN muse_work w USING(work_id) WHERE c.chapter_id=ANY(%s)", + (chapter_ids,), + ) + .fetchall() + ) + class 规划存储: def __init__(self, 连): diff --git a/src/muse/作品规划/接口.py b/src/muse/作品规划/接口.py index 6e9cef5..e97bb20 100644 --- a/src/muse/作品规划/接口.py +++ b/src/muse/作品规划/接口.py @@ -282,6 +282,28 @@ def 读取章节归属(连, 作者: str, chapter_id: str) -> dict: return {k: v for k, v in 行.items() if k != "author_id"} +def 批量核对章节归属( + 连, 作者: str, chapter_ids: list[str], *, work_id: str | None = None +) -> dict[str, dict]: + """同事务批量核对章节归属;任一不存在或越界整批拒绝,返回按 chapter_id 索引的字典。""" + if not chapter_ids: + return {} + 唯一ID = list(dict.fromkeys(chapter_ids)) + rows = 作品存储(连).批量读取章节归属(唯一ID) + if len(rows) != len(唯一ID): + 查到ID = {r["chapter_id"] for r in rows} + 缺失 = [cid for cid in 唯一ID if cid not in 查到ID] + raise 作品错误("CHAPTER_NOT_FOUND", f"章节不存在: {sorted(缺失)}") + 结果 = {} + for 行 in rows: + if 行["author_id"] != 作者: + raise 作品错误("SCOPE_DENIED", "章节不属于当前作者") + if work_id is not None and 行["work_id"] != work_id: + raise 作品错误("SCOPE_DENIED", "章节不属于指定作品") + 结果[行["chapter_id"]] = {k: v for k, v in 行.items() if k != "author_id"} + return 结果 + + def 读取有界作品范围(连, 作者: str, work_id: str, *, 数量上限: int, 字节上限: int) -> dict: """在同一语句限制目录传输;超限只交回数量/大小,调用方决定拒绝口径。""" from muse.作品规划.存储 import 作品存储 @@ -312,6 +334,7 @@ __all__ = [ "作品错误", "登记作品参与者", "读取章节归属", + "批量核对章节归属", "创作进度服务", "读取作品范围", "探索服务", diff --git a/src/muse/正文写作/存储.py b/src/muse/正文写作/存储.py index 83d306f..d9601d9 100644 --- a/src/muse/正文写作/存储.py +++ b/src/muse/正文写作/存储.py @@ -93,6 +93,22 @@ class 正文存储: .fetchone() ) + def 批量读取当前(self, chapter_ids: list[str], 分支: str = "main") -> list[dict]: + if not chapter_ids: + return [] + return ( + self.连.cursor(row_factory=dict_row) + .execute( + "SELECT d.document_id,d.chapter_id,d.branch_id,v.revision,v.document," + "v.document_hash,v.visible_text_hash,v.restored_from " + "FROM muse_document d JOIN muse_document_version v ON v.document_id=d.document_id " + "AND v.revision=d.current_revision " + "WHERE d.chapter_id=ANY(%s) AND d.branch_id=%s", + (chapter_ids, 分支), + ) + .fetchall() + ) + def 读取元数据(self, document_id: str, 版本: int) -> dict | None: """复检只返回版本和大小;数据库侧长度计算不承诺物理 I/O 上界。""" return ( diff --git a/src/muse/正文写作/接口.py b/src/muse/正文写作/接口.py index 477faea..4139bd9 100644 --- a/src/muse/正文写作/接口.py +++ b/src/muse/正文写作/接口.py @@ -3,7 +3,7 @@ from dataclasses import asdict from uuid import NAMESPACE_URL, uuid5 -from muse.作品规划.接口 import 读取章节归属 +from muse.作品规划.接口 import 批量核对章节归属, 读取章节归属 from muse.基础设施.数据库.连接 import 数据库工厂 from muse.正式变更.接口 import 作者动作, 参与者目录, 变更命令, 变更错误, 正式变更服务 from muse.正文写作.人工保存 import 文稿依赖, 正文保存入口, 正文参与者 @@ -66,6 +66,36 @@ def 读取当前正文依据(连, 作者: str, chapter_id: str, *, 分支: str = } +def 批量读取当前正文依据( + 连, + 作者: str, + work_id: str, + chapter_ids: list[str], + *, + 分支: str = "main", +) -> dict[str, dict]: + """批量核对章位归属后读取当前正式正文;未保存不返回条目,由调用方作为缺文处理。""" + if not chapter_ids: + return {} + 归属 = 批量核对章节归属(连, 作者, chapter_ids, work_id=work_id) + 存储 = 正文存储(连) + 行列表 = 存储.批量读取当前(list(归属.keys()), 分支=分支) + 结果 = {} + for 行 in 行列表: + cid = 行["chapter_id"] + id_ = 文稿身份(cid, 分支) + 结果[cid] = { + "work_id": work_id, + "document_id": id_, + "chapter_id": cid, + "revision": 行["revision"], + "current_revision": 行["revision"], + "document_hash": 行["document_hash"], + "document": 存储.恢复草稿(行), + } + return 结果 + + def 读取正文依据(连, 作者: str, chapter_id: str, revision: int, *, 分支: str = "main") -> dict: """事实及其他同事务消费者读取确切正文;同时返回当前指针供来源复检。""" 章节 = 读取章节归属(连, 作者, chapter_id) @@ -440,6 +470,7 @@ __all__ = [ "读取正文依据", "读取候选依据", "读取当前正文依据", + "批量读取当前正文依据", "文稿身份", "创建写作任务", "写入模型候选", diff --git a/tests/单元/test_全书工作面批量读取.py b/tests/单元/test_全书工作面批量读取.py new file mode 100644 index 0000000..5fef308 --- /dev/null +++ b/tests/单元/test_全书工作面批量读取.py @@ -0,0 +1,163 @@ +"""全书工作面批量读取与归属校验的独立机制验证。""" + +from dataclasses import asdict + +import pytest + +from muse.交付连载.全书整理 import 整理全书工作面 +from muse.作品规划.模型 import 作品错误 +from muse.正文写作.模型 import 正文草稿, 正文错误, 段落 +from muse.正文写作.正文格式 import 可见文本哈希, 正文结构哈希 + + +class 模拟连: + def __init__(self, chapters, *, author="author-1", work_id="work-1", missing=(), corrupt=()): + self.chapters = chapters + self.author = author + self.work_id = work_id + self.missing = set(missing) + self.corrupt = set(corrupt) + self.queries = [] + + def cursor(self, **_): + return self + + def execute(self, sql, params=()): + self.queries.append((sql, params)) + if "FROM muse_work w" in sql or "c.chapter_id=ANY(%s)" in sql: + # 批量读取章节归属 + ids = params[0] + rows = [] + for cid in ids: + if cid.startswith("nonexistent"): + continue + a = "wrong-author" if cid.startswith("wrong-author") else self.author + w = "wrong-work" if cid.startswith("wrong-work") else self.work_id + rows.append( + { + "chapter_id": cid, + "work_id": w, + "title": f"Title {cid}", + "position": 1, + "author_id": a, + "directory_revision": 1, + } + ) + self._rows = rows + return self + + if "FROM muse_document d JOIN muse_document_version v" in sql: + # 批量读取当前正文 + ids = params[0] + branch = params[1] + rows = [] + for cid in ids: + if cid in self.missing: + continue + draft = 正文草稿((段落(f"{cid}:p0", ()),)) + doc_hash = "bad_hash" if cid in self.corrupt else 正文结构哈希(draft) + vis_hash = 可见文本哈希(draft) + rows.append( + { + "document_id": f"doc-{cid}", + "chapter_id": cid, + "branch_id": branch, + "revision": 1, + "document": asdict(draft), + "document_hash": doc_hash, + "visible_text_hash": vis_hash, + "restored_from": None, + } + ) + self._rows = rows + return self + + self._rows = [] + return self + + def fetchall(self): + return getattr(self, "_rows", []) + + def fetchone(self): + rows = getattr(self, "_rows", []) + return rows[0] if rows else None + + +@pytest.mark.case_id("TC-DELIVERY-BATCH-AUTH-CHECK") +def test_批量核对章节归属异常分支(): + from muse.作品规划.接口 import 批量核对章节归属 + + # 1. 空列表直接返回 + 连 = 模拟连([]) + assert 批量核对章节归属(连, "author-1", []) == {} + + # 2. 章节不存在整批拒绝 + 连 = 模拟连([]) + with pytest.raises(作品错误) as exc: + 批量核对章节归属(连, "author-1", ["c1", "nonexistent-1"]) + assert exc.value.错误码 == "CHAPTER_NOT_FOUND" + + # 3. 章节不属于当前作者整批拒绝 + with pytest.raises(作品错误) as exc: + 批量核对章节归属(连, "author-1", ["c1", "wrong-author-c2"]) + assert exc.value.错误码 == "SCOPE_DENIED" + assert "章节不属于当前作者" in exc.value.说明 + + # 4. 章节不属于指定作品整批拒绝 + with pytest.raises(作品错误) as exc: + 批量核对章节归属(连, "author-1", ["c1", "wrong-work-c2"], work_id="work-1") + assert exc.value.错误码 == "SCOPE_DENIED" + assert "章节不属于指定作品" in exc.value.说明 + + +@pytest.mark.case_id("TC-DELIVERY-BATCH-CORRUPT-DETECT") +def test_批量读取正文损坏则报错(): + from muse.正文写作.接口 import 批量读取当前正文依据 + + 连 = 模拟连(["c1"], corrupt=["c1"]) + with pytest.raises(正文错误, match="已保存正文与其结构或文本哈希不一致"): + 批量读取当前正文依据(连, "author-1", "work-1", ["c1"]) + + +@pytest.mark.case_id("TC-DELIVERY-BATCH-READ-WORKBENCH") +def test_全书批量读取查询次数为常数上界(): + from muse.正文写作.接口 import 批量读取当前正文依据 + + # 100 章批量获取,SQL 查询次数恒定为 1 次批量归属 + 1 次批量正文 + c_ids = [f"ch-{i}" for i in range(100)] + 连 = 模拟连(c_ids) + 结果 = 批量读取当前正文依据(连, "author-1", "work-1", c_ids) + assert len(结果) == 100 + assert len(连.queries) == 2 # 1次批量核对归属 + 1次批量正文读取,而非 200 次! + + +@pytest.mark.case_id("TC-DELIVERY-WORKBENCH-MEM-SEPARATED") +def test_全书工作面组装正确区分状态(): + # 模拟包含正常章、缺正文章、空正文章 + directory = { + "revision": 5, + "chapters": [ + {"chapter_id": "c1", "title": "第一章", "position": 1}, + {"chapter_id": "c2", "title": "第二章", "position": 2}, + ], + } + # c1 正常,c2 缺失 + draft = 正文草稿((段落("c1:p0", ()),)) + body_map = { + "c1": { + "work_id": "work-1", + "document_id": "doc-c1", + "chapter_id": "c1", + "revision": 1, + "current_revision": 1, + "document_hash": 正文结构哈希(draft), + "document": draft, + } + } + res = 整理全书工作面("work-1", directory, body_map) + assert res["work_id"] == "work-1" + assert res["directory_revision"] == 5 + assert len(res["chapters"]) == 2 + assert res["chapters"][0]["state"] == "empty" # 空内容 + assert res["chapters"][1]["state"] == "missing" # 缺正文 + assert not res["can_freeze"] # 有 problem 不能冻结 diff --git a/tests/用例清单.json b/tests/用例清单.json index 57ed403..c9e5732 100644 --- a/tests/用例清单.json +++ b/tests/用例清单.json @@ -35317,6 +35317,70 @@ "数据库" ] }, + { + "case_id": "TC-DELIVERY-BATCH-AUTH-CHECK", + "file": "tests/单元/test_全书工作面批量读取.py", + "symbol": "test_批量核对章节归属异常分支", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_全书工作面批量读取.py::test_批量核对章节归属异常分支" + ], + "fixtures": [ + "request", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, + { + "case_id": "TC-DELIVERY-BATCH-CORRUPT-DETECT", + "file": "tests/单元/test_全书工作面批量读取.py", + "symbol": "test_批量读取正文损坏则报错", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_全书工作面批量读取.py::test_批量读取正文损坏则报错" + ], + "fixtures": [ + "request", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, + { + "case_id": "TC-DELIVERY-BATCH-READ-WORKBENCH", + "file": "tests/单元/test_全书工作面批量读取.py", + "symbol": "test_全书批量读取查询次数为常数上界", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_全书工作面批量读取.py::test_全书批量读取查询次数为常数上界" + ], + "fixtures": [ + "request", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, + { + "case_id": "TC-DELIVERY-WORKBENCH-MEM-SEPARATED", + "file": "tests/单元/test_全书工作面批量读取.py", + "symbol": "test_全书工作面组装正确区分状态", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_全书工作面批量读取.py::test_全书工作面组装正确区分状态" + ], + "fixtures": [ + "request", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, { "case_id": "TC-O08-SSE-001", "file": "tests/单元/test_任务事件收尾.py", From d5e338ad97f5c0b6e3e1c0b4f9b1e80e6b470d60 Mon Sep 17 00:00:00 2001 From: zizi Date: Mon, 21 Sep 2026 21:12:38 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E4=BC=98=E5=8C=96(=E5=89=8D=E7=AB=AF):=20?= =?UTF-8?q?=E6=B8=85=E7=90=86=E8=B5=84=E6=96=99=E7=A0=94=E7=A9=B6=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E5=86=B2=E7=AA=81=E5=B9=B6=E5=AE=9E=E6=96=BD=E5=85=A8?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E8=B7=AF=E7=94=B1=E6=87=92=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E4=B8=8E=E9=94=99=E8=AF=AF=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/功能/资料研究/数据.ts | 2 - web/src/功能/资料研究/资料页.tsx | 5 +- web/src/应用/路由.tsx | 248 ++++++++++++++++++++++--------- web/src/应用/页面错误边界.tsx | 62 ++++++++ web/tsconfig.tsbuildinfo | 2 +- 5 files changed, 245 insertions(+), 74 deletions(-) create mode 100644 web/src/应用/页面错误边界.tsx diff --git a/web/src/功能/资料研究/数据.ts b/web/src/功能/资料研究/数据.ts index a9d569b..21d93c5 100644 --- a/web/src/功能/资料研究/数据.ts +++ b/web/src/功能/资料研究/数据.ts @@ -118,7 +118,6 @@ export async function 发起拆书( 输入: { config_id: string; reason?: string | null }, ) { if (!输入.config_id.trim()) throw new Error("请明确指定已启用的分析配置。"); - const { 客户端 } = await import("../../接口/生成/客户端"); const { data, error } = await 客户端.POST( "/api/v1/sources/{source_id}/analyses", { @@ -136,7 +135,6 @@ export async function 发起拆书( } export async function 恢复拆书(taskId: string) { - const { 客户端 } = await import("../../接口/生成/客户端"); const { data, error } = await 客户端.POST( "/api/v1/analyses/{task_id}/resume", { diff --git a/web/src/功能/资料研究/资料页.tsx b/web/src/功能/资料研究/资料页.tsx index db7f2cd..629cd69 100644 --- a/web/src/功能/资料研究/资料页.tsx +++ b/web/src/功能/资料研究/资料页.tsx @@ -1,5 +1,6 @@ /** 资料对照页:来源版本原文、清理候选对照与榜单快照(含失败态)。 */ import { useState } from "react"; +import { 客户端 } from "../../接口/生成/客户端"; import { useMuse来源列表, useMuse版本原文 } from "./数据"; import { Ui反馈状态 } from "../../界面/反馈状态"; import { useMuse作者会话 } from "../../应用/作者会话"; @@ -14,12 +15,12 @@ export function Ui资料页() { async function 生成并应用(sourceId: string, revision: number) { try { - const { data, error } = await (await import("../../接口/生成/客户端")).客户端.POST( + const { data, error } = await 客户端.POST( "/api/v1/sources/{source_id}/versions/{revision}/clean-candidates", { params: { path: { source_id: sourceId, revision } } }, ); if (!data) throw new Error((error as { message?: string })?.message ?? "生成失败"); - const apply = await (await import("../../接口/生成/客户端")).客户端.POST( + const apply = await 客户端.POST( "/api/v1/clean-candidates/{candidate_id}/apply", { params: { path: { candidate_id: (data as { candidate_id: string }).candidate_id } } }, ); diff --git a/web/src/应用/路由.tsx b/web/src/应用/路由.tsx index 723eee0..4f493b2 100644 --- a/web/src/应用/路由.tsx +++ b/web/src/应用/路由.tsx @@ -1,76 +1,186 @@ +import { lazy, Suspense } from "react"; import { Navigate, Route, Routes } from "react-router-dom"; -import { Ui审校页, Ui声音页, Ui规则页 } from "../功能/审校修订"; -import { Ui任务列表 } from "../功能/任务运行"; -import { Ui实验页 } from "../功能/效果评测"; -import { - Ui作品首页, - Ui作品档案, - Ui探索工作区, - Ui规划工作区, -} from "../功能/作品规划"; -import { Ui候选审阅页, Ui正文页 } from "../功能/正文写作"; -import { Ui资料页, Ui拆书工作区, Ui榜单与选题页 } from "../功能/资料研究"; -import { Ui世界资料页, Ui人物关系页, Ui时间与伏笔页 } from "../功能/故事世界"; -import { Ui方法库页, Ui方法详情, Ui版本绑定 } from "../功能/知识方法"; -import { Ui偏好页, Ui反馈对照, Ui改进提案页 } from "../功能/作者经验"; -import { - Ui全书整理页, - Ui定稿导出页, - Ui连载计划页, - Ui读者反馈页, -} from "../功能/交付连载"; -import { Ui连接与模型页, Ui数据管理页, Ui备份恢复页 } from "../功能/系统管理"; +import { Ui反馈状态 } from "../界面/反馈状态"; +import { Ui页面错误边界 } from "./页面错误边界"; + +// 首屏核心静态保留:轻量作品列表 +import { Ui作品首页 } from "../功能/作品规划/作品首页"; + +// 其余功能页路由级懒加载(精准具体页面入口,避免聚合出口产生重叠打包) +const Ui探索工作区 = lazy(() => + import("../功能/作品规划/探索工作区").then((m) => ({ default: m.Ui探索工作区 })), +); +const Ui作品档案 = lazy(() => + import("../功能/作品规划/作品档案").then((m) => ({ default: m.Ui作品档案 })), +); +const Ui规划工作区 = lazy(() => + import("../功能/作品规划/规划工作区").then((m) => ({ default: m.Ui规划工作区 })), +); + +// 正文写作与审阅(含富文本编辑器重依赖) +const Ui正文页 = lazy(() => + import("../功能/正文写作/正文页").then((m) => ({ default: m.Ui正文页 })), +); +const Ui候选审阅页 = lazy(() => + import("../功能/正文写作/候选审阅").then((m) => ({ default: m.Ui候选审阅页 })), +); + +// 审校修订 +const Ui审校页 = lazy(() => + import("../功能/审校修订/审校页").then((m) => ({ default: m.Ui审校页 })), +); +const Ui声音页 = lazy(() => + import("../功能/审校修订/声音档案").then((m) => ({ default: m.Ui声音页 })), +); +const Ui规则页 = lazy(() => + import("../功能/审校修订/规则页").then((m) => ({ default: m.Ui规则页 })), +); + +// 任务运行与效果评测 +const Ui任务列表 = lazy(() => + import("../功能/任务运行/任务列表").then((m) => ({ default: m.Ui任务列表 })), +); +const Ui实验页 = lazy(() => + import("../功能/效果评测/实验页").then((m) => ({ default: m.Ui实验页 })), +); + +// 故事世界 +const Ui世界资料页 = lazy(() => + import("../功能/故事世界/世界资料页").then((m) => ({ default: m.Ui世界资料页 })), +); +const Ui人物关系页 = lazy(() => + import("../功能/故事世界/人物关系页").then((m) => ({ default: m.Ui人物关系页 })), +); +const Ui时间与伏笔页 = lazy(() => + import("../功能/故事世界/时间与伏笔页").then((m) => ({ default: m.Ui时间与伏笔页 })), +); + +// 资料研究 +const Ui资料页 = lazy(() => + import("../功能/资料研究/资料页").then((m) => ({ default: m.Ui资料页 })), +); +const Ui拆书工作区 = lazy(() => + import("../功能/资料研究/拆书工作区").then((m) => ({ default: m.Ui拆书工作区 })), +); +const Ui榜单与选题页 = lazy(() => + import("../功能/资料研究/榜单与选题页").then((m) => ({ default: m.Ui榜单与选题页 })), +); + +// 知识方法 +const Ui方法库页 = lazy(() => + import("../功能/知识方法/方法库页").then((m) => ({ default: m.Ui方法库页 })), +); +const Ui方法详情 = lazy(() => + import("../功能/知识方法/方法详情").then((m) => ({ default: m.Ui方法详情 })), +); +const Ui版本绑定 = lazy(() => + import("../功能/知识方法/版本绑定").then((m) => ({ default: m.Ui版本绑定 })), +); + +// 交付连载 +const Ui全书整理页 = lazy(() => + import("../功能/交付连载/全书整理页").then((m) => ({ default: m.Ui全书整理页 })), +); +const Ui定稿导出页 = lazy(() => + import("../功能/交付连载/定稿导出页").then((m) => ({ default: m.Ui定稿导出页 })), +); +const Ui连载计划页 = lazy(() => + import("../功能/交付连载/连载计划页").then((m) => ({ default: m.Ui连载计划页 })), +); +const Ui读者反馈页 = lazy(() => + import("../功能/交付连载/读者反馈页").then((m) => ({ default: m.Ui读者反馈页 })), +); + +// 系统管理 +const Ui连接与模型页 = lazy(() => + import("../功能/系统管理/连接与模型页").then((m) => ({ default: m.Ui连接与模型页 })), +); +const Ui数据管理页 = lazy(() => + import("../功能/系统管理/数据管理页").then((m) => ({ default: m.Ui数据管理页 })), +); +const Ui备份恢复页 = lazy(() => + import("../功能/系统管理/备份恢复页").then((m) => ({ default: m.Ui备份恢复页 })), +); + +// 作者经验 +const Ui偏好页 = lazy(() => + import("../功能/作者经验/偏好页").then((m) => ({ default: m.Ui偏好页 })), +); +const Ui反馈对照 = lazy(() => + import("../功能/作者经验/反馈对照").then((m) => ({ default: m.Ui反馈对照 })), +); +const Ui改进提案页 = lazy(() => + import("../功能/作者经验/改进提案页").then((m) => ({ default: m.Ui改进提案页 })), +); export function Ui页面路由() { return ( - - } /> - } /> - } /> - } /> - } /> - } - /> - } /> - } /> - } /> - } - /> - } /> - } - /> - } /> - } /> - } /> - } /> - } - /> - } - /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - + + +
+ +
+ + } + > + + } /> + } /> + } /> + } /> + } + /> + } + /> + } /> + } /> + } /> + } + /> + } /> + } + /> + } /> + } /> + } /> + } /> + } + /> + } + /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + } /> + +
+
); } diff --git a/web/src/应用/页面错误边界.tsx b/web/src/应用/页面错误边界.tsx new file mode 100644 index 0000000..1cf7a39 --- /dev/null +++ b/web/src/应用/页面错误边界.tsx @@ -0,0 +1,62 @@ +import { Component, type ErrorInfo, type ReactNode } from "react"; +import { Ui反馈状态 } from "../界面/反馈状态"; + +interface Props { + children: ReactNode; +} + +interface State { + hasError: boolean; + error: Error | null; +} + +export class Ui页面错误边界 extends Component { + constructor(props: Props) { + super(props); + this.state = { hasError: false, error: null }; + } + + static getDerivedStateFromError(error: Error): State { + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error("页面加载或渲染失败:", error, errorInfo); + } + + 重试 = () => { + this.setState({ hasError: false, error: null }); + }; + + render() { + if (this.state.hasError) { + return ( +
+
+
+

加载受阻

+

页面未正常载入

+

可能是网络暂时中断或应用版本已更新。

+
+
+ +
+ + +
+
+ ); + } + return this.props.children; + } +} diff --git a/web/tsconfig.tsbuildinfo b/web/tsconfig.tsbuildinfo index 5056fac..7ef35ad 100644 --- a/web/tsconfig.tsbuildinfo +++ b/web/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/功能/上下文/index.ts","./src/功能/上下文/上下文清单.tsx","./src/功能/上下文/数据.ts","./src/功能/上下文/来源证据面板.tsx","./src/功能/交付连载/index.ts","./src/功能/交付连载/全书整理页.tsx","./src/功能/交付连载/定稿导出页.tsx","./src/功能/交付连载/数据.ts","./src/功能/交付连载/读者反馈页.tsx","./src/功能/交付连载/跨章校对.tsx","./src/功能/交付连载/连载计划页.tsx","./src/功能/任务运行/index.ts","./src/功能/任务运行/任务列表.tsx","./src/功能/任务运行/任务订阅.ts","./src/功能/任务运行/任务详情.tsx","./src/功能/任务运行/任务预算.tsx","./src/功能/任务运行/恢复控制.tsx","./src/功能/任务运行/数据.ts","./src/功能/任务运行/调用账目.tsx","./src/功能/作品规划/index.ts","./src/功能/作品规划/作品档案.tsx","./src/功能/作品规划/作品首页.tsx","./src/功能/作品规划/探索工作区.tsx","./src/功能/作品规划/数据.ts","./src/功能/作品规划/章节目录.tsx","./src/功能/作品规划/节点规划.tsx","./src/功能/作品规划/规划工作区.tsx","./src/功能/作者经验/index.ts","./src/功能/作者经验/偏好页.tsx","./src/功能/作者经验/反馈对照.tsx","./src/功能/作者经验/改进提案页.tsx","./src/功能/作者经验/数据.ts","./src/功能/作者经验/新规则改进.tsx","./src/功能/作者经验/运行观察.tsx","./src/功能/作者经验/长期观察.tsx","./src/功能/创作对话/index.ts","./src/功能/创作对话/会话面板.tsx","./src/功能/创作对话/作者动作.tsx","./src/功能/创作对话/数据.ts","./src/功能/创作对话/消息流.tsx","./src/功能/审校修订/index.ts","./src/功能/审校修订/修订对照.tsx","./src/功能/审校修订/声音档案.tsx","./src/功能/审校修订/审校页.tsx","./src/功能/审校修订/数据.ts","./src/功能/审校修订/有限返修.tsx","./src/功能/审校修订/独立比较.tsx","./src/功能/审校修订/规则启用.tsx","./src/功能/审校修订/规则页.tsx","./src/功能/审校修订/问题清单.tsx","./src/功能/故事世界/index.ts","./src/功能/故事世界/世界资料页.tsx","./src/功能/故事世界/事实审阅.tsx","./src/功能/故事世界/人物关系页.tsx","./src/功能/故事世界/实体编辑器.tsx","./src/功能/故事世界/数据.ts","./src/功能/故事世界/时间与伏笔页.tsx","./src/功能/效果评测/index.ts","./src/功能/效果评测/实验页.tsx","./src/功能/效果评测/效果判定.tsx","./src/功能/效果评测/数据.ts","./src/功能/效果评测/混淆观察.tsx","./src/功能/效果评测/逐例比较.tsx","./src/功能/正式变更/index.ts","./src/功能/正式变更/决策面板.tsx","./src/功能/正式变更/审阅控制.ts","./src/功能/正式变更/数据.ts","./src/功能/正文写作/index.ts","./src/功能/正文写作/保存控制.ts","./src/功能/正文写作/候选审阅.tsx","./src/功能/正文写作/候选缓冲.ts","./src/功能/正文写作/数据.ts","./src/功能/正文写作/正文页.tsx","./src/功能/正文写作/版本分支.tsx","./src/功能/正文写作/版本比较.tsx","./src/功能/正文写作/编辑会话.ts","./src/功能/正文写作/编辑缓冲.ts","./src/功能/正文写作/路由参数.ts","./src/功能/正文写作/选段改写.tsx","./src/功能/知识方法/index.ts","./src/功能/知识方法/数据.ts","./src/功能/知识方法/方法库页.tsx","./src/功能/知识方法/方法详情.tsx","./src/功能/知识方法/版本绑定.tsx","./src/功能/系统管理/index.ts","./src/功能/系统管理/备份恢复页.tsx","./src/功能/系统管理/数据.ts","./src/功能/系统管理/数据管理页.tsx","./src/功能/系统管理/连接与模型页.tsx","./src/功能/资料研究/index.ts","./src/功能/资料研究/原文分析对照.tsx","./src/功能/资料研究/拆书工作区.tsx","./src/功能/资料研究/数据.ts","./src/功能/资料研究/榜单与选题页.tsx","./src/功能/资料研究/资料页.tsx","./src/应用/作品会话.ts","./src/应用/作者会话.ts","./src/应用/依赖装配.tsx","./src/应用/工作台布局.tsx","./src/应用/应用.tsx","./src/应用/路由.tsx","./src/接口/事件连接.ts","./src/接口/传输.ts","./src/接口/查询键.ts","./src/接口/生成/客户端.ts","./src/接口/生成/类型.ts","./src/界面/关系图.tsx","./src/界面/反馈状态.tsx","./src/界面/结构表单/字段渲染.tsx","./src/界面/结构表单/投影会话.ts","./src/界面/结构表单/结构表单.tsx","./src/界面/编辑器/字符位置.ts","./src/界面/编辑器/文档适配.ts","./src/界面/编辑器/正文编辑器.tsx","./src/界面/编辑器/粘贴处理.ts","./src/界面/编辑器/选区定位.ts","./tests/设置.ts","./tests/交互/上下文材料.test.tsx","./tests/交互/世界实体编辑.test.tsx","./tests/交互/交付连载.test.tsx","./tests/交互/任务订阅生命周期.test.tsx","./tests/交互/作者偏好.test.tsx","./tests/交互/候选审阅.test.tsx","./tests/交互/候选摘要分页.test.tsx","./tests/交互/具体改进.test.tsx","./tests/交互/分析配置.test.ts","./tests/交互/切作品隔离.test.tsx","./tests/交互/创作对话.test.tsx","./tests/交互/动态字段与结构过期.test.tsx","./tests/交互/审校报告呈现.test.tsx","./tests/交互/方法启用.test.tsx","./tests/交互/有限返修.test.tsx","./tests/交互/系统管理.test.tsx","./tests/交互/规划重看基线.test.tsx","./tests/交互/规则启用.test.tsx","./tests/交互/规则改进.test.tsx","./tests/交互/评测报告.test.tsx","./tests/交互/调用账目.test.tsx","./tests/交互/运行观察.test.tsx","./tests/交互/返修比较记录.test.tsx","./tests/交互/退出会话.test.tsx","./tests/交互/选区定位.test.ts","./tests/单元/中文显示与动作.test.tsx","./tests/单元/旅程环境.test.ts","./tests/单元/路由参数.test.tsx","./tests/旅程/世界维护.spec.ts","./tests/旅程/人工创作.spec.ts","./tests/旅程/任务材料.spec.ts","./tests/旅程/任务预算与推进.spec.ts","./tests/旅程/作者偏好.spec.ts","./tests/旅程/作者审校.spec.ts","./tests/旅程/候选审阅.spec.ts","./tests/旅程/具体改进.spec.ts","./tests/旅程/分支缓冲与事件收尾.spec.ts","./tests/旅程/动态类型到事实确认.spec.ts","./tests/旅程/备份恢复.spec.ts","./tests/旅程/定稿连载.spec.ts","./tests/旅程/探索草稿.spec.ts","./tests/旅程/方法启用.spec.ts","./tests/旅程/方法库.spec.ts","./tests/旅程/有限返修.spec.ts","./tests/旅程/生成对话.spec.ts","./tests/旅程/系统管理.spec.ts","./tests/旅程/规划生成.spec.ts","./tests/旅程/规则启用.spec.ts","./tests/旅程/规则改进.spec.ts","./tests/旅程/评测报告.spec.ts","./tests/旅程/资料对照.spec.ts","./tests/旅程/运行观察.spec.ts","./tests/旅程/返修独立比较.spec.ts","./tests/编辑/中文输入.test.tsx","./tests/编辑/保存冲突.test.tsx","./tests/编辑/候选缓冲.test.ts","./tests/编辑/历史回退.test.tsx","./tests/编辑/断网缓冲.test.tsx","./tests/编辑/正文往返.test.ts","./tests/编辑/编辑事务.test.tsx","./tests/编辑/编辑热路径.test.tsx","./tests/编辑/选区转换.test.ts"],"version":"5.9.3"} \ No newline at end of file +{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/功能/上下文/index.ts","./src/功能/上下文/上下文清单.tsx","./src/功能/上下文/数据.ts","./src/功能/上下文/来源证据面板.tsx","./src/功能/交付连载/index.ts","./src/功能/交付连载/全书整理页.tsx","./src/功能/交付连载/定稿导出页.tsx","./src/功能/交付连载/数据.ts","./src/功能/交付连载/读者反馈页.tsx","./src/功能/交付连载/跨章校对.tsx","./src/功能/交付连载/连载计划页.tsx","./src/功能/任务运行/index.ts","./src/功能/任务运行/任务列表.tsx","./src/功能/任务运行/任务订阅.ts","./src/功能/任务运行/任务详情.tsx","./src/功能/任务运行/任务预算.tsx","./src/功能/任务运行/恢复控制.tsx","./src/功能/任务运行/数据.ts","./src/功能/任务运行/调用账目.tsx","./src/功能/作品规划/index.ts","./src/功能/作品规划/作品档案.tsx","./src/功能/作品规划/作品首页.tsx","./src/功能/作品规划/探索工作区.tsx","./src/功能/作品规划/数据.ts","./src/功能/作品规划/章节目录.tsx","./src/功能/作品规划/节点规划.tsx","./src/功能/作品规划/规划工作区.tsx","./src/功能/作者经验/index.ts","./src/功能/作者经验/偏好页.tsx","./src/功能/作者经验/反馈对照.tsx","./src/功能/作者经验/改进提案页.tsx","./src/功能/作者经验/数据.ts","./src/功能/作者经验/新规则改进.tsx","./src/功能/作者经验/运行观察.tsx","./src/功能/作者经验/长期观察.tsx","./src/功能/创作对话/index.ts","./src/功能/创作对话/会话面板.tsx","./src/功能/创作对话/作者动作.tsx","./src/功能/创作对话/数据.ts","./src/功能/创作对话/消息流.tsx","./src/功能/审校修订/index.ts","./src/功能/审校修订/修订对照.tsx","./src/功能/审校修订/声音档案.tsx","./src/功能/审校修订/审校页.tsx","./src/功能/审校修订/数据.ts","./src/功能/审校修订/有限返修.tsx","./src/功能/审校修订/独立比较.tsx","./src/功能/审校修订/规则启用.tsx","./src/功能/审校修订/规则页.tsx","./src/功能/审校修订/问题清单.tsx","./src/功能/故事世界/index.ts","./src/功能/故事世界/世界资料页.tsx","./src/功能/故事世界/事实审阅.tsx","./src/功能/故事世界/人物关系页.tsx","./src/功能/故事世界/实体编辑器.tsx","./src/功能/故事世界/数据.ts","./src/功能/故事世界/时间与伏笔页.tsx","./src/功能/效果评测/index.ts","./src/功能/效果评测/实验页.tsx","./src/功能/效果评测/效果判定.tsx","./src/功能/效果评测/数据.ts","./src/功能/效果评测/混淆观察.tsx","./src/功能/效果评测/逐例比较.tsx","./src/功能/正式变更/index.ts","./src/功能/正式变更/决策面板.tsx","./src/功能/正式变更/审阅控制.ts","./src/功能/正式变更/数据.ts","./src/功能/正文写作/index.ts","./src/功能/正文写作/保存控制.ts","./src/功能/正文写作/候选审阅.tsx","./src/功能/正文写作/候选缓冲.ts","./src/功能/正文写作/数据.ts","./src/功能/正文写作/正文页.tsx","./src/功能/正文写作/版本分支.tsx","./src/功能/正文写作/版本比较.tsx","./src/功能/正文写作/编辑会话.ts","./src/功能/正文写作/编辑缓冲.ts","./src/功能/正文写作/路由参数.ts","./src/功能/正文写作/选段改写.tsx","./src/功能/知识方法/index.ts","./src/功能/知识方法/数据.ts","./src/功能/知识方法/方法库页.tsx","./src/功能/知识方法/方法详情.tsx","./src/功能/知识方法/版本绑定.tsx","./src/功能/系统管理/index.ts","./src/功能/系统管理/备份恢复页.tsx","./src/功能/系统管理/数据.ts","./src/功能/系统管理/数据管理页.tsx","./src/功能/系统管理/连接与模型页.tsx","./src/功能/资料研究/index.ts","./src/功能/资料研究/原文分析对照.tsx","./src/功能/资料研究/拆书工作区.tsx","./src/功能/资料研究/数据.ts","./src/功能/资料研究/榜单与选题页.tsx","./src/功能/资料研究/资料页.tsx","./src/应用/作品会话.ts","./src/应用/作者会话.ts","./src/应用/依赖装配.tsx","./src/应用/工作台布局.tsx","./src/应用/应用.tsx","./src/应用/路由.tsx","./src/应用/页面错误边界.tsx","./src/接口/事件连接.ts","./src/接口/传输.ts","./src/接口/查询键.ts","./src/接口/生成/客户端.ts","./src/接口/生成/类型.ts","./src/界面/关系图.tsx","./src/界面/反馈状态.tsx","./src/界面/结构表单/字段渲染.tsx","./src/界面/结构表单/投影会话.ts","./src/界面/结构表单/结构表单.tsx","./src/界面/编辑器/字符位置.ts","./src/界面/编辑器/文档适配.ts","./src/界面/编辑器/正文编辑器.tsx","./src/界面/编辑器/粘贴处理.ts","./src/界面/编辑器/选区定位.ts","./tests/设置.ts","./tests/交互/上下文材料.test.tsx","./tests/交互/世界实体编辑.test.tsx","./tests/交互/交付连载.test.tsx","./tests/交互/任务订阅生命周期.test.tsx","./tests/交互/作者偏好.test.tsx","./tests/交互/候选审阅.test.tsx","./tests/交互/候选摘要分页.test.tsx","./tests/交互/具体改进.test.tsx","./tests/交互/分析配置.test.ts","./tests/交互/切作品隔离.test.tsx","./tests/交互/创作对话.test.tsx","./tests/交互/动态字段与结构过期.test.tsx","./tests/交互/审校报告呈现.test.tsx","./tests/交互/方法启用.test.tsx","./tests/交互/有限返修.test.tsx","./tests/交互/系统管理.test.tsx","./tests/交互/规划重看基线.test.tsx","./tests/交互/规则启用.test.tsx","./tests/交互/规则改进.test.tsx","./tests/交互/评测报告.test.tsx","./tests/交互/调用账目.test.tsx","./tests/交互/运行观察.test.tsx","./tests/交互/返修比较记录.test.tsx","./tests/交互/退出会话.test.tsx","./tests/交互/选区定位.test.ts","./tests/单元/中文显示与动作.test.tsx","./tests/单元/旅程环境.test.ts","./tests/单元/路由参数.test.tsx","./tests/旅程/世界维护.spec.ts","./tests/旅程/人工创作.spec.ts","./tests/旅程/任务材料.spec.ts","./tests/旅程/任务预算与推进.spec.ts","./tests/旅程/作者偏好.spec.ts","./tests/旅程/作者审校.spec.ts","./tests/旅程/候选审阅.spec.ts","./tests/旅程/具体改进.spec.ts","./tests/旅程/分支缓冲与事件收尾.spec.ts","./tests/旅程/动态类型到事实确认.spec.ts","./tests/旅程/备份恢复.spec.ts","./tests/旅程/定稿连载.spec.ts","./tests/旅程/探索草稿.spec.ts","./tests/旅程/方法启用.spec.ts","./tests/旅程/方法库.spec.ts","./tests/旅程/有限返修.spec.ts","./tests/旅程/生成对话.spec.ts","./tests/旅程/系统管理.spec.ts","./tests/旅程/规划生成.spec.ts","./tests/旅程/规则启用.spec.ts","./tests/旅程/规则改进.spec.ts","./tests/旅程/评测报告.spec.ts","./tests/旅程/资料对照.spec.ts","./tests/旅程/运行观察.spec.ts","./tests/旅程/返修独立比较.spec.ts","./tests/编辑/中文输入.test.tsx","./tests/编辑/保存冲突.test.tsx","./tests/编辑/候选缓冲.test.ts","./tests/编辑/历史回退.test.tsx","./tests/编辑/断网缓冲.test.tsx","./tests/编辑/正文往返.test.ts","./tests/编辑/编辑事务.test.tsx","./tests/编辑/编辑热路径.test.tsx","./tests/编辑/选区转换.test.ts"],"version":"5.9.3"} \ No newline at end of file From 1571abad43bb97d4ee2f3a408cff33b1ae3b793d Mon Sep 17 00:00:00 2001 From: zizi Date: Mon, 21 Sep 2026 21:17:23 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E4=BC=98=E5=8C=96(=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E6=B1=A0=E4=B8=8ESSE):=20=E8=BF=9E=E6=8E=A5=E6=B1=A0=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=8B=AC=E7=AB=8B=E8=A7=A3=E8=80=A6=E4=B8=8E=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E5=8F=82=E6=95=B0=E5=8C=96=EF=BC=8CSSE=E7=A9=BA?= =?UTF-8?q?=E8=BD=AE=E8=AF=A2=E5=B9=B3=E6=BB=91=E9=80=80=E9=81=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/muse/启动.py | 10 +- src/muse/接入/http/事件订阅.py | 7 +- src/muse/配置.py | 44 +++++- tests/单元/test_连接池配置与退避.py | 217 ++++++++++++++++++++++++++++ tests/用例清单.json | 66 +++++++++ 5 files changed, 341 insertions(+), 3 deletions(-) create mode 100644 tests/单元/test_连接池配置与退避.py diff --git a/src/muse/启动.py b/src/muse/启动.py index 9031def..9391e1c 100644 --- a/src/muse/启动.py +++ b/src/muse/启动.py @@ -239,11 +239,19 @@ class 应用装配: def 构建(配置: 应用配置, *, 时钟: 时钟 | None = None, 流程: 流程登记 | None = None) -> 应用装配: """注入按用途绑定的数据库工厂;装配与自检不建立连接。""" + 最大连接 = 配置.连接池.最大连接 + if 最大连接 is None: + 最大连接 = 2 if 配置.运行用途.value == "evaluation" else 4 + 等待秒 = 配置.连接池.等待秒 + if 等待秒 is None: + 等待秒 = 2.0 + 数据库 = 数据库工厂( 配置.数据库, 配置.运行用途, 常驻=True, - 最大连接=2 if 配置.运行用途.value == "evaluation" else 4, + 最大连接=最大连接, + 等待秒=等待秒, ) 目录 = 参与者目录() 登记作品参与者(目录, 探索服务(Path(配置.探索草稿)) if 配置.探索草稿 else None, 解析本书规划引用) diff --git a/src/muse/接入/http/事件订阅.py b/src/muse/接入/http/事件订阅.py index 2aa8840..cd69dd6 100644 --- a/src/muse/接入/http/事件订阅.py +++ b/src/muse/接入/http/事件订阅.py @@ -79,6 +79,7 @@ async def 订阅事件( async def 数据流(): 游标 = max(cursor, last_event_id or 0) + 空轮询次数 = 0 while not await request.is_disconnected(): 结果 = await run_in_threadpool(服务.续接事件, task_id, 游标) 页 = 呈现事件(结果) @@ -100,7 +101,11 @@ async def 订阅事件( return if not 页.items: yield ": keep-alive\n\n" - await asyncio.sleep(1) + 空轮询次数 += 1 + else: + 空轮询次数 = 0 + 等待秒 = 2.0 if (protocol == "bounded-v2" and 空轮询次数 >= 2) else 1.0 + await asyncio.sleep(等待秒) return StreamingResponse( 数据流(), diff --git a/src/muse/配置.py b/src/muse/配置.py index 23e3590..329345b 100644 --- a/src/muse/配置.py +++ b/src/muse/配置.py @@ -9,6 +9,7 @@ from __future__ import annotations +import math import tomllib from dataclasses import dataclass, replace from pathlib import Path @@ -21,6 +22,25 @@ from muse.共享.错误 import 配置错误 _允许的取值方式 = frozenset({"环境变量", "受控存储"}) +@dataclass(frozen=True, slots=True) +class 连接池配置: + """运行连接池参数;独立于凭据引用,不参与数据库目标身份相等比较。""" + + 最大连接: int | None = None + 等待秒: float | None = None + + def __post_init__(self) -> None: + if self.最大连接 is not None: + if type(self.最大连接) is not int or self.最大连接 <= 0 or self.最大连接 > 100: + raise 配置错误("连接池.最大连接 必须是 1 到 100 之间的整数") + if self.等待秒 is not None: + if not isinstance(self.等待秒, (int, float)) or type(self.等待秒) is bool: + raise 配置错误("连接池.等待秒 必须是有效数值") + val = float(self.等待秒) + if math.isnan(val) or math.isinf(val) or not (0.1 <= val <= 60.0): + raise 配置错误("连接池.等待秒 必须在 0.1 到 60.0 之间的有限数值") + + @dataclass(frozen=True, slots=True) class 数据库引用: """数据库连接引用:只记录取值方式与位置,不含连接串明文。""" @@ -83,6 +103,7 @@ class 应用配置: 探索草稿: str | None = None 备份目录: str | None = None 运行装配: 运行装配配置 = 运行装配配置() + 连接池: 连接池配置 = 连接池配置() def __post_init__(self) -> None: if not self.资源发布身份.strip(): @@ -130,6 +151,18 @@ def 解析配置(数据: dict[str, Any]) -> 应用配置: 运行装配 = 运行装配配置(**装配节) except TypeError as exc: raise 配置错误("运行装配配置字段不合法") from exc + 池节 = 数据.get("数据库", {}).get("连接池") + if 池节 is None: + 池节 = 数据.get("连接池") + if 池节 is not None: + if not isinstance(池节, dict): + raise 配置错误("数据库.连接池 必须是映射结构") + try: + 连接池 = 连接池配置(**池节) + except TypeError as exc: + raise 配置错误("数据库.连接池 字段不合法") from exc + else: + 连接池 = 连接池配置() return 应用配置( 数据库=_校验数据库节(数据["数据库"]), 资源发布身份=发布身份, @@ -139,6 +172,7 @@ def 解析配置(数据: dict[str, Any]) -> 应用配置: 探索草稿=数据.get("文件", {}).get("探索草稿"), 备份目录=数据.get("文件", {}).get("备份目录"), 运行装配=运行装配, + 连接池=连接池, ) @@ -187,4 +221,12 @@ def 读取配置(路径: str | Path) -> 应用配置: return 配置 -__all__ = ["数据库引用", "应用配置", "服务配置", "运行装配配置", "解析配置", "读取配置"] +__all__ = [ + "数据库引用", + "连接池配置", + "应用配置", + "服务配置", + "运行装配配置", + "解析配置", + "读取配置", +] diff --git a/tests/单元/test_连接池配置与退避.py b/tests/单元/test_连接池配置与退避.py new file mode 100644 index 0000000..ed76a8c --- /dev/null +++ b/tests/单元/test_连接池配置与退避.py @@ -0,0 +1,217 @@ +"""连接池配置解耦、校验及 SSE 空轮询退避机制验证。""" + +import asyncio + +import pytest + +from muse.共享.错误 import 配置错误 +from muse.配置 import 数据库引用, 解析配置, 连接池配置 + + +@pytest.mark.case_id("TC-POOL-CONFIG-VALIDATION") +def test_连接池配置字段强校验(): + # 正常值 + cfg = 连接池配置(最大连接=8, 等待秒=5.0) + assert cfg.最大连接 == 8 + assert cfg.等待秒 == 5.0 + + # 最大连接不接受非 int、bool、越界 + with pytest.raises(配置错误, match="连接池.最大连接"): + 连接池配置(最大连接=True) # type: ignore + with pytest.raises(配置错误, match="连接池.最大连接"): + 连接池配置(最大连接=0) + with pytest.raises(配置错误, match="连接池.最大连接"): + 连接池配置(最大连接=101) + with pytest.raises(配置错误, match="连接池.最大连接"): + 连接池配置(最大连接="8") # type: ignore + + # 等待秒不接受 bool、NaN、Inf、越界 + with pytest.raises(配置错误, match="连接池.等待秒"): + 连接池配置(等待秒=False) # type: ignore + with pytest.raises(配置错误, match="连接池.等待秒"): + 连接池配置(等待秒=float("nan")) + with pytest.raises(配置错误, match="连接池.等待秒"): + 连接池配置(等待秒=float("inf")) + with pytest.raises(配置错误, match="连接池.等待秒"): + 连接池配置(等待秒=0.05) + with pytest.raises(配置错误, match="连接池.等待秒"): + 连接池配置(等待秒=61.0) + + +@pytest.mark.case_id("TC-POOL-CONFIG-DECOUPLING") +def test_连接池配置不改变数据库引用相等性(): + ref1 = 数据库引用("环境变量", "DB_URL") + ref2 = 数据库引用("环境变量", "DB_URL") + assert ref1 == ref2 + + # 配置解析产出独立连接池配置 + cfg = 解析配置( + { + "数据库": { + "取值方式": "环境变量", + "位置": "DB_URL", + "连接池": {"最大连接": 10, "等待秒": 3.0}, + }, + "资源": {"发布身份": "identity-1"}, + } + ) + assert cfg.数据库 == ref1 + assert cfg.连接池.最大连接 == 10 + assert cfg.连接池.等待秒 == 3.0 + + +@pytest.mark.case_id("TC-POOL-CONFIG-STARTUP-INTEGRATION") +def test_启动构建消费连接池配置(monkeypatch): + from muse.启动 import 构建 + + # 1. 显式配置生效 + cfg = 解析配置( + { + "数据库": { + "取值方式": "环境变量", + "位置": "DB_URL", + "连接池": {"最大连接": 12, "等待秒": 4.5}, + }, + "资源": {"发布身份": "identity-1"}, + "运行": {"用途": "production"}, + } + ) + 装配 = 构建(cfg) + assert 装配.数据库.最大连接 == 12 + assert 装配.数据库.等待秒 == 4.5 + + # 2. 未配置时回退默认(生产 4 / 2.0,评测 2 / 2.0) + cfg_prod = 解析配置( + { + "数据库": {"取值方式": "环境变量", "位置": "DB_URL"}, + "资源": {"发布身份": "identity-1"}, + "运行": {"用途": "production"}, + } + ) + 装配_prod = 构建(cfg_prod) + assert 装配_prod.数据库.最大连接 == 4 + assert 装配_prod.数据库.等待秒 == 2.0 + + cfg_eval = 解析配置( + { + "数据库": {"取值方式": "环境变量", "位置": "DB_URL"}, + "资源": {"发布身份": "identity-1"}, + "运行": {"用途": "evaluation"}, + } + ) + 装配_eval = 构建(cfg_eval) + assert 装配_eval.数据库.最大连接 == 2 + assert 装配_eval.数据库.等待秒 == 2.0 + + +@pytest.mark.case_id("TC-SSE-BACKOFF-ADAPTIVE") +def test_SSE空轮询退避机制(monkeypatch): + from types import SimpleNamespace + + from muse.任务运行.模型 import 事件类型, 事件续接, 运行事件 + from muse.接入.http import 事件订阅 + + def 构造事件(seq): + from datetime import UTC, datetime + + return 运行事件( + f"event-{seq}", + "task", + None, + None, + seq, + 事件类型.步骤完成, + datetime(2026, 9, 17, tzinfo=UTC), + 1, + {"step": f"step-{seq}"}, + ) + + class 模拟事件服务: + def __init__(self, 页集): + self.页集 = 页集 + + def 续接事件(self, task_id, cursor, 数量=100): + return self.页集.get(cursor, 事件续接((), False, cursor, cursor, None)) + + def 运行订阅(protocol, 页集, 循环次数=4): + 服务 = 模拟事件服务(页集) + monkeypatch.setattr(事件订阅, "取得任务服务", lambda _: 服务) + monkeypatch.setattr(事件订阅, "读取作者任务", lambda req, tid, wid=None: None) + 等待记录 = [] + + async def 记录等待(秒): + 等待记录.append(秒) + + monkeypatch.setattr(事件订阅.asyncio, "sleep", 记录等待) + + 检查次数 = [0] + + async def 已断开(): + 检查次数[0] += 1 + return 检查次数[0] > 循环次数 + + async def 执行(): + 响应 = await 事件订阅.订阅事件( + "task-1", + SimpleNamespace(is_disconnected=已断开), + "author", + cursor=0, + last_event_id=None, + protocol=protocol, + ) + return [块 async for 块 in 响应.body_iterator] + + asyncio.run(执行()) + return 等待记录 + + # 1. bounded-v2: 连续空轮询从 1.0s 退避到 2.0s + 等待_v2 = 运行订阅("bounded-v2", {}, 循环次数=4) + assert 等待_v2 == [1.0, 2.0, 2.0, 2.0] + + # 2. legacy: 始终保持 1.0s + 等待_legacy = 运行订阅("legacy", {}, 循环次数=4) + assert 等待_legacy == [1.0, 1.0, 1.0, 1.0] + + # 3. bounded-v2: 退避后有新事件到达,立即重置回 1.0s + class 动态服务: + def __init__(self): + self.count = 0 + + def 续接事件(self, task_id, cursor, 数量=100): + self.count += 1 + if self.count == 3: + return 事件续接((构造事件(1),), False, 1, 1, None) + return 事件续接((), False, cursor, cursor, None) + + 服务动态 = 动态服务() + monkeypatch.setattr(事件订阅, "取得任务服务", lambda _: 服务动态) + monkeypatch.setattr(事件订阅, "读取作者任务", lambda req, tid, wid=None: None) + 动态等待 = [] + + async def 记录动态等待(秒): + 动态等待.append(秒) + + monkeypatch.setattr(事件订阅.asyncio, "sleep", 记录动态等待) + 检查 = [0] + + async def 已断开_动态(): + 检查[0] += 1 + return 检查[0] > 4 + + async def 执行动态(): + 响应 = await 事件订阅.订阅事件( + "task-1", + SimpleNamespace(is_disconnected=已断开_动态), + "author", + cursor=0, + last_event_id=None, + protocol="bounded-v2", + ) + return [块 async for 块 in 响应.body_iterator] + + asyncio.run(执行动态()) + # 轮询1: 空 (等待1.0) + # 轮询2: 空 (等待2.0) + # 轮询3: 有事件 (重置为0,等待1.0) + # 轮询4: 空 (等待1.0) + assert 动态等待 == [1.0, 2.0, 1.0, 1.0] diff --git a/tests/用例清单.json b/tests/用例清单.json index c9e5732..1cc1b4d 100644 --- a/tests/用例清单.json +++ b/tests/用例清单.json @@ -35588,6 +35588,72 @@ ], "markers": [] }, + { + "case_id": "TC-POOL-CONFIG-DECOUPLING", + "file": "tests/单元/test_连接池配置与退避.py", + "symbol": "test_连接池配置不改变数据库引用相等性", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_连接池配置与退避.py::test_连接池配置不改变数据库引用相等性" + ], + "fixtures": [ + "request", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, + { + "case_id": "TC-POOL-CONFIG-STARTUP-INTEGRATION", + "file": "tests/单元/test_连接池配置与退避.py", + "symbol": "test_启动构建消费连接池配置", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_连接池配置与退避.py::test_启动构建消费连接池配置" + ], + "fixtures": [ + "monkeypatch", + "request", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, + { + "case_id": "TC-POOL-CONFIG-VALIDATION", + "file": "tests/单元/test_连接池配置与退避.py", + "symbol": "test_连接池配置字段强校验", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_连接池配置与退避.py::test_连接池配置字段强校验" + ], + "fixtures": [ + "request", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, + { + "case_id": "TC-SSE-BACKOFF-ADAPTIVE", + "file": "tests/单元/test_连接池配置与退避.py", + "symbol": "test_SSE空轮询退避机制", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_连接池配置与退避.py::test_SSE空轮询退避机制" + ], + "fixtures": [ + "monkeypatch", + "request", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, { "case_id": "TC-a089d73880d8", "environment": "隔离PG、实际S02与合成HTTP;不认证外部模型文学收益", From cd8914f1f4228af9a7f2b8d187df3749db0f5dec Mon Sep 17 00:00:00 2001 From: zizi Date: Mon, 21 Sep 2026 21:26:31 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E4=BC=98=E5=8C=96(=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E4=BC=A0=E8=BE=93):=20=E7=A7=BB=E9=99=A4=E5=BC=BA=E5=88=B6?= =?UTF-8?q?=E7=9F=AD=E8=BF=9E=E6=8E=A5=E5=B9=B6=E4=BB=A5=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E4=BD=9C=E7=94=A8=E5=9F=9F=E5=A4=8D=E7=94=A8HTTP=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/muse/启动.py | 6 +- src/muse/基础设施/模型/HTTP传输.py | 65 ++++++++++++---- src/muse/编排/生成正文.py | 89 +++++++++++---------- tests/单元/test_模型长连接复用.py | 120 +++++++++++++++++++++++++++++ tests/用例清单.json | 60 +++++++++++++++ 5 files changed, 283 insertions(+), 57 deletions(-) create mode 100644 tests/单元/test_模型长连接复用.py diff --git a/src/muse/启动.py b/src/muse/启动.py index 9391e1c..259ee58 100644 --- a/src/muse/启动.py +++ b/src/muse/启动.py @@ -197,7 +197,9 @@ class 应用装配: ) return self.数据库 - def 要求模型执行器(self, 上下文: 执行上下文, 计价: 调用计价 | None) -> 模型执行器: + def 要求模型执行器( + self, 上下文: 执行上下文, 计价: 调用计价 | None, *, 客户端: Any | None = None + ) -> 模型执行器: 数据库 = self.要求数据库() 版本 = 配置版本管理(数据库).读取任务绑定(上下文.领取.任务ID) 内容 = 版本.内容 @@ -221,7 +223,7 @@ class 应用装配: self.要求原文(), self.要求证据(), 策略, - 直接宿主(HTTP传输(提供方.地址, 凭据.来源, 凭据.位置, 提供方.协议)), + 直接宿主(HTTP传输(提供方.地址, 凭据.来源, 凭据.位置, 提供方.协议, 客户端=客户端)), 实际计价, 固定配置=版本, ) diff --git a/src/muse/基础设施/模型/HTTP传输.py b/src/muse/基础设施/模型/HTTP传输.py index d5d7f85..4967778 100644 --- a/src/muse/基础设施/模型/HTTP传输.py +++ b/src/muse/基础设施/模型/HTTP传输.py @@ -5,6 +5,7 @@ from __future__ import annotations import asyncio import json from collections.abc import AsyncIterable, AsyncIterator +from contextlib import asynccontextmanager from dataclasses import dataclass, field import httpx @@ -39,12 +40,35 @@ async def 解码SSE(字节流: AsyncIterable[bytes]) -> AsyncIterator[dict]: raise 模型协议错误("SSE 在完整事件分隔符之前断开") +@asynccontextmanager +async def 作用域HTTP客户端( + *, + 连接池限制: httpx.Limits | None = None, +) -> AsyncIterator[httpx.AsyncClient]: + """在当前事件循环作用域内管理长连接客户端生命周期;退出时确保完成 aclose 释放。""" + limits = 连接池限制 or httpx.Limits( + max_keepalive_connections=20, + max_connections=50, + keepalive_expiry=60.0, + ) + 客户端 = httpx.AsyncClient( + limits=limits, + follow_redirects=False, + trust_env=False, + ) + try: + yield 客户端 + finally: + await 客户端.aclose() + + @dataclass(frozen=True) class HTTP传输: 地址: str 凭据方式: str 凭据位置: str 协议: str + 客户端: httpx.AsyncClient | None = field(default=None, repr=False) def 准备(self, 请求: dict, 总期限秒: float) -> 已准备HTTP请求: try: @@ -68,13 +92,12 @@ class HTTP传输: 头 = { "Content-Type": "application/json", "Accept-Encoding": "identity", - "Connection": "close", } if self.协议 == "anthropic": 头.update({"x-api-key": 密钥, "anthropic-version": "2023-06-01"}) else: 头["Authorization"] = "Bearer " + 密钥 - return 已准备HTTP请求(str(地址), tuple(头.items()), 数据, 总期限秒) + return 已准备HTTP请求(str(地址), tuple(头.items()), 数据, 总期限秒, 客户端=self.客户端) async def 流(self, 请求: dict, 总期限秒: float) -> AsyncIterator[dict]: async for 事件 in self.准备(请求, 总期限秒).流(): @@ -87,23 +110,37 @@ class 已准备HTTP请求: 头: tuple[tuple[str, str], ...] = field(repr=False) 数据: bytes = field(repr=False) 总期限秒: float + 客户端: httpx.AsyncClient | None = field(default=None, repr=False) async def 流(self) -> AsyncIterator[dict]: + # 作用域客户端由调用方在当前事件循环内创建并负责关闭;未注入或已关闭时退回一次性客户端。 + 作用域 = self.客户端 + if 作用域 is not None and not 作用域.is_closed: + 客户端, 需关闭 = 作用域, False + else: + 客户端 = httpx.AsyncClient( + timeout=self.总期限秒, follow_redirects=False, trust_env=False + ) + 需关闭 = True try: async with asyncio.timeout(self.总期限秒): - async with httpx.AsyncClient( - timeout=self.总期限秒, follow_redirects=False, trust_env=False - ) as 客户端: - async with 客户端.stream( - "POST", self.地址, content=self.数据, headers=dict(self.头) - ) as 响应: - if 响应.is_error: - raise 模型协议错误( - "模型 HTTP 请求失败", 上下文={"status": 响应.status_code} - ) - async for 事件 in 解码SSE(响应.aiter_bytes()): - yield 事件 + async with 客户端.stream( + "POST", + self.地址, + content=self.数据, + headers=dict(self.头), + timeout=self.总期限秒, + ) as 响应: + if 响应.is_error: + raise 模型协议错误( + "模型 HTTP 请求失败", 上下文={"status": 响应.status_code} + ) + async for 事件 in 解码SSE(响应.aiter_bytes()): + yield 事件 except (TimeoutError, httpx.TimeoutException): raise 模型协议错误("模型调用超过总期限") from None except httpx.HTTPError: raise 模型协议错误("模型传输中断,调用结果可能未知") from None + finally: + if 需关闭: + await 客户端.aclose() diff --git a/src/muse/编排/生成正文.py b/src/muse/编排/生成正文.py index 7307f7b..9fc5700 100644 --- a/src/muse/编排/生成正文.py +++ b/src/muse/编排/生成正文.py @@ -44,6 +44,7 @@ from muse.任务运行.接口 import ( from muse.共享.调用身份 import 内容用途 from muse.共享.错误 import Muse错误 from muse.基础设施.数据库.连接 import 数据库工厂 +from muse.基础设施.模型.HTTP传输 import 作用域HTTP客户端 from muse.审校修订.接口 import 审校服务 from muse.正文写作.接口 import ( 写作输出合同, @@ -202,9 +203,6 @@ def 登记生成正文(登记: 流程登记, 装配, 计价) -> None: def 受限探索(上下文: 执行上下文) -> 步骤结果: 任务 = 上下文.任务 工具 = 装配.要求只读工具(上下文.领取) - 清单: tuple[探索条目, ...] = () - 绑定集: dict[str, 来源绑定] = {} - 历史: list[回合记录] = [] 轮次上限 = int( 任务.冻结输入["冻结上下文"].get("stop_conditions", {}).get("探索轮数上限", 6) ) @@ -213,44 +211,53 @@ def 登记生成正文(登记: 流程登记, 装配, 计价) -> None: for d in 工具.工具.values() ) 探索提示, 探索模板哈希 = 受限探索模板() - for _ in range(轮次上限): - 请求 = _写手请求( - 装配, - 上下文, - 阶段="探索", - 系统提示=探索提示, - 用户输入=json.dumps( - { - "粒度": 任务.冻结输入["输入"]["写作任务"]["粒度"], - "用途说明": 任务.冻结输入["输入"]["写作任务"].get("用途说明", ""), - "材料需求": ["目标章细纲", "时点事实", "历史正文"], - }, - ensure_ascii=False, - ), - 工具=工具描述, - 历史=tuple(历史), - ) - 执行器 = 装配.要求模型执行器(上下文, 计价) - 授权 = _原文授权(装配, 任务, 请求, 方式="persistent") - 回合 = asyncio.run(执行器.执行回合(上下文, 请求, 阶段="探索", 原文授权ID=授权)) - if 回合.结果.状态 == "tool_calls": - 回传: list[工具回传] = [] - for 调用 in 回合.结果.工具调用: - 结果 = 工具.调用(调用) - 清单 = 记录探索(清单, 调用.调用ID, 调用.名称, 调用.参数, 结果) - for 源 in 结果.来源: - 绑定集.setdefault( - 源.来源ID, - 来源绑定(源.来源ID, 源.数据版本, 源.结构哈希, 源.投影版本), - ) - 回传.append(工具回传(调用, json.dumps(结果.内容, ensure_ascii=False))) - 历史.append(回合记录(回合.结果, tuple(回传))) - continue - if 回合.结果.状态 != "completed": - raise 生成正文错误(f"探索回合未完成:{回合.结果.状态}") - break - else: - raise 生成正文错误("探索轮数超出停止条件上限") + + async def _运行探索循环(): + 清单: tuple[探索条目, ...] = () + 绑定集: dict[str, 来源绑定] = {} + 历史: list[回合记录] = [] + async with 作用域HTTP客户端() as 客户端: + for _ in range(轮次上限): + 请求 = _写手请求( + 装配, + 上下文, + 阶段="探索", + 系统提示=探索提示, + 用户输入=json.dumps( + { + "粒度": 任务.冻结输入["输入"]["写作任务"]["粒度"], + "用途说明": 任务.冻结输入["输入"]["写作任务"].get("用途说明", ""), + "材料需求": ["目标章细纲", "时点事实", "历史正文"], + }, + ensure_ascii=False, + ), + 工具=工具描述, + 历史=tuple(历史), + ) + 执行器 = 装配.要求模型执行器(上下文, 计价, 客户端=客户端) + 授权 = _原文授权(装配, 任务, 请求, 方式="persistent") + 回合 = await 执行器.执行回合(上下文, 请求, 阶段="探索", 原文授权ID=授权) + if 回合.结果.状态 == "tool_calls": + 回传: list[工具回传] = [] + for 调用 in 回合.结果.工具调用: + 结果 = 工具.调用(调用) + 清单 = 记录探索(清单, 调用.调用ID, 调用.名称, 调用.参数, 结果) + for 源 in 结果.来源: + 绑定集.setdefault( + 源.来源ID, + 来源绑定(源.来源ID, 源.数据版本, 源.结构哈希, 源.投影版本), + ) + 回传.append(工具回传(调用, json.dumps(结果.内容, ensure_ascii=False))) + 历史.append(回合记录(回合.结果, tuple(回传))) + continue + if 回合.结果.状态 != "completed": + raise 生成正文错误(f"探索回合未完成:{回合.结果.状态}") + break + else: + raise 生成正文错误("探索轮数超出停止条件上限") + return 清单, 绑定集 + + 清单, 绑定集 = asyncio.run(_运行探索循环()) if not 清单: raise 生成正文错误("写手没有进行任何受限探索读取") return 步骤结果( diff --git a/tests/单元/test_模型长连接复用.py b/tests/单元/test_模型长连接复用.py new file mode 100644 index 0000000..c51a7ef --- /dev/null +++ b/tests/单元/test_模型长连接复用.py @@ -0,0 +1,120 @@ +"""模型 HTTP 传输执行作用域长连接复用与生命周期机械验证。""" + +import asyncio +import threading +from http.server import BaseHTTPRequestHandler, HTTPServer +from socketserver import ThreadingMixIn + +import pytest + +from muse.基础设施.模型.HTTP传输 import HTTP传输, 作用域HTTP客户端 + + +class _可复用HTTP服务(ThreadingMixIn, HTTPServer): + daemon_threads = True + + def __init__(self, server_address, handler_cls): + super().__init__(server_address, handler_cls) + self.tcp_accept_count = 0 + self.request_count = 0 + self.lock = threading.Lock() + + def get_request(self): + sock, addr = super().get_request() + with self.lock: + self.tcp_accept_count += 1 + return sock, addr + + +class _SSE处理器(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + + def do_POST(self): + length = int(self.headers.get("content-length", 0)) + _ = self.rfile.read(length) + with self.server.lock: + self.server.request_count += 1 + + body = b'data: {"type": "response.output_text.delta", "delta": "ok"}\n\ndata: [DONE]\n\n' + self.send_response(200) + self.send_header("Content-Type", "text/event-stream") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + self.wfile.flush() + + def log_message(self, format, *args): + pass + + +@pytest.fixture +def 本地HTTP服务(): + server = _可复用HTTP服务(("127.0.0.1", 0), _SSE处理器) + thread = threading.Thread(target=server.serve_forever) + thread.daemon = True + thread.start() + port = server.server_port + try: + yield f"http://127.0.0.1:{port}", server + finally: + server.shutdown() + server.server_close() + + +@pytest.mark.网络 +@pytest.mark.case_id("TC-HTTP-KEEP-ALIVE-REUSE") +def test_作用域HTTP客户端复用单条TCP连接(本地HTTP服务, tmp_path): + base_url, server = 本地HTTP服务 + key_file = tmp_path / "mock-key.txt" + key_file.write_text("test-key") + + async def _运行三次请求(): + async with 作用域HTTP客户端() as 客户端: + 传输 = HTTP传输(base_url, "受控存储", str(key_file), "responses", 客户端=客户端) + for _ in range(3): + 事件 = [] + async for 项 in 传输.流({"input": "hi"}, 总期限秒=5.0): + 事件.append(项) + assert len(事件) == 1 + assert 事件[0]["delta"] == "ok" + assert not 客户端.is_closed + assert 客户端.is_closed + + asyncio.run(_运行三次请求()) + + # 3 次 HTTP 请求在同一作用域内共享同一个客户端,只建立 1 次真实 TCP 连接 + assert server.request_count == 3 + assert server.tcp_accept_count == 1 + + +@pytest.mark.网络 +@pytest.mark.case_id("TC-HTTP-SHORT-CONNECTION-CONTRAST") +def test_未指定作用域时每次请求独立建连(本地HTTP服务, tmp_path): + base_url, server = 本地HTTP服务 + key_file = tmp_path / "mock-key.txt" + key_file.write_text("test-key") + + async def _运行三次独立请求(): + # 无外部客户端,每次请求使用临时客户端 + 传输 = HTTP传输(base_url, "受控存储", str(key_file), "responses") + for _ in range(3): + 事件 = [] + async for 项 in 传输.流({"input": "hi"}, 总期限秒=5.0): + 事件.append(项) + assert len(事件) == 1 + + asyncio.run(_运行三次独立请求()) + + assert server.request_count == 3 + assert server.tcp_accept_count == 3 + + +@pytest.mark.case_id("TC-HTTP-HEADER-NO-CONNECTION-CLOSE") +def test_请求头移除强制关闭并保留恒等编码(tmp_path): + key_file = tmp_path / "mock-key.txt" + key_file.write_text("test-key") + 传输 = HTTP传输("http://127.0.0.1:8000", "受控存储", str(key_file), "responses") + 准备 = 传输.准备({"input": "test"}, 总期限秒=10.0) + 头字典 = dict(准备.头) + assert "Connection" not in 头字典 or 头字典["Connection"] != "close" + assert 头字典.get("Accept-Encoding") == "identity" diff --git a/tests/用例清单.json b/tests/用例清单.json index 1cc1b4d..8ba7665 100644 --- a/tests/用例清单.json +++ b/tests/用例清单.json @@ -35381,6 +35381,66 @@ ], "markers": [] }, + { + "case_id": "TC-HTTP-HEADER-NO-CONNECTION-CLOSE", + "file": "tests/单元/test_模型长连接复用.py", + "symbol": "test_请求头移除强制关闭并保留恒等编码", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_模型长连接复用.py::test_请求头移除强制关闭并保留恒等编码" + ], + "fixtures": [ + "request", + "tmp_path", + "tmp_path_factory", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [] + }, + { + "case_id": "TC-HTTP-KEEP-ALIVE-REUSE", + "file": "tests/单元/test_模型长连接复用.py", + "symbol": "test_作用域HTTP客户端复用单条TCP连接", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_模型长连接复用.py::test_作用域HTTP客户端复用单条TCP连接" + ], + "fixtures": [ + "request", + "tmp_path", + "tmp_path_factory", + "本地HTTP服务", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [ + "网络" + ] + }, + { + "case_id": "TC-HTTP-SHORT-CONNECTION-CONTRAST", + "file": "tests/单元/test_模型长连接复用.py", + "symbol": "test_未指定作用域时每次请求独立建连", + "parameter_ids": [], + "node_ids": [ + "tests/单元/test_模型长连接复用.py::test_未指定作用域时每次请求独立建连" + ], + "fixtures": [ + "request", + "tmp_path", + "tmp_path_factory", + "本地HTTP服务", + "测试资源接缝", + "源码资源", + "离线防护" + ], + "markers": [ + "网络" + ] + }, { "case_id": "TC-O08-SSE-001", "file": "tests/单元/test_任务事件收尾.py", From dca00320016f1a87e1d681c1ad750d6493658abd Mon Sep 17 00:00:00 2001 From: zizi Date: Mon, 21 Sep 2026 21:27:54 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E6=96=87=E6=A1=A3(=E8=BF=90=E8=A1=8C):=20?= =?UTF-8?q?=E7=99=BB=E8=AE=B0=E8=BF=9E=E6=8E=A5=E6=B1=A0=E5=8F=AF=E9=80=89?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E8=8A=82=E4=B8=8E=E9=BB=98=E8=AE=A4=E5=80=BC?= =?UTF-8?q?=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/运行手册.md | 1 + 部署/应用.example.toml | 6 ++++++ 配置/应用.example.toml | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/docs/运行手册.md b/docs/运行手册.md index 71e570f..7a4e823 100644 --- a/docs/运行手册.md +++ b/docs/运行手册.md @@ -38,6 +38,7 @@ ps -p "$pid" -o command= - 版本化范围:`配置/本机正式.toml`、`配置/本机维护.toml` 保存非敏感配置及受控引用;仅创建文件不代表已经提交 Git。 - 本机受控根:`~/.local/share/muse/正式环境/`(目录 0700,凭据文件 0600)。三个数据库角色分别使用 `muse_app.连接.txt`、`muse_eval.连接.txt`、`muse_maint.连接.txt`;工作台使用 `工作台口令.txt`。 +- 可选连接池参数:在 `["数据库"."连接池"]` 节声明 `最大连接`(1–100)与 `等待秒`(0.1–60.0)可显式覆盖默认值(生产 4、评测 2,等待 2.0 秒);只调优当次部署的借还行为,不改变数据库目标身份。 - infra 凭据副本:SSH `个人-minione-ubuntu-infra-4c16g120g`,目录 `/opt/infra/private/muse-agent-example/`。恢复时复制所需文件到本机受控根并核对权限;禁止输出凭据内容到日志或提交明文凭据。 - 正式连接仅使用 PG `100.64.0.8:5433`,带 `keepalives=1 keepalives_idle=15 keepalives_interval=5 keepalives_count=3`。Redis 与本项目无关。 - 原迁移目录中的库外原文、草稿和切换回执尚未找回。当前文件根是恢复后新建的目录,不代表原文件资产已恢复。 diff --git a/部署/应用.example.toml b/部署/应用.example.toml index d05fd0e..fed299b 100644 --- a/部署/应用.example.toml +++ b/部署/应用.example.toml @@ -3,6 +3,12 @@ "取值方式" = "受控存储" "位置" = "/run/secrets/muse_db" +# 可选:连接池参数显式覆盖;未声明时按用途取默认(生产 4、评测 2,等待 2.0 秒)。 +# 仅调优当次部署的借还行为,不改变数据库目标身份。 +# ["数据库"."连接池"] +# "最大连接" = 8 +# "等待秒" = 2.0 + ["运行"] "用途" = "production" diff --git a/配置/应用.example.toml b/配置/应用.example.toml index 20f05e0..bca03fe 100644 --- a/配置/应用.example.toml +++ b/配置/应用.example.toml @@ -4,6 +4,12 @@ # 相对地址以配置文件所在目录为起点。 "位置" = "数据库连接.txt" +# 可选:连接池参数显式覆盖;未声明时按用途取默认(生产 4、评测 2,等待 2.0 秒)。 +# 仅调优当次部署的借还行为,不改变数据库目标身份。 +# ["数据库"."连接池"] +# "最大连接" = 8 +# "等待秒" = 2.0 + ["资源"] # 从 工具/环境预检.py 的 resource_build_id 取得,不能只写发布标签。 "发布身份" = "<固定资源构建身份>" From 713cc45c636b1b68eabd8d111992a30aa5e7e89a Mon Sep 17 00:00:00 2001 From: zizi Date: Tue, 22 Sep 2026 10:18:51 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E9=87=8D=E6=9E=84(=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93):=20=E8=BF=81=E7=A7=BB=E9=93=BE=E5=8E=8B=E6=89=81?= =?UTF-8?q?=E4=B8=BA=E5=8D=95=E5=9F=BA=E7=BA=BF=E5=B9=B6=E7=B2=BE=E7=AE=80?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=87=B3=E4=BF=9D=E7=95=99=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 51 个增量迁移文件压扁为 V0001__基线.sql 完整快照(结构+种子+授权), 等价门禁:旧链全量执行库与基线库 pg_dump 逐字节一致 - 剔除 pg_dump 固化的 public schema 超级用户归属断言(muse_maint 无权执行) - 测试删减至保留集:备份往返 2 + 预算 2 + 租约 2 + 基线建库 1 - 租约/预算夹具改共享库,消除按例克隆建库 - 修复共享库三类既有污染:账本注入残留(系统管理)、失败触发器残留(评测)、 建表残留(正式变更事务),发布包迁移文件名硬编码改动态核对 - 全量数据库验收 722 passed / 0 failed / 0 errors(main 基线为 24F+291E) - 运行手册登记基线模式改表流程与账本校验和同步 --- docs/运行手册.md | 20 + tests/用例清单.json | 2050 +--- tests/迁移/test_备份恢复与切换核对.py | 817 +- tests/集成/test_任务租约与恢复.py | 356 +- tests/集成/test_发布包独立运行.py | 9 +- tests/集成/test_数据库底座隔离.py | 55 - tests/集成/test_数据库连接与迁移.py | 359 +- tests/集成/test_数据维护与恢复.py | 203 - tests/集成/test_模型任务备份恢复.py | 117 - tests/集成/test_正式变更事务.py | 5 +- tests/集成/test_生产评测权限隔离.py | 51 +- tests/集成/test_系统管理与版本保护.py | 18 +- tests/集成/test_结构版本与并发保护.py | 338 - tests/集成/test_预算预留与结算.py | 263 +- 数据库/迁移/V0001__共享标识与版本.sql | 64 - 数据库/迁移/V0001__基线.sql | 10085 ++++++++++++++++++ 数据库/迁移/V0002__元数据结构与策略.sql | 84 - 数据库/迁移/V0003__正式变更.sql | 38 - 数据库/迁移/V0004__任务运行与证据.sql | 290 - 数据库/迁移/V0005__作品规划.sql | 94 - 数据库/迁移/V0006__故事世界.sql | 52 - 数据库/迁移/V0007__资料研究.sql | 67 - 数据库/迁移/V0009__正文写作.sql | 50 - 数据库/迁移/V0016__流程定义与版本.sql | 20 - 数据库/迁移/V0020__上下文快照与消费.sql | 28 - 数据库/迁移/V0021__模型候选与审校报告.sql | 59 - 数据库/迁移/V0022__知识方法.sql | 129 - 数据库/迁移/V0023__模型规划与调用级消费.sql | 32 - 数据库/迁移/V0024__模型派发授权依据.sql | 19 - 数据库/迁移/V0025__旧库迁移来源与映射.sql | 70 - 数据库/迁移/V0026__参考分析版本.sql | 23 - 数据库/迁移/V0027__作品声音版本.sql | 37 - 数据库/迁移/V0028__文学审校报告.sql | 34 - 数据库/迁移/V0029__规则候选与诊断.sql | 31 - 数据库/迁移/V0030__模型修订结果.sql | 16 - 数据库/迁移/V0031__正文分支来源.sql | 34 - 数据库/迁移/V0032__选段修订依据.sql | 6 - 数据库/迁移/V0033__质量案例.sql | 20 - 数据库/迁移/V0034__隔离数据集与实验.sql | 46 - 数据库/迁移/V0035__评测逐例执行.sql | 43 - 数据库/迁移/V0036__评测停止决定.sql | 9 - 数据库/迁移/V0037__逐调用交付确认.sql | 20 - 数据库/迁移/V0038__评测引文拒绝.sql | 17 - 数据库/迁移/V0039__评测条件第三.sql | 10 - 数据库/迁移/V0040__标定金标准与凭据.sql | 18 - 数据库/迁移/V0041__评测语义检测单元.sql | 4 - 数据库/迁移/V0042__效果判据凭据.sql | 10 - 数据库/迁移/V0043__目标启用凭据.sql | 28 - 数据库/迁移/V0044__作者偏好与反馈.sql | 34 - 数据库/迁移/V0045__具体改进与目标回执.sql | 48 - 数据库/迁移/V0046__作者长期观察.sql | 21 - 数据库/迁移/V0047__定稿与导出产物.sql | 32 - 数据库/迁移/V0048__连载发布与读者反馈.sql | 42 - 数据库/迁移/V0049__运行版本只读核对.sql | 2 - 数据库/迁移/V0050__跨模块交付引用约束.sql | 15 - 数据库/迁移/V0051__工作台任务盘点视图.sql | 10 - 数据库/迁移/V0052__持久返修会话.sql | 81 - 数据库/迁移/V0053__返修独立比较证明.sql | 35 - 数据库/迁移/V0054__规则诊断资格与启停.sql | 110 - 数据库/迁移/V0055__运行观察来源.sql | 39 - 数据库/迁移/V0056__调用结算与配置验证.sql | 55 - 数据库/迁移/V0057__来源当前授权.sql | 3 - 数据库/迁移/V0058__成品补充验证回执.sql | 17 - 数据库/迁移/V0059__检索索引代次.sql | 31 - 数据库/迁移/V0060__评测单元复用来源.sql | 14 - 数据库/迁移/V0061__场景切片索引.sql | 87 - 66 files changed, 10313 insertions(+), 6611 deletions(-) delete mode 100644 tests/集成/test_数据库底座隔离.py delete mode 100644 tests/集成/test_数据维护与恢复.py delete mode 100644 tests/集成/test_模型任务备份恢复.py delete mode 100644 tests/集成/test_结构版本与并发保护.py delete mode 100644 数据库/迁移/V0001__共享标识与版本.sql create mode 100644 数据库/迁移/V0001__基线.sql delete mode 100644 数据库/迁移/V0002__元数据结构与策略.sql delete mode 100644 数据库/迁移/V0003__正式变更.sql delete mode 100644 数据库/迁移/V0004__任务运行与证据.sql delete mode 100644 数据库/迁移/V0005__作品规划.sql delete mode 100644 数据库/迁移/V0006__故事世界.sql delete mode 100644 数据库/迁移/V0007__资料研究.sql delete mode 100644 数据库/迁移/V0009__正文写作.sql delete mode 100644 数据库/迁移/V0016__流程定义与版本.sql delete mode 100644 数据库/迁移/V0020__上下文快照与消费.sql delete mode 100644 数据库/迁移/V0021__模型候选与审校报告.sql delete mode 100644 数据库/迁移/V0022__知识方法.sql delete mode 100644 数据库/迁移/V0023__模型规划与调用级消费.sql delete mode 100644 数据库/迁移/V0024__模型派发授权依据.sql delete mode 100644 数据库/迁移/V0025__旧库迁移来源与映射.sql delete mode 100644 数据库/迁移/V0026__参考分析版本.sql delete mode 100644 数据库/迁移/V0027__作品声音版本.sql delete mode 100644 数据库/迁移/V0028__文学审校报告.sql delete mode 100644 数据库/迁移/V0029__规则候选与诊断.sql delete mode 100644 数据库/迁移/V0030__模型修订结果.sql delete mode 100644 数据库/迁移/V0031__正文分支来源.sql delete mode 100644 数据库/迁移/V0032__选段修订依据.sql delete mode 100644 数据库/迁移/V0033__质量案例.sql delete mode 100644 数据库/迁移/V0034__隔离数据集与实验.sql delete mode 100644 数据库/迁移/V0035__评测逐例执行.sql delete mode 100644 数据库/迁移/V0036__评测停止决定.sql delete mode 100644 数据库/迁移/V0037__逐调用交付确认.sql delete mode 100644 数据库/迁移/V0038__评测引文拒绝.sql delete mode 100644 数据库/迁移/V0039__评测条件第三.sql delete mode 100644 数据库/迁移/V0040__标定金标准与凭据.sql delete mode 100644 数据库/迁移/V0041__评测语义检测单元.sql delete mode 100644 数据库/迁移/V0042__效果判据凭据.sql delete mode 100644 数据库/迁移/V0043__目标启用凭据.sql delete mode 100644 数据库/迁移/V0044__作者偏好与反馈.sql delete mode 100644 数据库/迁移/V0045__具体改进与目标回执.sql delete mode 100644 数据库/迁移/V0046__作者长期观察.sql delete mode 100644 数据库/迁移/V0047__定稿与导出产物.sql delete mode 100644 数据库/迁移/V0048__连载发布与读者反馈.sql delete mode 100644 数据库/迁移/V0049__运行版本只读核对.sql delete mode 100644 数据库/迁移/V0050__跨模块交付引用约束.sql delete mode 100644 数据库/迁移/V0051__工作台任务盘点视图.sql delete mode 100644 数据库/迁移/V0052__持久返修会话.sql delete mode 100644 数据库/迁移/V0053__返修独立比较证明.sql delete mode 100644 数据库/迁移/V0054__规则诊断资格与启停.sql delete mode 100644 数据库/迁移/V0055__运行观察来源.sql delete mode 100644 数据库/迁移/V0056__调用结算与配置验证.sql delete mode 100644 数据库/迁移/V0057__来源当前授权.sql delete mode 100644 数据库/迁移/V0058__成品补充验证回执.sql delete mode 100644 数据库/迁移/V0059__检索索引代次.sql delete mode 100644 数据库/迁移/V0060__评测单元复用来源.sql delete mode 100644 数据库/迁移/V0061__场景切片索引.sql diff --git a/docs/运行手册.md b/docs/运行手册.md index 7a4e823..441f8ac 100644 --- a/docs/运行手册.md +++ b/docs/运行手册.md @@ -39,6 +39,26 @@ ps -p "$pid" -o command= - 版本化范围:`配置/本机正式.toml`、`配置/本机维护.toml` 保存非敏感配置及受控引用;仅创建文件不代表已经提交 Git。 - 本机受控根:`~/.local/share/muse/正式环境/`(目录 0700,凭据文件 0600)。三个数据库角色分别使用 `muse_app.连接.txt`、`muse_eval.连接.txt`、`muse_maint.连接.txt`;工作台使用 `工作台口令.txt`。 - 可选连接池参数:在 `["数据库"."连接池"]` 节声明 `最大连接`(1–100)与 `等待秒`(0.1–60.0)可显式覆盖默认值(生产 4、评测 2,等待 2.0 秒);只调优当次部署的借还行为,不改变数据库目标身份。 + +### 数据库结构变更(基线模式) + +自 2026-09 起迁移链已压扁为单基线:`数据库/迁移/V0001__基线.sql` 是全部表结构、系统种子数据与角色授权的完整快照。不再为每个结构变更新增迁移文件。 + +日常改表流程: + +1. 动手前先备份(`muse 备份`); +2. 修改 `V0001__基线.sql`(同步结构、种子或授权变化); +3. 在正式库手动执行对应的 `ALTER TABLE ...` 等语句(以维护角色连接); +4. 跑 `make 数据库测试` 验证底座能用新基线建出可用库。 + +账本说明:`muse_migration` 表仍存在并登记 V0001 的校验和,用于备份清单核对与 `muse 管理系统状态` 的版本一致性检查。修改基线文件后必须同步更新账本校验和,否则启动诊断会报 `changed_versions`: + +```sql +-- 以 muse_maint 连接正式库执行; 为新基线文件的 sha256 +UPDATE muse_migration SET checksum='' WHERE version=1; +``` + +旧备份兼容:迁移链压扁前创建的备份,其清单登记 51 步账本,与新基线代码不匹配;若需恢复,先切回压扁前的代码版本执行恢复,再重新做一次新格式备份。压扁当日的最后一次旧格式备份建议长期保留。 - infra 凭据副本:SSH `个人-minione-ubuntu-infra-4c16g120g`,目录 `/opt/infra/private/muse-agent-example/`。恢复时复制所需文件到本机受控根并核对权限;禁止输出凭据内容到日志或提交明文凭据。 - 正式连接仅使用 PG `100.64.0.8:5433`,带 `keepalives=1 keepalives_idle=15 keepalives_interval=5 keepalives_count=3`。Redis 与本项目无关。 - 原迁移目录中的库外原文、草稿和切换回执尚未找回。当前文件根是恢复后新建的目录,不代表原文件资产已恢复。 diff --git a/tests/用例清单.json b/tests/用例清单.json index 8ba7665..bdda7fb 100644 --- a/tests/用例清单.json +++ b/tests/用例清单.json @@ -3455,37 +3455,6 @@ "file": "web/tests/旅程/任务预算与推进.spec.ts", "symbol": "NC-browser-task-execution:批准额度后单步执行到真实候选" }, - { - "case_id": "NC-budget-actual-over-cap", - "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", - "given": "实际成本超过单次预留金额", - "when": "用真实回执结算", - "then": [ - "保存真实金额和超额标记,停止任务预算" - ], - "contract": "docs/系统架构/新版设计/模块设计/S02-任务运行.md", - "file": "tests/集成/test_预算预留与结算.py", - "symbol": "test_超单次成本先保存事实并关闭任务预算__a61006", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_预算预留与结算.py::test_超单次成本先保存事实并关闭任务预算__a61006" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL", - "预算环境" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-budget-amount-validation", "environment": "离线纯规则", @@ -3518,80 +3487,6 @@ "parametrize" ] }, - { - "case_id": "NC-budget-call-limits", - "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", - "given": "窗口次数或任务计划只剩一次", - "when": "结算零成本调用后尝试下一次", - "then": [ - "两类次数限制都独立生效" - ], - "contract": "docs/系统架构/新版设计/模块设计/S02-任务运行.md", - "file": "tests/集成/test_预算预留与结算.py", - "symbol": "test_窗口次数和任务计划分别限制调用__a61008", - "parameter_ids": [ - "task", - "window" - ], - "node_ids": [ - "tests/集成/test_预算预留与结算.py::test_窗口次数和任务计划分别限制调用__a61008[task]", - "tests/集成/test_预算预留与结算.py::test_窗口次数和任务计划分别限制调用__a61008[window]" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "数据库底座", - "模式", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL", - "预算环境" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, - { - "case_id": "NC-budget-cancellation", - "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", - "given": "未发送或已发送的预留", - "when": "关闭任务预算", - "then": [ - "未发送释放、已发送未知且任务不再外发" - ], - "contract": "docs/系统架构/新版设计/模块设计/S02-任务运行.md", - "file": "tests/集成/test_预算预留与结算.py", - "symbol": "test_取消保留已发送调用的未知成本__a61004", - "parameter_ids": [ - "after-send", - "before-send" - ], - "node_ids": [ - "tests/集成/test_预算预留与结算.py::test_取消保留已发送调用的未知成本__a61004[after-send]", - "tests/集成/test_预算预留与结算.py::test_取消保留已发送调用的未知成本__a61004[before-send]" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "已发出", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL", - "预算环境" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, { "case_id": "NC-budget-concurrent-reserve", "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", @@ -3623,43 +3518,6 @@ "数据库" ] }, - { - "case_id": "NC-budget-expiration", - "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", - "given": "未发送或在途预留期限到达", - "when": "真实时间过期后回收", - "then": [ - "未发送释放,在途保留未知成本" - ], - "contract": "docs/系统架构/新版设计/模块设计/S02-任务运行.md", - "file": "tests/集成/test_预算预留与结算.py", - "symbol": "test_过期只释放尚未发送的预留__a61005", - "parameter_ids": [ - "in-flight", - "reserved" - ], - "node_ids": [ - "tests/集成/test_预算预留与结算.py::test_过期只释放尚未发送的预留__a61005[in-flight]", - "tests/集成/test_预算预留与结算.py::test_过期只释放尚未发送的预留__a61005[reserved]" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "已发出", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL", - "预算环境" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, { "case_id": "NC-budget-idempotent-settlement", "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", @@ -3714,68 +3572,6 @@ ], "markers": [] }, - { - "case_id": "NC-budget-settlement-rollback", - "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", - "given": "调用在途及PG注入结算失败触发器", - "when": "结算回滚后移除故障再结算", - "then": [ - "故障保留在途标记和未知实际金额,可恢复结算" - ], - "contract": "docs/系统架构/新版设计/模块设计/S02-任务运行.md", - "file": "tests/集成/test_预算预留与结算.py", - "symbol": "test_结算失败回滚仍保留在途标记__a61007", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_预算预留与结算.py::test_结算失败回滚仍保留在途标记__a61007" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL", - "预算环境" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-budget-unknown-across-window", - "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", - "given": "已发送无成本回执的调用且注入旧窗口", - "when": "尝试新调用并进行可信对账", - "then": [ - "未知不计零且跨窗阻断,对账后恢复" - ], - "contract": "docs/系统架构/新版设计/模块设计/S02-任务运行.md", - "file": "tests/集成/test_预算预留与结算.py", - "symbol": "test_未知成本跨窗口仍阻止后续调用直至对账__a61003", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_预算预留与结算.py::test_未知成本跨窗口仍阻止后续调用直至对账__a61003" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL", - "预算环境" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-candidate-stale-buffer-choice", "environment": "真实页面与Tiptap,HTTP替身;另有真实浏览器旅程", @@ -4189,68 +3985,6 @@ ], "markers": [] }, - { - "case_id": "NC-config-validation-binding", - "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", - "given": "陈旧绑定或离线证据用于生产", - "when": "验证配置版本", - "then": [ - "绑定不符和离线生产都拒绝" - ], - "contract": "docs/系统架构/新版设计/模块设计/S02-任务运行.md", - "file": "tests/集成/test_预算预留与结算.py", - "symbol": "test_配置不接受陈旧验证或离线证据启用生产__a6100a", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_预算预留与结算.py::test_配置不接受陈旧验证或离线证据启用生产__a6100a" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL", - "预算环境" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-config-version-freeze", - "environment": "隔离 PostgreSQL;配置验证器为显式协议替身", - "given": "显式合成验证器和两版配置", - "when": "验证启用、任务冻结、升级和停用", - "then": [ - "版本不可覆盖,CAS与回执匹配,旧任务副本保留" - ], - "contract": "docs/系统架构/新版设计/模块设计/S02-任务运行.md", - "file": "tests/集成/test_预算预留与结算.py", - "symbol": "test_配置验证启用与任务冻结版本互不覆盖__a61009", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_预算预留与结算.py::test_配置验证启用与任务冻结版本互不覆盖__a61009" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL", - "预算环境" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-ctx-aicontext-differs", "environment": "真实隔离PostgreSQL", @@ -5826,50 +5560,6 @@ "数据库" ] }, - { - "case_id": "NC-database-baseline-pg-01", - "file": "tests/集成/test_数据库底座隔离.py", - "symbol": "test_克隆保留真实提交且后例没有前例数据", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库底座隔离.py::test_克隆保留真实提交且后例没有前例数据" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-database-baseline-pg-02", - "file": "tests/集成/test_数据库底座隔离.py", - "symbol": "test_封存模板拒绝直接连接且失败用例精确清理", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库底座隔离.py::test_封存模板拒绝直接连接且失败用例精确清理" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-database-baseline-unit-05", "file": "tests/单元/test_数据库底座生命周期.py", @@ -5962,436 +5652,6 @@ ], "markers": [] }, - { - "case_id": "NC-db-cli-assembly", - "environment": "隔离 PostgreSQL", - "given": "生产和维护用途 TOML 配置", - "when": "运行真实 CLI 迁移入口", - "then": [ - "生产配置被拒,维护从包资源执行并登记 V0001" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_迁移命令使用维护装配与包资源__dc000c", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_迁移命令使用维护装配与包资源__dc000c" - ], - "fixtures": [ - "capsys", - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-db-controlled-reference", - "environment": "离线", - "given": "受控存储中的合成连接引用", - "when": "连接 owner 解析引用", - "then": [ - "通过凭据 owner 读取值且无默认回退" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_数据库引用通过唯一凭据入口读取受控文件__dd000d", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_数据库引用通过唯一凭据入口读取受控文件__dd000d" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "测试资源接缝", - "源码资源", - "离线防护" - ], - "markers": [] - }, - { - "case_id": "NC-db-eval-oracle", - "environment": "隔离 PostgreSQL", - "given": "oracle schema 中的合成答案和匿名映射", - "when": "生产角色与评测角色实际 SELECT", - "then": [ - "生产被 PG 拒权,评测可读" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_生产用途拒绝oracle及匿名映射读取__d80008", - "parameter_ids": [ - "blind-map", - "oracle" - ], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_生产用途拒绝oracle及匿名映射读取__d80008[blind-map]", - "tests/集成/test_数据库连接与迁移.py::test_生产用途拒绝oracle及匿名映射读取__d80008[oracle]" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "目标表", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, - { - "case_id": "NC-db-eval-production-write", - "environment": "隔离 PostgreSQL", - "given": "由维护迁移授权的生产和评测表", - "when": "两个角色分别写入", - "then": [ - "生产角色可写生产表,评测只能写评测表" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_评测角色仅可写评测对象__da000a", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_评测角色仅可写评测对象__da000a" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-db-migration-failure", - "environment": "隔离 PostgreSQL", - "given": "隔离测试库与受控连接引用", - "when": "执行连接、只读、事务、用途或迁移操作", - "then": [ - "拒绝与失败如实呈现;成功路径可复验" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_迁移失败不登记且可重跑__d30003", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_迁移失败不登记且可重跑__d30003" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-db-migration-idempotent", - "environment": "隔离 PostgreSQL", - "given": "隔离测试库与受控连接引用", - "when": "执行连接、只读、事务、用途或迁移操作", - "then": [ - "拒绝与失败如实呈现;成功路径可复验" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_迁移幂等与篡改拦截__d20002", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_迁移幂等与篡改拦截__d20002" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-db-migration-lock", - "environment": "隔离 PostgreSQL", - "given": "另一连接持有迁移锁且账本已最新", - "when": "迁移入口重跑", - "then": [ - "首先拒绝锁冲突,释放锁后可幂等重跑" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_迁移先取锁再判定账本__db000b", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_迁移先取锁再判定账本__db000b" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-db-migration-order", - "environment": "隔离 PostgreSQL", - "given": "隔离测试库与受控连接引用", - "when": "执行连接、只读、事务、用途或迁移操作", - "then": [ - "拒绝与失败如实呈现;成功路径可复验" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_低版本补录被拒绝__d40004", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_低版本补录被拒绝__d40004" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-db-no-fallback", - "environment": "离线", - "given": "数据库凭据引用未提供", - "when": "从真实装配取得数据库连接", - "then": [ - "报环境缺失并拒绝任何默认库回退" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_缺配置拒绝回退默认库__d10001", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_缺配置拒绝回退默认库__d10001" - ], - "fixtures": [ - "monkeypatch", - "request", - "测试资源接缝", - "源码资源", - "离线防护" - ], - "markers": [] - }, - { - "case_id": "NC-db-purpose-role", - "environment": "隔离 PostgreSQL", - "given": "三个固定普通登录角色", - "when": "正式连接入口声明其他用途", - "then": [ - "六种不匹配全部拒绝,匹配组合可用" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_用途角色不匹配被拒__d70007", - "parameter_ids": [ - "evaluation-as-maintenance", - "evaluation-as-production", - "maintenance-as-evaluation", - "maintenance-as-production", - "production-as-evaluation", - "production-as-maintenance" - ], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_用途角色不匹配被拒__d70007[evaluation-as-maintenance]", - "tests/集成/test_数据库连接与迁移.py::test_用途角色不匹配被拒__d70007[evaluation-as-production]", - "tests/集成/test_数据库连接与迁移.py::test_用途角色不匹配被拒__d70007[maintenance-as-evaluation]", - "tests/集成/test_数据库连接与迁移.py::test_用途角色不匹配被拒__d70007[maintenance-as-production]", - "tests/集成/test_数据库连接与迁移.py::test_用途角色不匹配被拒__d70007[production-as-evaluation]", - "tests/集成/test_数据库连接与迁移.py::test_用途角色不匹配被拒__d70007[production-as-maintenance]" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "声明用途", - "数据库底座", - "测试资源接缝", - "源码资源", - "登录用途", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, - { - "case_id": "NC-db-readonly-write", - "environment": "隔离 PostgreSQL", - "given": "维护角色连接且附加普通 options", - "when": "请求只读并写入", - "then": [ - "两种 options 下 PostgreSQL 都拒绝写入" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_只读连接拒绝写__d50005", - "parameter_ids": [ - "default", - "options" - ], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_只读连接拒绝写__d50005[default]", - "tests/集成/test_数据库连接与迁移.py::test_只读连接拒绝写__d50005[options]" - ], - "fixtures": [ - "options", - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, - { - "case_id": "NC-db-savepoint", - "environment": "隔离 PostgreSQL", - "given": "两种提交模式下已写入的外层事务", - "when": "保存点内写入后失败", - "then": [ - "局部回滚,外层提交且新连接可见" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_保存点局部失败保留外层事务__d90009", - "parameter_ids": [ - "auto", - "manual" - ], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_保存点局部失败保留外层事务__d90009[auto]", - "tests/集成/test_数据库连接与迁移.py::test_保存点局部失败保留外层事务__d90009[manual]" - ], - "fixtures": [ - "autocommit", - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, - { - "case_id": "NC-db-txn-rollback", - "environment": "隔离 PostgreSQL", - "given": "默认或自动提交连接", - "when": "事务第二参与者失败", - "then": [ - "全部写入回滚且错误不包含参与者原文" - ], - "contract": "docs/系统架构/新版设计/文件设计/数据库与迁移.md", - "file": "tests/集成/test_数据库连接与迁移.py", - "symbol": "test_事务回滚不留半成品__d60006", - "parameter_ids": [ - "auto", - "manual" - ], - "node_ids": [ - "tests/集成/test_数据库连接与迁移.py::test_事务回滚不留半成品__d60006[auto]", - "tests/集成/test_数据库连接与迁移.py::test_事务回滚不留半成品__d60006[manual]" - ], - "fixtures": [ - "autocommit", - "request", - "tmp_path", - "tmp_path_factory", - "临时库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, { "case_id": "NC-document-chinese-format", "environment": "离线纯正文格式与合成夹具", @@ -7277,36 +6537,6 @@ ], "markers": [] }, - { - "case_id": "NC-meta-binding-rollback-history", - "environment": "隔离 PostgreSQL,每例独占新库", - "given": "已启用结构", - "when": "发布作品扩展、回滚与重复内置导入", - "then": [ - "版本固定且旧值可回读。" - ], - "contract": "docs/系统架构/新版设计/接口契约/元数据投影与版本.md", - "file": "tests/集成/test_结构版本与并发保护.py", - "symbol": "test_扩展发布保留历史绑定且回滚不留半成品__a42002", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_结构版本与并发保护.py::test_扩展发布保留历史绑定且回滚不留半成品__a42002" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "元数据库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-meta-change-impact", "environment": "离线,固定结构及合成候选值", @@ -7385,42 +6615,6 @@ ], "markers": [] }, - { - "case_id": "NC-meta-concurrent-submit-guard", - "environment": "隔离 PostgreSQL,每例独占新库", - "given": "已预览候选", - "when": "提交持有结构锁且另连接切换", - "then": [ - "切换等待且旧请求在切换后拒绝。" - ], - "contract": "docs/系统架构/新版设计/接口契约/元数据投影与版本.md", - "file": "tests/集成/test_结构版本与并发保护.py", - "symbol": "test_结构策略切换与业务提交共享锁__a42004", - "parameter_ids": [ - "policy-revoke", - "schema-switch" - ], - "node_ids": [ - "tests/集成/test_结构版本与并发保护.py::test_结构策略切换与业务提交共享锁__a42004[policy-revoke]", - "tests/集成/test_结构版本与并发保护.py::test_结构策略切换与业务提交共享锁__a42004[schema-switch]" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "元数据库", - "变更类别", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "parametrize", - "数据库" - ] - }, { "case_id": "NC-meta-conditional-fields", "environment": "离线,固定结构及合成候选值", @@ -7572,36 +6766,6 @@ ], "markers": [] }, - { - "case_id": "NC-meta-immutable-extensions", - "environment": "隔离 PostgreSQL,每例独占新库", - "given": "已发布结构与作品扩展", - "when": "覆盖同版本或删除既有扩展", - "then": [ - "历史定义保持不变。" - ], - "contract": "docs/系统架构/新版设计/接口契约/元数据投影与版本.md", - "file": "tests/集成/test_结构版本与并发保护.py", - "symbol": "test_已发布定义与扩展追加合同不可绕过__a42005", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_结构版本与并发保护.py::test_已发布定义与扩展追加合同不可绕过__a42005" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "元数据库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-meta-nested-binding", "environment": "离线纯规则", @@ -7753,66 +6917,6 @@ "parametrize" ] }, - { - "case_id": "NC-meta-reviewed-version-binding", - "environment": "隔离 PostgreSQL,每例独占新库", - "given": "已启用结构", - "when": "候选未发布或预期版本过期", - "then": [ - "不改变当前绑定。" - ], - "contract": "docs/系统架构/新版设计/接口契约/元数据投影与版本.md", - "file": "tests/集成/test_结构版本与并发保护.py", - "symbol": "test_候选未发布与过期绑定均不可启用__a42003", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_结构版本与并发保护.py::test_候选未发布与过期绑定均不可启用__a42003" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "元数据库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-meta-seed-import-pg", - "environment": "隔离 PostgreSQL,每例独占新库", - "given": "隔离空库", - "when": "两次导入种子", - "then": [ - "24 个固定版本可回读且没有隐式绑定。" - ], - "contract": "docs/系统架构/新版设计/接口契约/元数据投影与版本.md", - "file": "tests/集成/test_结构版本与并发保护.py", - "symbol": "test_内置发布可重复且不自动启用__a42001", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_结构版本与并发保护.py::test_内置发布可重复且不自动启用__a42001" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "元数据库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-meta-seed-semantics", "environment": "离线,固定结构及合成候选值", @@ -10956,68 +10060,6 @@ "file": "web/tests/交互/选区定位.test.ts", "symbol": "NC-selection-unicode:表情、组合字符和CRLF不使用UTF16假码点" }, - { - "case_id": "NC-task-cancel-fencing", - "environment": "隔离PostgreSQL", - "given": "正在执行且持有作品范围的任务", - "when": "作者取消后旧结果到达", - "then": [ - "拒绝迟到写入并允许新任务取得范围" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_取消后拒绝旧结果并释放作品范围__a51004", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_取消后拒绝旧结果并释放作品范围__a51004" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-control-idempotent", - "environment": "隔离PostgreSQL", - "given": "重复或异参数的任务控制请求", - "when": "控制同一持久化任务", - "then": [ - "同命令返回原回执且不重复事件,异参数拒绝" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_控制命令重放不重复事件且异参数拒绝__a5100b", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_控制命令重放不重复事件且异参数拒绝__a5100b" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-task-durable-restart", "environment": "隔离PostgreSQL", @@ -11049,317 +10091,6 @@ "数据库" ] }, - { - "case_id": "NC-task-event-reconnect", - "environment": "隔离PostgreSQL", - "given": "有序事件及固定事件身份", - "when": "重复提交、同 ID 不同内容及实际删除中间事件", - "then": [ - "重复幂等、冲突拒绝、游标缺口要求任务快照" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_事件重复幂等且游标缺口要求快照__a51007", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_事件重复幂等且游标缺口要求快照__a51007" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-failure-stop", - "environment": "隔离PostgreSQL", - "given": "处理器失败和待执行任务", - "when": "记录失败并停止当前进程领取", - "then": [ - "失败不变成功,重建服务可领取持久任务" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_失败如实保留且停止领取不丢状态__a51008", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_失败如实保留且停止领取不丢状态__a51008" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-lease-fencing", - "environment": "隔离PostgreSQL", - "given": "持久检查点及已过期租约", - "when": "新执行者接管,旧执行者提交或续租", - "then": [ - "旧身份被拒,新持有代次递增且检查点保留" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_过期接管拒绝旧步骤和作用域代次__a51003", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_过期接管拒绝旧步骤和作用域代次__a51003" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-list-scope", - "environment": "隔离PostgreSQL", - "given": "不同作者和作品的已登记任务", - "when": "列出当前作者和作品任务", - "then": [ - "只返回匹配的真实任务" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_任务列表按作者作品及用途隔离__a5100c", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_任务列表按作者作品及用途隔离__a5100c" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-purpose-isolation", - "environment": "隔离PostgreSQL", - "given": "相同命令的生产和评测任务", - "when": "各自数据库角色领取和查询", - "then": [ - "分别持久执行且不能跨用途读取任务" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_生产评测任务使用独立权限与实例__a51009", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_生产评测任务使用独立权限与实例__a51009" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-registered-revalidation", - "environment": "隔离 PostgreSQL、具名接入;合成 owner 检查", - "given": "暂停任务和登记的合成 owner 来源、结构、授权与预算检查", - "when": "从 HTTP/CLI 共用入口恢复并重放命令", - "then": [ - "当前来源不匹配时保持暂停", - "重验通过后排队,重复命令返回相同回执" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_具名接入恢复由登记owner重验__a5100f", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_具名接入恢复由登记owner重验__a5100f" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-resume-revalidation", - "environment": "隔离PostgreSQL", - "given": "暂停任务及已保存检查点", - "when": "重建服务并提供业务恢复校验", - "then": [ - "校验失败仍暂停,合法恢复保留检查点" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_暂停恢复重验且检查点持久保留__a51005", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_暂停恢复重验且检查点持久保留__a51005" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-scope-competition", - "environment": "隔离PostgreSQL", - "given": "同作品两任务与另一作品任务", - "when": "两个独立连接并发领取", - "then": [ - "同范围仅一个持有者,另一范围可并行" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_独立连接竞争同范围而不同范围可并行__a51002", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_独立连接竞争同范围而不同范围可并行__a51002" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-short-transaction", - "environment": "隔离PostgreSQL", - "given": "已领取任务的真实处理器", - "when": "隔离集群管理员检查 pg_stat_activity", - "then": [ - "处理器期间目标库不存在悬挂事务" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_处理器调用期间不持有数据库事务__a5100a", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_处理器调用期间不持有数据库事务__a5100a" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-task-step-order", - "environment": "隔离PostgreSQL", - "given": "不同于字典序的冻结流程", - "when": "读取任务步骤", - "then": [ - "按冻结流程顺序显示" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_任务步骤按冻结流程顺序显示__a5100d", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_任务步骤按冻结流程顺序显示__a5100d" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-task-unknown-reconciliation", "environment": "隔离PostgreSQL", @@ -25712,6 +24443,7 @@ "测试资源接缝", "源码资源", "离线防护", + "脏账本还原", "隔离数据库URL" ], "markers": [ @@ -25744,6 +24476,7 @@ "测试资源接缝", "源码资源", "离线防护", + "脏账本还原", "隔离数据库URL" ], "markers": [ @@ -26071,105 +24804,11 @@ ], "markers": [] }, - { - "case_id": "NC-w29-29b001", - "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "完整PG文件权限关系与动态内容实际往返" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_完整PG文件权限关系与动态内容实际往返__29b001", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_完整PG文件权限关系与动态内容实际往返__29b001" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-w29-29b002", - "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "并发业务写锁存在时备份立即失败且无半成品" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_并发业务写锁存在时备份立即失败且无半成品__29b002", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_并发业务写锁存在时备份立即失败且无半成品__29b002" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-w29-29b003", - "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "数据库归档损坏与清单字段篡改均在连接目标前拒绝" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_数据库归档损坏与清单字段篡改均在连接目标前拒绝__29b003", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_数据库归档损坏与清单字段篡改均在连接目标前拒绝__29b003" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-w29-29b004", "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", + "given": "显式隔离配置与合成数据", + "when": "向来源库或已有内容目标发起恢复", "then": [ "拒绝来源库与已有内容目标且不覆盖文件" ], @@ -26197,170 +24836,6 @@ "数据库" ] }, - { - "case_id": "NC-w29-29b005", - "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "pg_restore中途失败时单事务回滚并清理文件目标" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_pg_restore中途失败时单事务回滚并清理文件目标__29b005", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_pg_restore中途失败时单事务回滚并清理文件目标__29b005" - ], - "fixtures": [ - "caplog", - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-w29-29b006", - "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "错误客户端输出不回显DSN凭据或绝对来源" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_错误客户端输出不回显DSN凭据或绝对来源__29b006", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_错误客户端输出不回显DSN凭据或绝对来源__29b006" - ], - "fixtures": [ - "caplog", - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-w29-29b007", - "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "默认ACL等价归一仍拒绝恢复后额外生产权限" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_默认ACL等价归一仍拒绝恢复后额外生产权限__29b007", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_默认ACL等价归一仍拒绝恢复后额外生产权限__29b007" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-w29-29b008", - "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "维护CLI断源恢复真实候选正文与排队交付任务" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/集成/test_数据维护与恢复.py", - "symbol": "test_维护CLI断源恢复真实候选正文与排队交付任务__29b008", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据维护与恢复.py::test_维护CLI断源恢复真实候选正文与排队交付任务__29b008" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "交付环境", - "候选环境", - "内置种子方案", - "内置结构测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, - { - "case_id": "NC-w29-29b009", - "environment": "隔离PG", - "given": "显式隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "认证备份目录核对下载不依赖可用源库并拒绝坏份" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/集成/test_数据维护与恢复.py", - "symbol": "test_认证备份目录核对下载不依赖可用源库并拒绝坏份__29b009", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_数据维护与恢复.py::test_认证备份目录核对下载不依赖可用源库并拒绝坏份__29b009" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-w29-29c001", "environment": "隔离PG", @@ -26744,40 +25219,6 @@ "数据库" ] }, - { - "case_id": "NC-w29-29f005", - "environment": "隔离PG", - "given": "显式作者、隔离配置、合成数据与已知发布构建", - "when": "经真实维护、业务或浏览器入口执行并读取持久结果", - "then": [ - "断源恢复模型任务只补未执行步骤并保持原预算与候选" - ], - "contract": "docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", - "file": "tests/集成/test_模型任务备份恢复.py", - "symbol": "test_断源恢复模型任务只补未执行步骤并保持原预算与候选__29f005", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_模型任务备份恢复.py::test_断源恢复模型任务只补未执行步骤并保持原预算与候选__29f005" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "内置种子方案", - "内置结构测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "生成环境", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-w30-c0f001", "environment": "离线单元;客户端替身,不证明真实PG备份成功", @@ -28333,37 +26774,6 @@ "数据库" ] }, - { - "case_id": "NC-worker-heartbeat-stop", - "environment": "隔离PostgreSQL", - "given": "执行时间超过原租期的处理器", - "when": "运行执行器并停止", - "then": [ - "自动续租完成当前步骤,停止后不领取后续" - ], - "contract": "docs/系统架构/新版设计/接口契约/任务工具与事件.md", - "file": "tests/集成/test_任务租约与恢复.py", - "symbol": "test_执行器续租并在停止后不领取新步骤__a5100e", - "parameter_ids": [], - "node_ids": [ - "tests/集成/test_任务租约与恢复.py::test_执行器续租并在停止后不领取新步骤__a5100e" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "任务库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "NC-world-actor-knowledge-time", "environment": "真实隔离PostgreSQL与S01/B02", @@ -29854,7 +28264,7 @@ { "case_id": "TC-0f7c45927fbe", "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", + "when": "备份、校验、恢复。", "contract": "docs/系统架构/新版设计/迁移与验收.md", "file": "tests/迁移/test_备份恢复与切换核对.py", "symbol": "test_备份单快照七域往返且同内容重放一致__0f7c45", @@ -30794,35 +29204,6 @@ ], "markers": [] }, - { - "case_id": "TC-2b32b67a3482", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_恢复要求资源发布身份与安装一致并在连接前拒绝__2b32b6", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_恢复要求资源发布身份与安装一致并在连接前拒绝__2b32b6" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-2bd29465a077", "environment": "离线新版匿名、引文、语义与文学仲裁公开合同;不认证真实派发或外部模型", @@ -30842,35 +29223,6 @@ ], "markers": [] }, - { - "case_id": "TC-2d7f171ffd33", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_资源构建身份漂移在连接前拒绝恢复__2d7f17", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_资源构建身份漂移在连接前拒绝恢复__2d7f17" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-2d83b2dca999", "environment": "离线数值合同", @@ -32265,32 +30617,6 @@ ], "markers": [] }, - { - "case_id": "TC-545fb1541c3a", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_备份清单拒绝重复键和未知字段__545fb1", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_备份清单拒绝重复键和未知字段__545fb1" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-566cefcd2cd9", "environment": "离线新版匿名、引文、语义与文学仲裁公开合同;不认证真实派发或外部模型", @@ -33112,34 +31438,6 @@ ], "markers": [] }, - { - "case_id": "TC-6740be8d17a3", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_序列恢复只向前且保持确认__6740be", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_序列恢复只向前且保持确认__6740be" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-679e5ea919c9", "environment": "真实业务入口与隔离 PostgreSQL,评测替身须明示", @@ -33402,32 +31700,6 @@ "数据库" ] }, - { - "case_id": "TC-74a6ec3a8017", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_非维护用途在创建备份前拒绝__74a6ec", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_非维护用途在创建备份前拒绝__74a6ec" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-75676077ad55", "environment": "隔离PG、真实S02及合成HTTP", @@ -33749,35 +32021,6 @@ ], "markers": [] }, - { - "case_id": "TC-7c7fadfd3680", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_占用的恢复文件目标在破坏性写入前拒绝__7c7fad", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_占用的恢复文件目标在破坏性写入前拒绝__7c7fad" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-7ca68e954f35", "environment": "隔离PG、真实S02与合成HTTP;不认证外部模型质量", @@ -34162,35 +32405,6 @@ ], "markers": [] }, - { - "case_id": "TC-863e5ced39df", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_备份确认不匹配不创建业务连接__863e5c", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_备份确认不匹配不创建业务连接__863e5c" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-86ec39ac775c", "environment": "离线新版匿名、引文、语义与文学仲裁公开合同;不认证真实派发或外部模型", @@ -34992,32 +33206,6 @@ "数据库" ] }, - { - "case_id": "TC-9a68f7f96bf6", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_文件归档意外损坏后离线核对失败__9a68f7", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_文件归档意外损坏后离线核对失败__9a68f7" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-9a7e59fe1698", "environment": "离线新版匿名、引文、语义与文学仲裁公开合同;不认证真实派发或外部模型", @@ -35751,35 +33939,6 @@ "数据库" ] }, - { - "case_id": "TC-a0e1e2234d2d", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_缺少可用备份在取锁连接前失败__a0e1e2", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_缺少可用备份在取锁连接前失败__a0e1e2" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-a0fd532aef44", "environment": "隔离 PostgreSQL,检测替身", @@ -36566,34 +34725,6 @@ "数据库" ] }, - { - "case_id": "TC-b40e21e62183", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_磁盘归档摘要漂移在恢复任何写入前失败__b40e21", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_磁盘归档摘要漂移在恢复任何写入前失败__b40e21" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-b430df49f1e4", "environment": "离线,固定原文与引用", @@ -36832,6 +34963,36 @@ ], "markers": [] }, + { + "case_id": "TC-base-0001", + "environment": "隔离PG", + "given": "全新空库与包内基线 SQL", + "when": "以维护用途执行基线迁移", + "then": [ + "账本登记基线版本,生产角色可连接并读取结构" + ], + "file": "tests/集成/test_数据库连接与迁移.py", + "symbol": "test_空库执行基线登记账本且业务角色可连__base001", + "parameter_ids": [], + "node_ids": [ + "tests/集成/test_数据库连接与迁移.py::test_空库执行基线登记账本且业务角色可连__base001" + ], + "fixtures": [ + "request", + "tmp_path", + "tmp_path_factory", + "临时库", + "数据库底座", + "测试资源接缝", + "源码资源", + "离线防护", + "空测试库", + "隔离数据库URL" + ], + "markers": [ + "数据库" + ] + }, { "case_id": "TC-bb1f26f796ff", "environment": "离线新版匿名、引文、语义与文学仲裁公开合同;不认证真实派发或外部模型", @@ -37037,35 +35198,6 @@ ], "markers": [] }, - { - "case_id": "TC-c2a43647c057", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_备份迁移与安装清单漂移在恢复任何客户端前拒绝__c2a436", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_备份迁移与安装清单漂移在恢复任何客户端前拒绝__c2a436" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-c45d9e768e76", "environment": "离线纯规则", @@ -37257,35 +35389,6 @@ "parametrize" ] }, - { - "case_id": "TC-c8063c15e318", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_恢复在并发维护锁下不执行数据库客户端__c8063c", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_恢复在并发维护锁下不执行数据库客户端__c8063c" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-c83b1ea9504a", "environment": "隔离 PostgreSQL,检测替身", @@ -37549,35 +35652,6 @@ ], "markers": [] }, - { - "case_id": "TC-d07d1f9ee590", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_恢复后复核失败清理文件根并报错__d07d1f", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_恢复后复核失败清理文件根并报错__d07d1f" - ], - "fixtures": [ - "monkeypatch", - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-d0e17d43037f", "environment": "离线,固定原文与引用", @@ -38482,34 +36556,6 @@ "数据库" ] }, - { - "case_id": "TC-e95a51d27a2b", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_相同主键集合的确定性清单与特殊数据库类型往返__e95a51", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_相同主键集合的确定性清单与特殊数据库类型往返__e95a51" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "新空目标库", - "测试资源接缝", - "源码资源", - "离线防护", - "空测试库", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-ea9587d92a04", "environment": "离线组件测试;正式写入另有真后端旅程", @@ -38699,32 +36745,6 @@ ], "markers": [] }, - { - "case_id": "TC-f14761e9f048", - "environment": "隔离 PostgreSQL 与临时目录", - "when": "备份、校验、恢复或模拟切换失败。", - "contract": "docs/系统架构/新版设计/迁移与验收.md", - "file": "tests/迁移/test_备份恢复与切换核对.py", - "symbol": "test_备份输出只允许全新目录且不与来源重叠__f14761", - "parameter_ids": [], - "node_ids": [ - "tests/迁移/test_备份恢复与切换核对.py::test_备份输出只允许全新目录且不与来源重叠__f14761" - ], - "fixtures": [ - "request", - "tmp_path", - "tmp_path_factory", - "应用测试库", - "数据库底座", - "测试资源接缝", - "源码资源", - "离线防护", - "隔离数据库URL" - ], - "markers": [ - "数据库" - ] - }, { "case_id": "TC-f1f21ad8eece", "environment": "离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果", diff --git a/tests/迁移/test_备份恢复与切换核对.py b/tests/迁移/test_备份恢复与切换核对.py index 8ba5ee9..02d3705 100644 --- a/tests/迁移/test_备份恢复与切换核对.py +++ b/tests/迁移/test_备份恢复与切换核对.py @@ -1,21 +1,23 @@ +"""备份恢复的核心保护:七域真实往返与拒绝覆盖非空目标。 + +个人工具的最小安全网——全部作品资产在一个 PG 库里,备份必须能真恢复, +恢复不得覆盖任何已有内容。其余切换/篡改/权限变体用例已按简化决策删除。 +""" + from __future__ import annotations -import hashlib import json from decimal import Decimal from pathlib import Path from types import SimpleNamespace import pytest -from psycopg.conninfo import conninfo_to_dict, make_conninfo from muse.共享.调用身份 import 用途 -from muse.基础设施 import 备份恢复 from muse.基础设施.备份恢复 import 创建备份, 备份恢复错误, 恢复备份, 核对备份 -from muse.基础设施.数据库.维护锁 import 迁移维护锁 from muse.基础设施.数据库.连接 import 数据库工厂 from muse.资源加载 import 加载清单 -from muse.配置 import 应用配置, 数据库引用 +from muse.配置 import 应用配置 pytestmark = pytest.mark.数据库 @@ -24,47 +26,13 @@ def _资源身份() -> str: return 加载清单()["构建身份"] -敏感标记 = "w29-password-must-never-leak" - - -def _断言目标尚无迁移表(工厂: 数据库工厂) -> None: - with 工厂.连接() as 连: - assert 连.execute("SELECT to_regclass('public.muse_migration')").fetchone() == (None,) - - -def _记录客户端动作(monkeypatch: pytest.MonkeyPatch) -> list[str]: - 动作: list[str] = [] - 原始 = 备份恢复._运行客户端 - - def 记录(命令, 参数, 引用, 动作名): - 动作.append(动作名) - 原始(命令, 参数, 引用, 动作名) - - monkeypatch.setattr(备份恢复, "_运行客户端", 记录) - return 动作 - - -def _记录客户端命令(monkeypatch: pytest.MonkeyPatch) -> list[list[str]]: - 命令行 = [] - 原始 = 备份恢复.subprocess.run - - def 记录(args, **kwargs): - 命令行.append(list(args)) - return 原始(args, **kwargs) - - monkeypatch.setattr(备份恢复.subprocess, "run", 记录) - return 命令行 - - def _应用配置( 工厂: 数据库工厂, raw: Path, drafts: Path, - *, - 引用: 数据库引用 | None = None, ) -> 应用配置: return 应用配置( - 引用 or 工厂.引用, + 工厂.引用, _资源身份(), 运行用途=用途.维护, 原文暂存=str(raw), @@ -72,16 +40,6 @@ def _应用配置( ) -def _带敏感值引用(工厂: 数据库工厂, tmp_path: Path, 名称: str) -> 数据库引用: - 原串 = Path(工厂.引用.位置).read_text(encoding="utf-8") - 参数 = conninfo_to_dict(原串) - 参数["password"] = 敏感标记 - 路径 = tmp_path / 名称 - 路径.write_text(make_conninfo(**参数), encoding="utf-8") - 路径.chmod(0o600) - return 数据库引用("受控存储", str(路径)) - - def _准备文件(tmp_path: Path, 前缀: str) -> tuple[Path, Path]: raw = tmp_path / f"{前缀}-raw" drafts = tmp_path / f"{前缀}-drafts" @@ -126,130 +84,80 @@ def _建立数据库探针(工厂: 数据库工厂) -> None: ) +def _建立类型探针(维护工厂: 数据库工厂) -> None: + """decimal 精度、timestamptz、嵌套 jsonb 与序列推进,供确定性往返用。""" + with 维护工厂.连接() as 连, 连.transaction(): + 连.execute("DROP TABLE IF EXISTS public.w29_seq_probe, public.w29_typed CASCADE") + 连.execute( + """ + CREATE TABLE public.w29_typed ( + id integer PRIMARY KEY, + at timestamptz NOT NULL, + score numeric(10,4) NOT NULL, + payload jsonb NOT NULL + ); + CREATE TABLE public.w29_seq_probe ( + id serial PRIMARY KEY, + note text NOT NULL + ); + """ + ) + 连.execute( + "INSERT INTO public.w29_typed VALUES (%s,%s,%s,%s)", + ( + 10, + "2026-07-21T08:00:00+00", + Decimal("1.2300"), + json.dumps({"扩展": {"层级": [1, "二"]}}), + ), + ) + 连.execute( + "INSERT INTO public.w29_typed VALUES (%s,%s,%s,%s)", + (2, "2026-07-20T00:00:00+00", Decimal("0.10"), json.dumps({"序": 2})), + ) + + @pytest.mark.case_id( - "NC-w29-29b001", - environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["完整PG文件权限关系与动态内容实际往返"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", + "TC-0f7c45927fbe", + environment="隔离 PostgreSQL 与临时目录", + when="备份、校验、恢复。", + contract="docs/系统架构/新版设计/迁移与验收.md", ) -def test_完整PG文件权限关系与动态内容实际往返__29b001( +def test_备份单快照七域往返且同内容重放一致__0f7c45( 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path ) -> None: + """数据库与文件进入同一份校验清单;关闭连接后从磁盘复验一致。""" 来源工厂 = 应用测试库[用途.维护] - _建立数据库探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "source") - 敏感引用 = _带敏感值引用(来源工厂, tmp_path, "source-secret.txt") - 来源配置 = _应用配置(来源工厂, raw, drafts, 引用=敏感引用) - 备份目录 = tmp_path / "backup" - - 清单 = 创建备份(来源配置, 备份目录) - 目标raw = tmp_path / "restored-raw" - 目标drafts = tmp_path / "restored-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - 结果 = 恢复备份(备份目录, 目标配置, 清单["backup_id"]) - - assert 结果["status"] == "verified" - assert 结果["services_started"] is False - assert 结果["external_model_calls_restored"] is False - assert 核对备份(备份目录) == 清单 - assert (目标raw / "供应方原文.bin").read_bytes() == b"\x00\xffraw-evidence\x80" - assert (目标drafts / "第一章 草稿.txt").read_text(encoding="utf-8") == "风从旧城来。\n" - with 新空目标库.工厂.连接() as 连: - 行 = 连.execute( - "SELECT dynamic_payload, raw_bytes FROM public.w29_parent WHERE id = 'parent-1'" - ).fetchone() - assert 行 == ( - {"扩展字段": {"层级": [1, "二", {"保留": True}]}}, - b"\x00\xff\x10" + "原文-bytea".encode(), - ) - assert 连.execute( - "SELECT audit_note FROM public.w29_child WHERE parent_id = 'parent-1'" - ).fetchone() == ("审计理由保留",) - assert 连.execute( - "SELECT has_table_privilege('muse_app', 'public.w29_parent', 'SELECT'), " - "has_table_privilege('muse_eval', 'public.w29_parent', 'SELECT')" - ).fetchone() == (True, True) - assert 连.execute( - "SELECT count(*) FROM pg_constraint WHERE conrelid = 'public.w29_child'::regclass " - "AND contype = 'f'" - ).fetchone() == (1,) - 清单正文 = (备份目录 / "manifest.json").read_text(encoding="utf-8") - assert 敏感标记 not in 清单正文 - assert str(raw) not in 清单正文 - assert str(drafts) not in 清单正文 - assert 来源工厂.引用.位置 not in 清单正文 - - -@pytest.mark.case_id( - "NC-w29-29b002", - environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["并发业务写锁存在时备份立即失败且无半成品"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", -) -def test_并发业务写锁存在时备份立即失败且无半成品__29b002(应用测试库: dict, tmp_path: Path) -> None: - 维护工厂 = 应用测试库[用途.维护] - _建立数据库探针(维护工厂) - raw, drafts = _准备文件(tmp_path, "locked") - 配置 = _应用配置(维护工厂, raw, drafts) - 输出 = tmp_path / "locked-backup" - with 应用测试库[用途.生产].连接() as 写连, 写连.transaction(): - 写连.execute( - "INSERT INTO public.w29_parent VALUES (%s, %s, %s)", - ("uncommitted", json.dumps({"状态": "writing"}), b"pending"), - ) - with pytest.raises(备份恢复错误, match="备份锁"): - 创建备份(配置, 输出, pg_dump命令="should-not-run") - assert not 输出.exists() - - -@pytest.mark.case_id( - "NC-w29-29b003", - environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["数据库归档损坏与清单字段篡改均在连接目标前拒绝"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", -) -def test_数据库归档损坏与清单字段篡改均在连接目标前拒绝__29b003( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path -) -> None: - 来源工厂 = 应用测试库[用途.维护] - _建立数据库探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "damaged") - 备份目录 = tmp_path / "damaged-backup" + _建立类型探针(来源工厂) + raw, drafts = _准备文件(tmp_path, "domains") + 备份目录 = tmp_path / "domains-backup" 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = tmp_path / "target-raw", tmp_path / "target-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) + 复验 = 核对备份(备份目录) + assert 复验 == 清单 + assert set(清单["database"]) == { + "archive", + "size", + "sha256", + "source_fingerprint", + "fingerprint_scope", + "server_version_num", + "migrations", + "summary", + } + assert 清单["database"]["migrations"] and 清单["file_archive"]["file_count"] == 2 + assert 清单["file_archive"]["roots"] == ["drafts", "raw"] - 数据库归档 = 备份目录 / "database.dump" - 原字节 = 数据库归档.read_bytes() - 数据库归档.write_bytes(原字节[:-1] + bytes([原字节[-1] ^ 0xFF])) - 数据库归档.chmod(0o600) - with pytest.raises(备份恢复错误, match="哈希"): - 恢复备份(备份目录, 目标配置, 清单["backup_id"]) - assert not 目标raw.exists() and not 目标drafts.exists() - _断言目标尚无迁移表(新空目标库.工厂) - - 数据库归档.write_bytes(原字节) - 数据库归档.chmod(0o600) - 清单路径 = 备份目录 / "manifest.json" - 篡改 = json.loads(清单路径.read_text(encoding="utf-8")) - 篡改["resource_release"] = "tampered-release" - 清单路径.write_text(json.dumps(篡改), encoding="utf-8") - 清单路径.chmod(0o600) - with pytest.raises(备份恢复错误, match="备份ID"): - 核对备份(备份目录) + 目标raw, 目标drafts = tmp_path / "domains-target-raw", tmp_path / "domains-target-drafts" + 恢复备份(备份目录, _应用配置(新空目标库.工厂, 目标raw, 目标drafts), 清单["backup_id"]) + with 新空目标库.工厂.连接() as 连: + assert 连.execute("SELECT count(*) FROM public.w29_typed").fetchone() == (2,) @pytest.mark.case_id( "NC-w29-29b004", environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", + given="显式隔离配置与合成数据", + when="向来源库或已有内容目标发起恢复", then=["拒绝来源库与已有内容目标且不覆盖文件"], contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", ) @@ -282,588 +190,3 @@ def test_拒绝来源库与已有内容目标且不覆盖文件__29b004( with 新空目标库.工厂.连接() as 连: assert 连.execute("SELECT value FROM public.keep_me").fetchone() == ("保留",) assert not 目标raw.exists() and not 目标drafts.exists() - - -@pytest.mark.case_id( - "NC-w29-29b005", - environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["pg_restore中途失败时单事务回滚并清理文件目标"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", -) -def test_pg_restore中途失败时单事务回滚并清理文件目标__29b005( - 应用测试库: dict, - 新空目标库: SimpleNamespace, - tmp_path: Path, - monkeypatch: pytest.MonkeyPatch, - caplog: pytest.LogCaptureFixture, -) -> None: - 来源工厂 = 应用测试库[用途.维护] - _建立数据库探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "rollback") - 备份目录 = tmp_path / "rollback-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw = tmp_path / "rollback-target-raw" - 目标drafts = tmp_path / "rollback-target-drafts" - 敏感引用 = _带敏感值引用(新空目标库.工厂, tmp_path, "restore-secret.txt") - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts, 引用=敏感引用) - 命令行 = _记录客户端命令(monkeypatch) - 原运行 = 备份恢复._运行客户端 - - def 注入恢复竞争(命令: str, 参数: tuple[str, ...], 引用: 数据库引用, 动作: str) -> None: - if 动作 == "数据库恢复": - with 数据库工厂(引用, 用途.维护).连接() as 连, 连.transaction(): - 连.execute( - "CREATE TABLE public.muse_migration " - "(version integer PRIMARY KEY, marker text NOT NULL)" - ) - 连.execute("INSERT INTO public.muse_migration VALUES (9999, 'keep-race-marker')") - 原运行(命令, 参数, 引用, 动作) - - monkeypatch.setattr(备份恢复, "_运行客户端", 注入恢复竞争) - with pytest.raises(备份恢复错误, match="^数据库恢复客户端失败$") as 捕获: - 恢复备份(备份目录, 目标配置, 清单["backup_id"]) - - assert 命令行 - assert 敏感标记 not in str(捕获.value.呈现()) - assert 敏感标记 not in caplog.text - assert 敏感标记 not in json.dumps(命令行) - assert not 目标raw.exists() and not 目标drafts.exists() - with 新空目标库.工厂.连接() as 连: - assert 连.execute("SELECT marker FROM public.muse_migration").fetchone() == ( - "keep-race-marker", - ) - assert 连.execute("SELECT to_regnamespace('metadata')").fetchone() == (None,) - assert 连.execute("SELECT to_regtype('public.muse_purpose')").fetchone() == (None,) - - -@pytest.mark.case_id( - "NC-w29-29b006", - environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["错误客户端输出不回显DSN凭据或绝对来源"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", -) -def test_错误客户端输出不回显DSN凭据或绝对来源__29b006( - 应用测试库: dict, - tmp_path: Path, - monkeypatch: pytest.MonkeyPatch, - caplog: pytest.LogCaptureFixture, -) -> None: - 来源工厂 = 应用测试库[用途.维护] - _建立数据库探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "secret") - 引用 = _带敏感值引用(来源工厂, tmp_path, "failed-secret.txt") - 配置 = _应用配置(来源工厂, raw, drafts, 引用=引用) - 假客户端 = tmp_path / "failing-pg-dump" - 假客户端.write_text('#!/bin/sh\nprintf "%s" "$PGPASSWORD" >&2\nexit 1\n') - 假客户端.chmod(0o700) - 命令行 = _记录客户端命令(monkeypatch) - - with pytest.raises(备份恢复错误) as 捕获: - 创建备份(配置, tmp_path / "failed-backup", pg_dump命令=str(假客户端)) - - 呈现 = json.dumps(捕获.value.呈现(), ensure_ascii=False) - assert 命令行 - assert 捕获.value.说明 == "数据库备份客户端失败" - assert 捕获.value.上下文["stderr_sha256"] == hashlib.sha256(敏感标记.encode()).hexdigest() - assert 敏感标记 not in caplog.text - assert 敏感标记 not in json.dumps(命令行) - assert 敏感标记 not in 呈现 - assert str(raw) not in 呈现 - assert str(drafts) not in 呈现 - assert 来源工厂.引用.位置 not in 呈现 - assert not (tmp_path / "failed-backup").exists() - - -@pytest.mark.case_id( - "NC-w29-29b007", - environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["默认ACL等价归一仍拒绝恢复后额外生产权限"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", -) -def test_默认ACL等价归一仍拒绝恢复后额外生产权限__29b007( - 应用测试库, 新空目标库, tmp_path, monkeypatch -): - raw, drafts = _准备文件(tmp_path, "acl-source") - source = _应用配置(应用测试库[用途.维护], raw, drafts) - archive = tmp_path / "acl-backup" - record = 创建备份(source, archive) - target = _应用配置(新空目标库.工厂, tmp_path / "acl-raw", tmp_path / "acl-drafts") - original = 备份恢复._运行客户端 - - def changed(command, args, reference, action): - original(command, args, reference, action) - if action == "数据库恢复": - with 数据库工厂(reference, 用途.维护).连接() as conn, conn.transaction(): - conn.execute("GRANT SELECT ON public.muse_enablement_receipt TO muse_app") - - monkeypatch.setattr(备份恢复, "_运行客户端", changed) - with pytest.raises(备份恢复错误, match="权限或关系摘要不一致"): - 恢复备份(archive, target, record["backup_id"]) - with 应用测试库[用途.维护].连接() as conn: - assert conn.execute( - "SELECT has_table_privilege('muse_app','public.muse_enablement_receipt','SELECT')" - ).fetchone() == (False,) - - -def _建立类型探针(维护工厂: 数据库工厂) -> None: - """decimal 精度、timestamptz、嵌套 jsonb 与序列推进,供确定性往返用。""" - with 维护工厂.连接() as 连, 连.transaction(): - 连.execute("DROP TABLE IF EXISTS public.w29_seq_probe, public.w29_typed CASCADE") - 连.execute( - """ - CREATE TABLE public.w29_typed ( - id integer PRIMARY KEY, - at timestamptz NOT NULL, - score numeric(10,4) NOT NULL, - payload jsonb NOT NULL - ); - CREATE TABLE public.w29_seq_probe ( - id serial PRIMARY KEY, - note text NOT NULL - ); - """ - ) - 连.execute( - "INSERT INTO public.w29_typed VALUES (%s,%s,%s,%s)", - ( - 10, - "2026-07-21T08:00:00+00", - Decimal("1.2300"), - json.dumps({"扩展": {"层级": [1, "二"]}}), - ), - ) - 连.execute( - "INSERT INTO public.w29_typed VALUES (%s,%s,%s,%s)", - (2, "2026-07-20T00:00:00+00", Decimal("0.10"), json.dumps({"序": 2})), - ) - 连.execute("INSERT INTO public.w29_seq_probe(note) VALUES ('甲'),('乙'),('丙')") - - -@pytest.mark.case_id( - "TC-e95a51d27a2b", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_相同主键集合的确定性清单与特殊数据库类型往返__e95a51( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path -) -> None: - """相同内容两次备份得到相同清单与指纹;decimal/timestamptz/jsonb 往返保持值。""" - 来源工厂 = 应用测试库[用途.维护] - _建立类型探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "typed") - 配置 = _应用配置(来源工厂, raw, drafts) - 一 = 创建备份(配置, tmp_path / "typed-backup-1") - 二 = 创建备份(配置, tmp_path / "typed-backup-2") - # 表内容、模式、约束与序列摘要按确定性顺序哈希,不因查询返回顺序改变; - # pg_dump 归档字节本身可能带非确定性头,不强求 backup_id 相同。 - assert 一["database"]["summary"] == 二["database"]["summary"] - assert 一["database"]["source_fingerprint"] == 二["database"]["source_fingerprint"] - - 目标raw, 目标drafts = tmp_path / "typed-target-raw", tmp_path / "typed-target-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - 恢复备份(tmp_path / "typed-backup-1", 目标配置, 一["backup_id"]) - with 新空目标库.工厂.连接() as 连: - 连.execute("SELECT set_config('TimeZone', 'UTC', true)") - assert 连.execute( - "SELECT id, to_char(at AT TIME ZONE 'UTC', 'YYYY-MM-DD HH24:MI:SS'), " - "score::text, payload::text FROM public.w29_typed ORDER BY id" - ).fetchall() == [ - (2, "2026-07-20 00:00:00", "0.1000", '{"序": 2}'), - ( - 10, - "2026-07-21 08:00:00", - "1.2300", - '{"扩展": {"层级": [1, "二"]}}', - ), - ] - - -@pytest.mark.case_id( - "TC-f14761e9f048", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_备份输出只允许全新目录且不与来源重叠__f14761(应用测试库: dict, tmp_path: Path) -> None: - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "path") - 配置 = _应用配置(来源工厂, raw, drafts) - 已存在 = tmp_path / "occupied" - 已存在.mkdir() - (已存在 / "保留文件").write_text("keep", encoding="utf-8") - with pytest.raises(备份恢复错误, match="全新"): - 创建备份(配置, 已存在) - assert (已存在 / "保留文件").read_text(encoding="utf-8") == "keep" - - with pytest.raises(备份恢复错误, match="重叠"): - 创建备份(配置, raw / "nested-backup") - - -@pytest.mark.case_id( - "TC-0f7c45927fbe", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_备份单快照七域往返且同内容重放一致__0f7c45( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path -) -> None: - """数据库与文件七域进入同一份校验清单;关闭连接后从磁盘复验一致。""" - 来源工厂 = 应用测试库[用途.维护] - _建立类型探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "domains") - 备份目录 = tmp_path / "domains-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 复验 = 核对备份(备份目录) - assert 复验 == 清单 - assert set(清单["database"]) == { - "archive", - "size", - "sha256", - "source_fingerprint", - "fingerprint_scope", - "server_version_num", - "migrations", - "summary", - } - assert 清单["database"]["migrations"] and 清单["file_archive"]["file_count"] == 2 - assert 清单["file_archive"]["roots"] == ["drafts", "raw"] - - 目标raw, 目标drafts = tmp_path / "domains-target-raw", tmp_path / "domains-target-drafts" - 恢复备份(备份目录, _应用配置(新空目标库.工厂, 目标raw, 目标drafts), 清单["backup_id"]) - with 新空目标库.工厂.连接() as 连: - assert 连.execute("SELECT count(*) FROM public.w29_typed").fetchone() == (2,) - - -@pytest.mark.case_id( - "TC-9a68f7f96bf6", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_文件归档意外损坏后离线核对失败__9a68f7(应用测试库: dict, tmp_path: Path) -> None: - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "corrupt") - 备份目录 = tmp_path / "corrupt-backup" - 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 原文 = 备份目录 / "files" / "data" / "raw" / "供应方原文.bin" - 原文.write_bytes(原文.read_bytes() + b"\x00tampered") - with pytest.raises(备份恢复错误): - 核对备份(备份目录) - - -@pytest.mark.case_id( - "TC-545fb1541c3a", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_备份清单拒绝重复键和未知字段__545fb1(应用测试库: dict, tmp_path: Path) -> None: - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "contract") - 备份目录 = tmp_path / "contract-backup" - 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 清单路径 = 备份目录 / "manifest.json" - 原文 = 清单路径.read_text(encoding="utf-8") - 重复 = 原文.replace('"backup_id":"', '"backup_id":"", "backup_id":"', 1) - 清单路径.write_text(重复, encoding="utf-8") - 清单路径.chmod(0o600) - with pytest.raises(备份恢复错误, match="重复字段"): - 核对备份(备份目录) - - 清单路径.write_text(原文, encoding="utf-8") - 清单路径.chmod(0o600) - 未知 = 原文.rstrip()[:-1] + ',"extra_field":1}' - 清单路径.write_text(未知, encoding="utf-8") - 清单路径.chmod(0o600) - with pytest.raises(备份恢复错误): - 核对备份(备份目录) - - -@pytest.mark.case_id( - "TC-2d7f171ffd33", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_资源构建身份漂移在连接前拒绝恢复__2d7f17( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path, monkeypatch -) -> None: - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "identity") - 备份目录 = tmp_path / "identity-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = tmp_path / "identity-target-raw", tmp_path / "identity-target-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - - monkeypatch.setattr( - 备份恢复, - "_核对安装", - lambda 配置: {"发布身份": "wrong-release", "构建身份": "0" * 64}, - ) - with pytest.raises(备份恢复错误, match="构建身份不属于此备份"): - 恢复备份(备份目录, 目标配置, 清单["backup_id"], pg_restore命令="never") - assert not 目标raw.exists() and not 目标drafts.exists() - _断言目标尚无迁移表(新空目标库.工厂) - - -@pytest.mark.case_id( - "TC-7c7fadfd3680", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_占用的恢复文件目标在破坏性写入前拒绝__7c7fad( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path, monkeypatch -) -> None: - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "occupied-target") - 备份目录 = tmp_path / "occupied-target-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 占用根 = tmp_path / "occupied-target-root" - 占用根.mkdir() - 目标配置 = _应用配置(新空目标库.工厂, 占用根, tmp_path / "occupied-target-drafts") - 动作 = _记录客户端动作(monkeypatch) - with pytest.raises(备份恢复错误, match="恢复文件目标必须全新"): - 恢复备份(备份目录, 目标配置, 清单["backup_id"], pg_restore命令="should-not-run") - assert "数据库恢复" not in 动作 - _断言目标尚无迁移表(新空目标库.工厂) - - -@pytest.mark.case_id( - "TC-2b32b67a3482", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_恢复要求资源发布身份与安装一致并在连接前拒绝__2b32b6( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path, monkeypatch -) -> None: - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "code-identity") - 备份目录 = tmp_path / "code-identity-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = tmp_path / "code-id-raw", tmp_path / "code-id-drafts" - 错误配置 = 应用配置( - 新空目标库.工厂.引用, - "wrong-build-identity", - 运行用途=用途.维护, - 原文暂存=str(目标raw), - 探索草稿=str(目标drafts), - ) - 动作 = _记录客户端动作(monkeypatch) - with pytest.raises(备份恢复错误, match="当前程序、资源或配置不一致"): - 恢复备份(备份目录, 错误配置, 清单["backup_id"], pg_restore命令="never") - assert 动作 == [] - assert not 目标raw.exists() and not 目标drafts.exists() - _断言目标尚无迁移表(新空目标库.工厂) - - -@pytest.mark.case_id( - "TC-863e5ced39df", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_备份确认不匹配不创建业务连接__863e5c( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path, monkeypatch -) -> None: - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "confirm") - 备份目录 = tmp_path / "confirm-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = tmp_path / "confirm-target-raw", tmp_path / "confirm-target-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - 动作 = _记录客户端动作(monkeypatch) - with pytest.raises(备份恢复错误, match="预期备份ID"): - 恢复备份(备份目录, 目标配置, "bkp-" + "0" * 40, pg_restore命令="never") - assert 动作 == [] - assert not 目标raw.exists() and not 目标drafts.exists() - _断言目标尚无迁移表(新空目标库.工厂) - assert 清单["backup_id"].startswith("bkp-") - - -@pytest.mark.case_id( - "TC-c2a43647c057", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_备份迁移与安装清单漂移在恢复任何客户端前拒绝__c2a436( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path, monkeypatch -) -> None: - """正文/字段/数据库身份类漂移由迁移版本与校验和清单承接:不一致在连接前拒绝。""" - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "migration-drift") - 备份目录 = tmp_path / "migration-drift-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = ( - tmp_path / "migration-drift-target-raw", - tmp_path / "migration-drift-target-drafts", - ) - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - monkeypatch.setattr( - 备份恢复, - "_安装迁移清单", - lambda: [{"version": 999, "name": "V999__fake.sql", "checksum": "0" * 64}], - ) - 动作 = _记录客户端动作(monkeypatch) - with pytest.raises(备份恢复错误, match="迁移版本或校验和"): - 恢复备份(备份目录, 目标配置, 清单["backup_id"], pg_restore命令="never") - assert 动作 == [] - assert not 目标raw.exists() and not 目标drafts.exists() - _断言目标尚无迁移表(新空目标库.工厂) - - -@pytest.mark.case_id( - "TC-a0e1e2234d2d", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_缺少可用备份在取锁连接前失败__a0e1e2( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path, monkeypatch -) -> None: - raw, drafts = _准备文件(tmp_path, "missing-archive") - 目标raw, 目标drafts = tmp_path / "missing-raw", tmp_path / "missing-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - 动作 = _记录客户端动作(monkeypatch) - with pytest.raises(备份恢复错误, match="无法核对"): - 恢复备份(tmp_path / "不存在备份", 目标配置, "bkp-" + "0" * 40, pg_restore命令="never") - assert 动作 == [] - assert not 目标raw.exists() and not 目标drafts.exists() - - -@pytest.mark.case_id( - "TC-c8063c15e318", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_恢复在并发维护锁下不执行数据库客户端__c8063c( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path, monkeypatch -) -> None: - 来源工厂 = 应用测试库[用途.维护] - _建立类型探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "lock") - 备份目录 = tmp_path / "lock-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = tmp_path / "lock-target-raw", tmp_path / "lock-target-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - 动作 = _记录客户端动作(monkeypatch) - with 新空目标库.工厂.连接() as 连, 连.transaction(): - 持锁 = 连.execute("SELECT pg_try_advisory_lock(%s)", (迁移维护锁,)).fetchone()[0] - assert 持锁 - with pytest.raises(备份恢复错误, match="维护锁"): - 恢复备份(备份目录, 目标配置, 清单["backup_id"], pg_restore命令="never") - assert "数据库恢复" not in 动作 - assert not 目标raw.exists() - - -@pytest.mark.case_id( - "TC-74a6ec3a8017", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_非维护用途在创建备份前拒绝__74a6ec(应用测试库: dict, tmp_path: Path) -> None: - raw, drafts = _准备文件(tmp_path, "purpose") - 生产配置 = 应用配置( - 应用测试库[用途.生产].引用, - _资源身份(), - 运行用途=用途.生产, - 原文暂存=str(raw), - 探索草稿=str(drafts), - ) - with pytest.raises(备份恢复错误, match="maintenance"): - 创建备份(生产配置, tmp_path / "purpose-backup", pg_dump命令="never") - assert not (tmp_path / "purpose-backup").exists() - - -@pytest.mark.case_id( - "TC-b40e21e62183", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_磁盘归档摘要漂移在恢复任何写入前失败__b40e21( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path -) -> None: - 来源工厂 = 应用测试库[用途.维护] - raw, drafts = _准备文件(tmp_path, "drift") - 备份目录 = tmp_path / "drift-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = tmp_path / "drift-target-raw", tmp_path / "drift-target-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - 原文 = 备份目录 / "files" / "data" / "raw" / "供应方原文.bin" - 原文.write_bytes(原文.read_bytes() + b"changed") - with pytest.raises(备份恢复错误): - 恢复备份(备份目录, 目标配置, 清单["backup_id"], pg_restore命令="never") - assert not 目标raw.exists() and not 目标drafts.exists() - _断言目标尚无迁移表(新空目标库.工厂) - - -@pytest.mark.case_id( - "TC-6740be8d17a3", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_序列恢复只向前且保持确认__6740be( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path -) -> None: - 来源工厂 = 应用测试库[用途.维护] - _建立类型探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "sequence") - 备份目录 = tmp_path / "sequence-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = tmp_path / "sequence-target-raw", tmp_path / "sequence-target-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - 恢复备份(备份目录, 目标配置, 清单["backup_id"]) - with 新空目标库.工厂.连接() as 连, 连.transaction(): - 语句 = 连.execute( - "SELECT last_value, is_called FROM public.w29_seq_probe_id_seq" - ).fetchone() - assert 语句 == (3, True) - 连.execute("INSERT INTO public.w29_seq_probe(note) VALUES ('丁')") - assert 连.execute("SELECT max(id) FROM public.w29_seq_probe").fetchone() == (4,) - - -@pytest.mark.case_id( - "TC-d07d1f9ee590", - environment="隔离 PostgreSQL 与临时目录", - when="备份、校验、恢复或模拟切换失败。", - contract="docs/系统架构/新版设计/迁移与验收.md", -) -def test_恢复后复核失败清理文件根并报错__d07d1f( - 应用测试库: dict, 新空目标库: SimpleNamespace, tmp_path: Path, monkeypatch -) -> None: - 来源工厂 = 应用测试库[用途.维护] - _建立类型探针(来源工厂) - raw, drafts = _准备文件(tmp_path, "postcheck") - 备份目录 = tmp_path / "postcheck-backup" - 清单 = 创建备份(_应用配置(来源工厂, raw, drafts), 备份目录) - 目标raw, 目标drafts = tmp_path / "postcheck-target-raw", tmp_path / "postcheck-target-drafts" - 目标配置 = _应用配置(新空目标库.工厂, 目标raw, 目标drafts) - 原摘要 = 备份恢复._数据库摘要 - - def 漂移(连接, 关系): - 库 = 原摘要(连接, 关系) - if "table_data" in 库: - 库 = json.loads(json.dumps(库)) - 条目 = dict(库["table_data"][0]) - 条目["sha256"] = "0" * 64 - 库["table_data"] = [条目] - return 库 - - monkeypatch.setattr(备份恢复, "_数据库摘要", 漂移) - with pytest.raises(备份恢复错误, match="摘要不一致"): - 恢复备份(备份目录, 目标配置, 清单["backup_id"]) - assert not 目标raw.exists() and not 目标drafts.exists() diff --git a/tests/集成/test_任务租约与恢复.py b/tests/集成/test_任务租约与恢复.py index 798b5da..83c6f71 100644 --- a/tests/集成/test_任务租约与恢复.py +++ b/tests/集成/test_任务租约与恢复.py @@ -1,4 +1,8 @@ -"""公开任务接口的持久状态、独立连接竞争与恢复合同。""" +"""任务租约的核心保护:重启不重复执行、未知调用先对账。 + +按简化决策删除其余变体用例;夹具从按例克隆改为共享库以消除建库开销。 +`任务库` 与 `请求` 同时被 test_任务租约与迟到结果.py 复用。 +""" from __future__ import annotations @@ -6,26 +10,19 @@ import dataclasses import subprocess import sys import time -import uuid -from concurrent.futures import ThreadPoolExecutor from pathlib import Path -from threading import Barrier -import psycopg import pytest from muse.任务运行.接口 import ( - 事件类型, 任务服务, 任务状态, 任务请求, - 任务错误, 作用域, 步骤处理器, 步骤结果, 步骤计划, 状态冲突, - 租约失效, ) from muse.共享.调用身份 import 内容用途, 用途 from muse.基础设施.数据库.连接 import 数据库工厂 @@ -36,7 +33,7 @@ pytestmark = pytest.mark.数据库 @pytest.fixture def 任务库(数据库底座, monkeypatch: pytest.MonkeyPatch, tmp_path: Path): - with 数据库底座.借库(tmp_path / "连接引用") as 工厂: + with 数据库底座.共享库(tmp_path / "连接引用") as 工厂: # 子进程恢复入口继承相同的按例数据库,仍跨真实连接验证提交。 for 声明, 当前 in 工厂.items(): monkeypatch.setenv(f"MUSE_W05_{声明.name}_URL", Path(当前.引用.位置).read_text()) @@ -152,161 +149,6 @@ assert 运行.读取任务(sys.argv[1]).状态.value == "completed" assert all(步骤["result"] is not None for 步骤 in 运行.读取任务(身份).步骤) -@pytest.mark.case_id( - "NC-task-scope-competition", - environment="隔离PostgreSQL", - given="同作品两任务与另一作品任务", - when="两个独立连接并发领取", - then=["同范围仅一个持有者,另一范围可并行"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_独立连接竞争同范围而不同范围可并行__a51002(任务库) -> None: - 运行, 编排 = 构造服务(任务库[用途.生产]) - A = 运行.创建任务(请求("a"), "example", "1") - B = 运行.创建任务(请求("b"), "example", "1") - C = 运行.创建任务(请求("c", "work-C"), "example", "1") - 起点 = Barrier(2) - - def 领取(名称): - 起点.wait() - return 运行.领取步骤(名称, ["collect"]) - - with ThreadPoolExecutor(max_workers=2) as 线程: - 结果 = list(线程.map(领取, ["one", "two"])) - 有效 = [项 for 项 in 结果 if 项] - # 同范围争用者可能先让出;下一次领取应直接命中独立范围。 - if len(有效) == 1: - 下一 = 运行.领取步骤("third", ["collect"]) - assert 下一 is not None - 有效.append(下一) - assert len(有效) == 2 - assert C in {项.任务ID for 项 in 有效} - assert len({项.任务ID for 项 in 有效} & {A, B}) == 1 - assert 运行.领取步骤("blocked", ["collect"]) is None - for 项 in 有效: - 运行.完成步骤(项, 步骤结果({"done": 1})) - - -@pytest.mark.case_id( - "NC-task-lease-fencing", - environment="隔离PostgreSQL", - given="持久检查点及已过期租约", - when="新执行者接管,旧执行者提交或续租", - then=["旧身份被拒,新持有代次递增且检查点保留"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_过期接管拒绝旧步骤和作用域代次__a51003(任务库) -> None: - 运行, 编排 = 构造服务(任务库[用途.生产]) - 身份 = 运行.创建任务(请求(), "example", "1") - 旧 = 运行.领取步骤("old", ["collect"], 租期秒=0.12) - assert 旧 is not None - 运行.保存检查点(旧, {"offset": 4}) - time.sleep(0.16) - 新 = 运行.领取步骤("new", ["collect"]) - assert 新 is not None and 新.任务ID == 身份 - assert 新.尝试ID != 旧.尝试ID and 新.作用域代次 > 旧.作用域代次 - assert 新.检查点 == {"offset": 4} - for 操作 in [lambda: 运行.完成步骤(旧, 步骤结果({"late": 1})), lambda: 运行.续租(旧)]: - with pytest.raises(租约失效): - 操作() - with pytest.raises(租约失效): - 运行.执行一步(dataclasses.replace(新, 处理器ID="finish")) - 运行.完成步骤(新, 步骤结果({"current": 1})) - assert 运行.读取任务(身份).步骤[0]["result"] == {"current": 1} - - -@pytest.mark.case_id( - "NC-task-cancel-fencing", - environment="隔离PostgreSQL", - given="正在执行且持有作品范围的任务", - when="作者取消后旧结果到达", - then=["拒绝迟到写入并允许新任务取得范围"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_取消后拒绝旧结果并释放作品范围__a51004(任务库) -> None: - 运行, 编排 = 构造服务(任务库[用途.生产]) - 身份 = 运行.创建任务(请求("old"), "example", "1") - 旧 = 运行.领取步骤("old", ["collect"]) - assert 旧 is not None - 运行.控制任务(身份, "author", 任务状态.运行中, "取消", 命令ID="cancel") - with pytest.raises(租约失效): - 运行.完成步骤(旧, 步骤结果({"late": 1})) - 新任务 = 运行.创建任务(请求("new"), "example", "1") - 新 = 运行.领取步骤("new", ["collect"]) - assert 新 is not None and 新.任务ID == 新任务 - assert 运行.读取任务(身份).状态 is 任务状态.已取消 - - -@pytest.mark.case_id( - "NC-task-resume-revalidation", - environment="隔离PostgreSQL", - given="暂停任务及已保存检查点", - when="重建服务并提供业务恢复校验", - then=["校验失败仍暂停,合法恢复保留检查点"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_暂停恢复重验且检查点持久保留__a51005(任务库) -> None: - 运行, 编排 = 构造服务(任务库[用途.生产]) - 身份 = 运行.创建任务(请求(), "example", "1") - 旧 = 运行.领取步骤("old", ["collect"]) - assert 旧 is not None - 运行.保存检查点(旧, {"part": 2}) - 运行.控制任务(身份, "author", 任务状态.运行中, "暂停", 命令ID="pause") - - def 拒绝过期来源(快照): - raise 状态冲突("来源已变化") - - 重启, _ = 构造服务(任务库[用途.生产], 重验=拒绝过期来源) - with pytest.raises(状态冲突, match="来源"): - 重启.控制任务(身份, "author", 任务状态.已暂停, "恢复", 命令ID="resume") - assert 重启.读取任务(身份).状态 is 任务状态.已暂停 - - def 校验当前来源(快照): - assert 快照.冻结输入["冻结上下文"]["authorization"] == "grant-1" - - 重启, _ = 构造服务(任务库[用途.生产], 重验=校验当前来源) - 重启.控制任务(身份, "author", 任务状态.已暂停, "恢复", 命令ID="resume") - 新 = 重启.领取步骤("new", ["collect"]) - assert 新 is not None and 新.检查点 == {"part": 2} - - -@pytest.mark.case_id( - "NC-task-registered-revalidation", - environment="隔离 PostgreSQL、具名接入;合成 owner 检查", - given="暂停任务和登记的合成 owner 来源、结构、授权与预算检查", - when="从 HTTP/CLI 共用入口恢复并重放命令", - then=["当前来源不匹配时保持暂停", "重验通过后排队,重复命令返回相同回执"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_具名接入恢复由登记owner重验__a5100f(任务库) -> None: - """HTTP/CLI 共用入口不能自报重验;服务按冻结流程找到当前业务检查。""" - from muse.接入.主会话 import 任务控制请求, 执行任务控制 - - 当前来源 = {"版本": 4} - - def 重验合成任务(快照): - 上下文 = 快照.冻结输入["冻结上下文"] - if 上下文["source_scope"]["as_of"] != 当前来源["版本"]: - raise 状态冲突("来源版本已变化") - assert 上下文["schema_versions"] == {"entity": "1"} - assert 上下文["authorization"] == "grant-1" - assert 上下文["budget"]["remaining"] > 0 - - 运行, 编排 = 构造服务(任务库[用途.生产], 重验=重验合成任务) - 身份 = 运行.创建任务(请求(), "example", "1") - 运行.控制任务(身份, "author", 任务状态.待运行, "暂停", 命令ID="pause") - 控制 = 任务控制请求( - command_id="resume", target_ref=身份, expected_state=任务状态.已暂停, action="恢复" - ) - with pytest.raises(状态冲突, match="来源版本"): - 执行任务控制(运行, "author", 控制) - assert 运行.读取任务(身份).状态 is 任务状态.已暂停 - 当前来源["版本"] = 3 - 回执 = 执行任务控制(运行, "author", 控制) - assert 回执.state is 任务状态.待运行 - assert 执行任务控制(运行, "author", 控制) == 回执 - - @pytest.mark.case_id( "NC-task-unknown-reconciliation", environment="隔离PostgreSQL", @@ -340,189 +182,3 @@ def test_未知调用先对账并复用可靠输出__a51006(任务库) -> None: 运行.执行一步(收尾) assert 运行.读取任务(身份).状态 is 任务状态.已完成 assert 运行.读取任务(身份).步骤[0]["result"] == {"recovered": 1} - - -@pytest.mark.case_id( - "NC-task-event-reconnect", - environment="隔离PostgreSQL", - given="有序事件及固定事件身份", - when="重复提交、同 ID 不同内容及实际删除中间事件", - then=["重复幂等、冲突拒绝、游标缺口要求任务快照"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_事件重复幂等且游标缺口要求快照__a51007(任务库) -> None: - 运行, 编排 = 构造服务(任务库[用途.生产]) - 身份 = 运行.创建任务(请求(), "example", "1") - 领取 = 运行.领取步骤("one", ["collect"]) - assert 领取 is not None - 事件ID = str(uuid.uuid4()) - 事件 = 运行.追加事件(领取, 事件类型.文本片段, {"文本": "片段"}, 事件ID=事件ID) - assert 运行.追加事件(领取, 事件类型.文本片段, {"文本": "片段"}, 事件ID=事件ID) == 事件 - with pytest.raises(状态冲突): - 运行.追加事件(领取, 事件类型.文本片段, {"文本": "不同"}, 事件ID=事件ID) - 续接 = 运行.续接事件(身份) - assert [e.序号 for e in 续接.事件] == list(range(1, 续接.最后序号 + 1)) - assert not 续接.需要快照 - with 任务库[用途.维护].连接() as 连: - 连.execute("DELETE FROM public.muse_task_event WHERE task_id=%s AND sequence=2", (身份,)) - assert 运行.续接事件(身份).需要快照 - assert 运行.续接事件(身份, 事件.序号).事件 == () - - -@pytest.mark.case_id( - "NC-task-failure-stop", - environment="隔离PostgreSQL", - given="处理器失败和待执行任务", - when="记录失败并停止当前进程领取", - then=["失败不变成功,重建服务可领取持久任务"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_失败如实保留且停止领取不丢状态__a51008(任务库) -> None: - def 失败处理器(_): - raise RuntimeError("合成失败") - - 运行, 编排 = 构造服务(任务库[用途.生产], 失败处理器) - 身份 = 运行.创建任务(请求(), "example", "1") - 领取 = 运行.领取步骤("one", ["collect"]) - assert 领取 is not None - with pytest.raises(RuntimeError): - 运行.执行一步(领取) - assert 运行.读取任务(身份).状态 is 任务状态.已失败 - 运行.创建任务(请求("next", "another"), "example", "1") - 运行.停止领取() - assert 运行.领取步骤("stop", ["collect"]) is None - 重启, _ = 构造服务(任务库[用途.生产]) - assert 重启.领取步骤("restart", ["collect"]) is not None - - -@pytest.mark.case_id( - "NC-task-purpose-isolation", - environment="隔离PostgreSQL", - given="相同命令的生产和评测任务", - when="各自数据库角色领取和查询", - then=["分别持久执行且不能跨用途读取任务"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_生产评测任务使用独立权限与实例__a51009(任务库) -> None: - 生产, 生产编排 = 构造服务(任务库[用途.生产]) - 评测, 评测编排 = 构造服务(任务库[用途.评测]) - A = 生产.创建任务(请求(), "example", "1") - B = 评测.创建任务(请求(用途标记=用途.评测), "example", "1") - assert A != B - assert 生产.领取步骤("prod", ["collect"]) is not None - assert 评测.领取步骤("eval", ["collect"]) is not None - with pytest.raises(任务错误, match="不存在|用途"): - 评测.读取任务(A) - - -@pytest.mark.case_id( - "NC-task-short-transaction", - environment="隔离PostgreSQL", - given="已领取任务的真实处理器", - when="隔离集群管理员检查 pg_stat_activity", - then=["处理器期间目标库不存在悬挂事务"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_处理器调用期间不持有数据库事务__a5100a(任务库, 隔离数据库URL: str) -> None: - def 处理器(上下文): - with 任务库[用途.维护].连接() as 连: - 目标库 = 连.info.dbname - with psycopg.connect(隔离数据库URL) as 管理员: - 数量 = 管理员.execute( - "SELECT count(*) FROM pg_stat_activity WHERE datname=%s " - "AND pid<>pg_backend_pid() AND state='idle in transaction'", - (目标库,), - ).fetchone()[0] - assert 数量 == 0 - return 步骤结果({"done": True}) - - 运行, 编排 = 构造服务(任务库[用途.生产], 处理器) - 运行.创建任务(请求(), "example", "1") - 领取 = 运行.领取步骤("one", ["collect"]) - assert 领取 is not None - assert 运行.执行一步(领取).输出 == {"done": True} - - -@pytest.mark.case_id( - "NC-task-control-idempotent", - environment="隔离PostgreSQL", - given="重复或异参数的任务控制请求", - when="控制同一持久化任务", - then=["同命令返回原回执且不重复事件,异参数拒绝"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_控制命令重放不重复事件且异参数拒绝__a5100b(任务库) -> None: - 运行, 编排 = 构造服务(任务库[用途.生产]) - 身份 = 运行.创建任务(请求(), "example", "1") - 首次 = 运行.控制任务(身份, "author", 任务状态.待运行, "取消", 命令ID="cancel-one") - 重放 = 运行.控制任务(身份, "author", 任务状态.待运行, "取消", 命令ID="cancel-one") - assert 重放 == 首次 - assert 运行.读取任务(身份).最后序号 == 首次["last_sequence"] - with pytest.raises(任务错误): - 运行.控制任务(身份, "author", 任务状态.待运行, "暂停", 命令ID="cancel-one") - - -@pytest.mark.case_id( - "NC-task-list-scope", - environment="隔离PostgreSQL", - given="不同作者和作品的已登记任务", - when="列出当前作者和作品任务", - then=["只返回匹配的真实任务"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_任务列表按作者作品及用途隔离__a5100c(任务库) -> None: - 运行, 编排 = 构造服务(任务库[用途.生产]) - A = 运行.创建任务(请求("a", "work-A"), "example", "1") - 运行.创建任务(请求("b", "work-B"), "example", "1") - 运行.创建任务(dataclasses.replace(请求("c", "work-A"), 作者="other"), "example", "1") - assert [x.任务ID for x in 运行.列出任务("author", 作品ID="work-A")] == [A] - assert 运行.列出任务("missing") == [] - - -@pytest.mark.case_id( - "NC-task-step-order", - environment="隔离PostgreSQL", - given="不同于字典序的冻结流程", - when="读取任务步骤", - then=["按冻结流程顺序显示"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_任务步骤按冻结流程顺序显示__a5100d(任务库) -> None: - 运行, 编排 = 构造服务(任务库[用途.生产]) - 编排.发布( - 流程定义( - "example", - "2", - ( - 步骤计划("z-first", "collect", "1"), - 步骤计划("a-last", "finish", "1", ("z-first",)), - ), - ) - ) - 身份 = 运行.创建任务(请求("ordered"), "example", "2") - assert [step["step_id"] for step in 运行.读取任务(身份).步骤] == ["z-first", "a-last"] - - -@pytest.mark.case_id( - "NC-worker-heartbeat-stop", - environment="隔离PostgreSQL", - given="执行时间超过原租期的处理器", - when="运行执行器并停止", - then=["自动续租完成当前步骤,停止后不领取后续"], - contract="docs/系统架构/新版设计/接口契约/任务工具与事件.md", -) -def test_执行器续租并在停止后不领取新步骤__a5100e(任务库) -> None: - from muse.接入.执行器 import 执行器 - - def 长步骤(_): - time.sleep(0.45) - return 步骤结果({"done": True}) - - 运行, 编排 = 构造服务(任务库[用途.生产], 长步骤) - 身份 = 运行.创建任务(请求(), "example", "1") - worker = 执行器(运行, "durable-worker", ["collect", "finish"], 租期秒=0.3) - assert worker.运行一次() - worker.停止() - assert not worker.运行一次() - assert 运行.读取任务(身份).步骤[0]["state"] == "completed" - assert 运行.读取任务(身份).步骤[1]["state"] == "pending" diff --git a/tests/集成/test_发布包独立运行.py b/tests/集成/test_发布包独立运行.py index 3515bc0..02964ac 100644 --- a/tests/集成/test_发布包独立运行.py +++ b/tests/集成/test_发布包独立运行.py @@ -80,11 +80,10 @@ def 独立安装环境(tmp_path): for part in Path(name).parts ) migrations = [n for n in names if n.startswith("muse/资源/迁移/") and n.endswith(".sql")] - assert len(migrations) == len(list((根 / "数据库/迁移").glob("*.sql"))) - assert ( - archive.read("muse/资源/迁移/V0001__共享标识与版本.sql") - == (根 / "数据库/迁移/V0001__共享标识与版本.sql").read_bytes() - ) + 源迁移 = sorted((根 / "数据库/迁移").glob("*.sql")) + assert sorted(Path(n).name for n in migrations) == [p.name for p in 源迁移] + for 源 in 源迁移: + assert archive.read(f"muse/资源/迁移/{源.name}") == 源.read_bytes() requirements = tmp_path / "runtime.txt" _命令( [ diff --git a/tests/集成/test_数据库底座隔离.py b/tests/集成/test_数据库底座隔离.py deleted file mode 100644 index 1bc2621..0000000 --- a/tests/集成/test_数据库底座隔离.py +++ /dev/null @@ -1,55 +0,0 @@ -"""获准隔离 PG 后验证模板保护、独立提交与角色,不使用共享事务替身。""" - -import psycopg -import pytest -from psycopg.conninfo import conninfo_to_dict, make_conninfo - -from muse.共享.调用身份 import 用途 - -pytestmark = pytest.mark.数据库 - - -@pytest.mark.case_id("NC-database-baseline-pg-01") -def test_克隆保留真实提交且后例没有前例数据(数据库底座, tmp_path): - with 数据库底座.借库(tmp_path / "first", (1,)) as 一: - with 一[用途.维护].连接() as 连: - 连.execute("CREATE TABLE public.clone_probe (id serial PRIMARY KEY, value text)") - 连.execute("INSERT INTO public.clone_probe(value) VALUES ('first')") - with 一[用途.维护].连接() as 连: - assert 连.execute("SELECT id, value FROM public.clone_probe").fetchone() == (1, "first") - 第一库 = 连.info.dbname - with 数据库底座.借库(tmp_path / "second", (1,)) as 二: - with 二[用途.维护].连接() as 连: - assert 连.info.dbname != 第一库 - assert 连.execute("SELECT to_regclass('public.clone_probe')").fetchone() == (None,) - 连.execute("CREATE TABLE public.clone_probe (id serial PRIMARY KEY, value text)") - assert 连.execute( - "INSERT INTO public.clone_probe(value) VALUES ('second') RETURNING id" - ).fetchone() == (1,) - for 用途值, 角色 in [(用途.生产, "muse_app"), (用途.评测, "muse_eval")]: - with 二[用途值].连接() as 连: - assert 连.execute("SELECT current_user").fetchone() == (角色,) - # 此基线本 session 无论消费多少例都只执行一轮,clone 不再执行迁移。 - 模板 = 数据库底座.基线((1,)) - assert ( - len([e for e in 数据库底座.事件 if e["action"] == "ddl" and e["database"] == 模板.名称]) - == 1 - ) - - -@pytest.mark.case_id("NC-database-baseline-pg-02") -def test_封存模板拒绝直接连接且失败用例精确清理(数据库底座, 隔离数据库URL, tmp_path): - 模板 = 数据库底座.基线((1,)) - 参数 = conninfo_to_dict(隔离数据库URL) - 参数.update(dbname=模板.名称, connect_timeout="2") - with pytest.raises(psycopg.OperationalError): - psycopg.connect(make_conninfo(**参数)) - 库名 = None - with pytest.raises(ValueError), 数据库底座.借库(tmp_path / "failed", (1,)) as 工厂: - with 工厂[用途.维护].连接() as 连: - 库名 = 连.info.dbname - raise ValueError("模拟测试失败") - with psycopg.connect(隔离数据库URL) as 连: - assert ( - 连.execute("SELECT 1 FROM pg_database WHERE datname = %s", (库名,)).fetchone() is None - ) diff --git a/tests/集成/test_数据库连接与迁移.py b/tests/集成/test_数据库连接与迁移.py index be56504..8cf4574 100644 --- a/tests/集成/test_数据库连接与迁移.py +++ b/tests/集成/test_数据库连接与迁移.py @@ -1,350 +1,43 @@ -"""真实连接、权限、事务与迁移验证;仅使用显式隔离 PostgreSQL。""" +"""基线建库的最小验证:空库执行基线后账本登记且业务角色可连。""" -from __future__ import annotations - -import hashlib -import json from collections.abc import Iterator from pathlib import Path -import psycopg import pytest -from psycopg import sql -from muse.__main__ import main from muse.共享.调用身份 import 用途 -from muse.共享.错误 import 环境缺失错误 -from muse.启动 import 构建 -from muse.基础设施.数据库.事务 import 事务, 事务失败, 保存点 -from muse.基础设施.数据库.用途隔离 import 用途越权 -from muse.基础设施.数据库.迁移 import 已应用版本, 执行迁移, 迁移错误 -from muse.基础设施.数据库.连接 import 解析连接串, 连接 -from muse.配置 import 应用配置, 数据库引用 +from muse.基础设施.数据库.迁移 import 列出迁移, 已应用版本 +from muse.基础设施.数据库.连接 import 数据库引用, 连接 -迁移目录 = Path(__file__).resolve().parents[2] / "数据库" / "迁移" -角色表 = {用途.生产: "muse_app", 用途.评测: "muse_eval", 用途.维护: "muse_maint"} +pytestmark = pytest.mark.数据库 @pytest.fixture def 临时库(空测试库) -> Iterator[dict[用途, 数据库引用]]: - """空库没有预执行被测 DDL;真实提交、并发和迁移动作由测试执行。""" - yield {用途值: 工厂.引用 for 用途值, 工厂 in 空测试库.items()} - - -def 维护连接(临时库: dict[用途, 数据库引用], **参数: object) -> psycopg.Connection: - return 连接(临时库[用途.维护], 用途标记=用途.维护, **参数) + yield 空测试库 @pytest.mark.case_id( - "NC-db-no-fallback", - environment="离线", - given="数据库凭据引用未提供", - when="从真实装配取得数据库连接", - then=["报环境缺失并拒绝任何默认库回退"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", + "TC-base-0001", + environment="隔离PG", + given="全新空库与包内基线 SQL", + when="以维护用途执行基线迁移", + then=["账本登记基线版本,生产角色可连接并读取结构"], ) -def test_缺配置拒绝回退默认库__d10001(monkeypatch: pytest.MonkeyPatch) -> None: - """given 缺少连接引用;when 装配连接;then 拒绝默认库回退。""" - monkeypatch.delenv("MUSE_MISSING_DATABASE_URL", raising=False) - 配置 = 应用配置(数据库引用("环境变量", "MUSE_MISSING_DATABASE_URL"), "test") - 装配 = 构建(配置) - 工厂 = 装配.要求数据库() - with 装配.生命周期(): - # 打开空池不读凭据;首次借用才解析,缺环境变量时拒绝默认库回退。 - with pytest.raises(环境缺失错误, match="拒绝回退"): - with 工厂.连接(): - pass +def test_空库执行基线登记账本且业务角色可连__base001(临时库) -> None: + # 空测试库不预执行 DDL;在本用例内从零执行基线并验证账本与角色连接。 + 维护 = 连接(临时库[用途.维护].引用, 用途标记=用途.维护) + with 维护 as 连: + from muse.基础设施.数据库.迁移 import 执行迁移 - -@pytest.mark.case_id( - "NC-db-readonly-write", - environment="隔离 PostgreSQL", - given="维护角色连接且附加普通 options", - when="请求只读并写入", - then=["两种 options 下 PostgreSQL 都拒绝写入"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -@pytest.mark.parametrize( - "options", ["", "-c application_name=readonly-probe"], ids=["default", "options"] -) -def test_只读连接拒绝写__d50005(临时库: dict[用途, 数据库引用], options: str) -> None: - """given 普通连接选项;when 请求只读;then 数据库拒绝写入。""" - with 维护连接(临时库, 只读=True, options=options) as 连: - with pytest.raises(psycopg.errors.ReadOnlySqlTransaction): - 连.execute("CREATE TABLE readonly_probe (id int)") - 连.rollback() - - -@pytest.mark.case_id( - "NC-db-txn-rollback", - environment="隔离 PostgreSQL", - given="默认或自动提交连接", - when="事务第二参与者失败", - then=["全部写入回滚且错误不包含参与者原文"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -@pytest.mark.parametrize("autocommit", [False, True], ids=["manual", "auto"]) -def test_事务回滚不留半成品__d60006(临时库: dict[用途, 数据库引用], autocommit: bool) -> None: - """given 两种提交模式;when 第二参与者失败;then 全部写入回滚。""" - with 维护连接(临时库, autocommit=autocommit) as 连: - with pytest.raises(事务失败) as 记录: - with 事务(连): - 连.execute("CREATE TABLE participant_one (id int)") - 连.execute("CREATE TABLE participant_two (id int)") - raise RuntimeError("第二参与者失败,正文与凭据不得被拼入错误") - assert "正文与凭据" not in str(记录.value.呈现()) - assert ( - 连.execute( - "SELECT count(*) FROM information_schema.tables " - "WHERE table_name IN ('participant_one', 'participant_two')" - ).fetchone()[0] - == 0 - ) - - -@pytest.mark.case_id( - "NC-db-purpose-role", - environment="隔离 PostgreSQL", - given="三个固定普通登录角色", - when="正式连接入口声明其他用途", - then=["六种不匹配全部拒绝,匹配组合可用"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -@pytest.mark.parametrize( - ("登录用途", "声明用途"), - [(角色, 声明) for 角色 in 用途 for 声明 in 用途 if 角色 != 声明], - ids=[f"{角色.value}-as-{声明.value}" for 角色 in 用途 for 声明 in 用途 if 角色 != 声明], -) -def test_用途角色不匹配被拒__d70007( - 临时库: dict[用途, 数据库引用], 登录用途: 用途, 声明用途: 用途 -) -> None: - """given 固定普通角色;when 正式连接入口声明其他用途;then 连接被拒。""" - with pytest.raises(用途越权): - 连接(临时库[登录用途], 用途标记=声明用途) - with 连接(临时库[登录用途], 用途标记=登录用途) as 连: - assert 连.execute("SELECT current_user").fetchone()[0] == 角色表[登录用途] - - -@pytest.mark.case_id( - "NC-db-eval-oracle", - environment="隔离 PostgreSQL", - given="oracle schema 中的合成答案和匿名映射", - when="生产角色与评测角色实际 SELECT", - then=["生产被 PG 拒权,评测可读"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -@pytest.mark.parametrize("目标表", ["answer", "blind_assignment"], ids=["oracle", "blind-map"]) -def test_生产用途拒绝oracle及匿名映射读取__d80008( - 临时库: dict[用途, 数据库引用], 目标表: str -) -> None: - """given 维护角色建立答案或匿名映射;when 生产连接查询;then PG 拒权。""" - 目标 = sql.Identifier("oracle", 目标表) - with 维护连接(临时库) as 连: - 执行迁移(连, 迁移目录, 目标版本=1) - 连.execute(sql.SQL("CREATE TABLE {} (id int)").format(目标)) - 连.execute(sql.SQL("INSERT INTO {} VALUES (1)").format(目标)) - with 连接(临时库[用途.生产], 用途标记=用途.生产) as 连: - with pytest.raises(psycopg.errors.InsufficientPrivilege): - 连.execute(sql.SQL("SELECT * FROM {}").format(目标)) - 连.rollback() - with 连接(临时库[用途.评测], 用途标记=用途.评测) as 连: - assert 连.execute(sql.SQL("SELECT id FROM {}").format(目标)).fetchone()[0] == 1 - - -@pytest.mark.case_id( - "NC-db-savepoint", - environment="隔离 PostgreSQL", - given="两种提交模式下已写入的外层事务", - when="保存点内写入后失败", - then=["局部回滚,外层提交且新连接可见"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -@pytest.mark.parametrize("autocommit", [False, True], ids=["manual", "auto"]) -def test_保存点局部失败保留外层事务__d90009( - 临时库: dict[用途, 数据库引用], autocommit: bool -) -> None: - """given 外层事务已有写入;when 保存点失败;then 局部回滚且外层可提交。""" - with 维护连接(临时库, autocommit=autocommit) as 连: - with 事务(连): - 连.execute("CREATE TABLE savepoint_probe (id int)") - 连.execute("INSERT INTO savepoint_probe VALUES (1)") - with pytest.raises(RuntimeError): - with 保存点(连, '中文保存点"'): - 连.execute("INSERT INTO savepoint_probe VALUES (2)") - raise RuntimeError("局部失败") - 连.execute("INSERT INTO savepoint_probe VALUES (3)") - assert 连.execute("SELECT id FROM savepoint_probe ORDER BY id").fetchall() == [(1,), (3,)] - with 维护连接(临时库) as 再读: - assert 再读.execute("SELECT count(*) FROM savepoint_probe").fetchone()[0] == 2 - - -@pytest.mark.case_id( - "NC-db-eval-production-write", - environment="隔离 PostgreSQL", - given="由维护迁移授权的生产和评测表", - when="两个角色分别写入", - then=["生产角色可写生产表,评测只能写评测表"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -def test_评测角色仅可写评测对象__da000a(临时库: dict[用途, 数据库引用]) -> None: - """given 生产与评测对象;when 评测连接写入;then 仅评测对象可写。""" - with 维护连接(临时库) as 连: - 执行迁移(连, 迁移目录, 目标版本=1) - 连.execute("CREATE TABLE public.production_probe (id int)") - 连.execute("CREATE TABLE evaluation.sample_probe (id int)") - with 连接(临时库[用途.生产], 用途标记=用途.生产) as 连: - 连.execute("INSERT INTO public.production_probe VALUES (1)") - with 连接(临时库[用途.评测], 用途标记=用途.评测) as 连: - with pytest.raises(psycopg.errors.InsufficientPrivilege): - 连.execute("INSERT INTO public.production_probe VALUES (2)") - 连.rollback() - 连.execute("INSERT INTO evaluation.sample_probe VALUES (3)") - assert 连.execute("SELECT id FROM evaluation.sample_probe").fetchone()[0] == 3 - with 维护连接(临时库) as 连: - assert 连.execute("SELECT id FROM public.production_probe").fetchall() == [(1,)] - - -@pytest.mark.case_id( - "NC-db-migration-idempotent", - environment="隔离 PostgreSQL", - given="隔离测试库与受控连接引用", - when="执行连接、只读、事务、用途或迁移操作", - then=["拒绝与失败如实呈现;成功路径可复验"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -def test_迁移幂等与篡改拦截__d20002(临时库: dict[用途, 数据库引用], tmp_path: Path) -> None: - """given 已登记迁移;when 重跑或篡改同版本;then 幂等跳过或拒绝。""" - with 维护连接(临时库) as 连: - assert [项.版本 for 项 in 执行迁移(连, 迁移目录, 目标版本=1)] == [1] - assert len(已应用版本(连)[1]) == 64 - assert 执行迁移(连, 迁移目录, 目标版本=1) == [] - (tmp_path / "V0001__共享标识与版本.sql").write_text("-- 改动\n", encoding="utf-8") - with pytest.raises(迁移错误, match="校验和"): - 执行迁移(连, tmp_path) - - -@pytest.mark.case_id( - "NC-db-migration-failure", - environment="隔离 PostgreSQL", - given="隔离测试库与受控连接引用", - when="执行连接、只读、事务、用途或迁移操作", - then=["拒绝与失败如实呈现;成功路径可复验"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -def test_迁移失败不登记且可重跑__d30003(临时库: dict[用途, 数据库引用], tmp_path: Path) -> None: - """given 两个版本;when 第二版本失败;then 仅第一版入账且修复可重跑。""" - (tmp_path / "V0001__共享标识与版本.sql").write_bytes( - (迁移目录 / "V0001__共享标识与版本.sql").read_bytes() - ) - V2 = tmp_path / "V0002__迁移.sql" - V2.write_text("CREATE TABLE migration_probe (id int);\n这不是合法 SQL;\n", encoding="utf-8") - with 维护连接(临时库) as 连: - with pytest.raises(迁移错误, match="未登记成功"): - 执行迁移(连, tmp_path) - assert set(已应用版本(连)) == {1} - with 连.transaction(): - assert 连.execute("SELECT to_regclass('public.migration_probe')").fetchone()[0] is None - V2.write_text("CREATE TABLE migration_probe (id int);\n", encoding="utf-8") - assert [项.版本 for 项 in 执行迁移(连, tmp_path)] == [2] - assert set(已应用版本(连)) == {1, 2} - - -@pytest.mark.case_id( - "NC-db-migration-order", - environment="隔离 PostgreSQL", - given="隔离测试库与受控连接引用", - when="执行连接、只读、事务、用途或迁移操作", - then=["拒绝与失败如实呈现;成功路径可复验"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -def test_低版本补录被拒绝__d40004(临时库: dict[用途, 数据库引用], tmp_path: Path) -> None: - """given 已登记较高版本;when 提供未应用低版本;then 拒绝补录。""" - with 维护连接(临时库) as 连: - 执行迁移(连, 迁移目录, 目标版本=1) - with 连.transaction(): - 连.execute( - "INSERT INTO public.muse_migration (version, name, checksum) VALUES (%s, %s, %s)", - (3, "V0003__既往.sql", hashlib.sha256(b"past").hexdigest()), - ) - (tmp_path / "V0002__补录.sql").write_text( - "CREATE TABLE backfill (id int);", encoding="utf-8" - ) - with pytest.raises(迁移错误, match="低版本"): - 执行迁移(连, tmp_path) - - -@pytest.mark.case_id( - "NC-db-migration-lock", - environment="隔离 PostgreSQL", - given="另一连接持有迁移锁且账本已最新", - when="迁移入口重跑", - then=["首先拒绝锁冲突,释放锁后可幂等重跑"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -def test_迁移先取锁再判定账本__db000b(临时库: dict[用途, 数据库引用]) -> None: - """given 一个进程持有迁移锁;when 另一连接重跑;then 不读取未保护账本。""" - with 维护连接(临时库, autocommit=True) as 持有者: - 执行迁移(持有者, 迁移目录, 目标版本=1) - 持有者.execute("SELECT pg_advisory_lock(%s)", (0x6D757365,)) - with 维护连接(临时库) as 竞争者: - with pytest.raises(迁移错误, match="持有锁"): - 执行迁移(竞争者, 迁移目录, 目标版本=1) - 持有者.execute("SELECT pg_advisory_unlock(%s)", (0x6D757365,)) - assert 执行迁移(竞争者, 迁移目录, 目标版本=1) == [] - - -@pytest.mark.case_id( - "NC-db-cli-assembly", - environment="隔离 PostgreSQL", - given="生产和维护用途 TOML 配置", - when="运行真实 CLI 迁移入口", - then=["生产配置被拒,维护从包资源执行并登记 V0001"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -@pytest.mark.数据库 -def test_迁移命令使用维护装配与包资源__dc000c( - 临时库: dict[用途, 数据库引用], tmp_path: Path, capsys: pytest.CaptureFixture[str] -) -> None: - """given 用途配置;when CLI 迁移;then 生产被拒且维护从安装资源执行。""" - 配置文件 = tmp_path / "连接.toml" - for 声明用途, 预期码 in [(用途.生产, 1), (用途.维护, 0)]: - 引用 = 临时库[声明用途] - 配置文件.write_text( - '["数据库"]\n"取值方式" = ' + json.dumps(引用.取值方式) + "\n" - '"位置" = ' + json.dumps(引用.位置) + "\n" - '["资源"]\n"发布身份" = "test"\n' - f'["运行"]\n"用途" = "{声明用途.value}"\n', - encoding="utf-8", - ) - # 取值方式与位置都取自夹具真实引用:夹具用受控存储文件,不假设环境变量。 - assert main(["迁移", str(配置文件), "--目标版本", "1"]) == 预期码 - assert "已应用 V0001" in capsys.readouterr().out - with 维护连接(临时库) as 连: - assert set(已应用版本(连)) == {1} - - -@pytest.mark.case_id( - "NC-db-controlled-reference", - environment="离线", - given="受控存储中的合成连接引用", - when="连接 owner 解析引用", - then=["通过凭据 owner 读取值且无默认回退"], - contract="docs/系统架构/新版设计/文件设计/数据库与迁移.md", -) -def test_数据库引用通过唯一凭据入口读取受控文件__dd000d(tmp_path: Path) -> None: - """given 受控文件引用;when 解析连接;then 与环境引用共用读取入口。""" - 文件 = tmp_path / "合成连接.txt" - 文件.write_text("dbname=isolated_example user=muse_app\n", encoding="utf-8") - assert 解析连接串(数据库引用("受控存储", str(文件))) == ( - "dbname=isolated_example user=muse_app" - ) + 执行迁移(连, Path("数据库/迁移")) + 项 = 列出迁移() + assert [i.版本 for i in 项] == [1] + assert 已应用版本(连) == {1: 项[0].校验和} + 生产 = 连接(临时库[用途.生产].引用, 用途标记=用途.生产) + with 生产 as 连: + 表数 = 连.execute( + "SELECT count(*) FROM information_schema.tables " + "WHERE table_schema = 'public' AND table_name LIKE 'muse_%'" + ).fetchone()[0] + assert 表数 > 30, "基线应建出完整的业务表集合" diff --git a/tests/集成/test_数据维护与恢复.py b/tests/集成/test_数据维护与恢复.py deleted file mode 100644 index 5ac0b11..0000000 --- a/tests/集成/test_数据维护与恢复.py +++ /dev/null @@ -1,203 +0,0 @@ -"""源库断开后从CLI恢复,再由真实业务owner读取候选和续接任务。""" - -import io -import json -import subprocess -import sys -import tarfile -from dataclasses import replace -from pathlib import Path - -import psycopg -import pytest -import test_定稿与导出 as 定稿测试 -import test_生产评测权限隔离 as 接入测试 -from fastapi.testclient import TestClient -from psycopg import sql -from psycopg.conninfo import conninfo_to_dict, make_conninfo - -from muse.共享.调用身份 import 用途 -from muse.启动 import 构建 -from muse.基础设施.备份恢复 import 创建备份 -from muse.接入.http.应用 import 创建应用 -from muse.编排.定稿交付 import 发起定稿导出 -from muse.资源加载 import 加载清单 -from muse.配置 import 应用配置, 数据库引用, 读取配置 - -pytestmark = pytest.mark.数据库 -候选环境 = 定稿测试.候选环境 -交付环境 = 定稿测试.交付环境 - - -@pytest.mark.case_id( - "NC-w29-29b008", - environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["维护CLI断源恢复真实候选正文与排队交付任务"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", -) -def test_维护CLI断源恢复真实候选正文与排队交付任务__29b008( - 交付环境, 新空目标库, 隔离数据库URL, tmp_path -): - app, author, pools, request = 交付环境 - proposed = app.要求正文().创建人工候选( - author, - "backup-candidate", - "chapter-candidate", - 1, - 定稿测试.正文测试.草稿("备份中的未决候选"), - ) - candidate_id = proposed["results"][0]["candidate_id"] - candidate = app.要求正文().读取候选(author, candidate_id) - app.要求交付().冻结定稿(author, "backup-delivery", request) - queued = 发起定稿导出(app, author, "backup-export", request.delivery_id, ["txt"]) - raw, drafts = tmp_path / "source-raw", tmp_path / "source-drafts" - raw.mkdir() - drafts.mkdir() - (raw / "供应方原文.bin").write_bytes(b"\x00\xfffixture-raw") - (drafts / "随手记.txt").write_text("合成的作者草稿。") - - def config(path, reference, raw_root, drafts_root): - path.write_text( - '["数据库"]\n"取值方式"="受控存储"\n"位置"=' - + json.dumps(reference.位置) - + '\n["运行"]\n"用途"="maintenance"\n["资源"]\n"发布身份"=' - + json.dumps(加载清单()["构建身份"]) - + '\n["文件"]\n"原文暂存"=' - + json.dumps(str(raw_root)) - + '\n"探索草稿"=' - + json.dumps(str(drafts_root)) - + "\n" - ) - return path - - def cli(*args): - result = subprocess.run( - [sys.executable, "-I", "-m", "muse", "数据维护", *map(str, args)], - cwd=tmp_path, - capture_output=True, - text=True, - timeout=30, - ) - assert result.returncode == 0, result.stderr - return json.loads(result.stdout) - - source_cfg = config(tmp_path / "source.toml", pools[用途.维护].引用, raw, drafts) - archive = tmp_path / "cli-backup" - saved = cli("备份", source_cfg, archive) - assert saved["archive_verified"] and not saved["restore_verified"] - source_db = conninfo_to_dict(Path(pools[用途.维护].引用.位置).read_text())["dbname"] - # 只关闭本用例创建的源库连接,证明恢复并不依赖源库运行或任务调度。 - with psycopg.connect(隔离数据库URL, autocommit=True) as admin: - admin.execute( - sql.SQL("ALTER DATABASE {} ALLOW_CONNECTIONS false").format(sql.Identifier(source_db)) - ) - assert cli("核对", archive)["backup_id"] == saved["backup_id"] - restored_raw, restored_drafts = tmp_path / "cli-raw", tmp_path / "cli-drafts" - target_cfg = config( - tmp_path / "target.toml", 新空目标库.工厂.引用, restored_raw, restored_drafts - ) - outcome = cli("恢复", target_cfg, archive, "--预期备份ID", saved["backup_id"]) - assert outcome["status"] == "verified" and not outcome["services_started"] - params = conninfo_to_dict(Path(新空目标库.工厂.引用.位置).read_text()) - params["user"] = "muse_app" - secret = tmp_path / "target-production.txt" - secret.write_text(make_conninfo(**params)) - secret.chmod(0o600) - restored = 构建(应用配置(数据库引用("受控存储", str(secret)), 加载清单()["构建身份"])) - with restored.生命周期(): - current = restored.要求正文().读取候选(author, candidate_id) - assert current["candidate_hash"] == candidate["candidate_hash"] - assert current["decision"] == "undecided" - assert restored.要求正文().读取正文(author, "chapter-candidate")["revision"] == 1 - assert 定稿测试.跑导出(restored, queued["task_id"]).状态.value == "completed" - assert (restored_raw / "供应方原文.bin").read_bytes() == ( - raw / "供应方原文.bin" - ).read_bytes() - - -@pytest.mark.case_id( - "NC-w29-29b009", - environment="隔离PG", - given="显式隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["认证备份目录核对下载不依赖可用源库并拒绝坏份"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", -) -def test_认证备份目录核对下载不依赖可用源库并拒绝坏份__29b009(应用测试库, tmp_path): - root = tmp_path / "backups" - root.mkdir(mode=0o700) - good = root / "一份完整备份" - source = 应用配置(应用测试库[用途.维护].引用, 加载清单()["构建身份"], 运行用途=用途.维护) - archive = 创建备份(source, good) - bad = root / "不完整备份" - bad.mkdir(mode=0o700) - (bad / "manifest.json").write_text("{}") - (bad / "manifest.json").chmod(0o600) - cfg = 读取配置(接入测试._配置文件(应用测试库[用途.生产], tmp_path)) - # 当前HTTP配置故意没有可连接的DB引用,备份查询仍是独立只读能力。 - cfg = replace( - cfg, - 备份目录=str(root), - 数据库=数据库引用("受控存储", str(tmp_path / "missing-database")), - ) - with TestClient(创建应用(cfg), headers={"origin": "http://testserver"}) as client: - assert client.get("/api/v1/system/backups").status_code == 401 - assert ( - client.post( - "/api/v1/session", json={"password": "synthetic-evaluation-only"} - ).status_code - == 200 - ) - catalog = client.get("/api/v1/system/backups") - assert catalog.status_code == 200 - assert str(tmp_path) not in catalog.text - rows = catalog.json()["items"] - assert {x["state"] for x in rows} == {"manifest_only", "unreadable"} - row = next(x for x in rows if x.get("backup_id") == archive["backup_id"]) - path = "/api/v1/system/backups/" + row["entry_id"] - params = {"expected_backup_id": archive["backup_id"]} - checked = client.get(path + "/verify", params=params) - assert checked.status_code == 200, checked.text - assert checked.json()["archive_verified"] and not checked.json()["restore_verified"] - wrong = client.get(path + "/download", params={"expected_backup_id": "bkp-" + "0" * 40}) - assert wrong.status_code != 200 - downloaded = client.get(path + "/download", params=params) - assert downloaded.status_code == 200 - assert downloaded.headers["content-type"].startswith("application/x-tar") - with tarfile.open(fileobj=io.BytesIO(downloaded.content)) as bundle: - assert {x.name.split("/")[0] for x in bundle.getmembers()} == { - "manifest.json", - "database.dump", - "files", - } - content = bundle.extractfile("database.dump") - assert content is not None and content.read() == (good / "database.dump").read_bytes() - downloaded_file = tmp_path / "downloaded.tar" - downloaded_file.write_bytes(downloaded.content) - unpacked = tmp_path / "unpacked" - command = subprocess.run( - [ - sys.executable, - "-I", - "-m", - "muse", - "数据维护", - "解包", - str(downloaded_file), - str(unpacked), - "--预期备份ID", - archive["backup_id"], - ], - cwd=tmp_path, - capture_output=True, - text=True, - timeout=30, - ) - assert command.returncode == 0, command.stderr - assert json.loads(command.stdout)["archive_verified"] is True - assert (unpacked / "database.dump").read_bytes() == (good / "database.dump").read_bytes() - with (good / "database.dump").open("ab") as stream: - stream.write(b"corruption") - assert client.get(path + "/verify", params=params).status_code != 200 diff --git a/tests/集成/test_模型任务备份恢复.py b/tests/集成/test_模型任务备份恢复.py deleted file mode 100644 index e6830ce..0000000 --- a/tests/集成/test_模型任务备份恢复.py +++ /dev/null @@ -1,117 +0,0 @@ -"""隔离模型任务在原库断开后,从完整备份续接已批准任务且不重发旧回合。""" - -from dataclasses import replace -from datetime import UTC, datetime, timedelta -from decimal import Decimal -from pathlib import Path - -import psycopg -import pytest -import test_两阶段写手 as 写手测试 -from psycopg import sql -from psycopg.conninfo import conninfo_to_dict, make_conninfo - -from muse.任务运行.接口 import 任务预算计划, 角色预算, 预算管理, 额度策略 -from muse.共享.调用身份 import 用途 -from muse.启动 import 构建默认运行 -from muse.基础设施.备份恢复 import 创建备份, 恢复备份 -from muse.编排.生成正文 import 发起生成正文 -from muse.编排.运行装配 import 推进作者任务 -from muse.配置 import 数据库引用 - -pytestmark = pytest.mark.数据库 -生成环境 = 写手测试.生成环境 - - -@pytest.mark.case_id( - "NC-w29-29f005", - environment="隔离PG", - given="显式作者、隔离配置、合成数据与已知发布构建", - when="经真实维护、业务或浏览器入口执行并读取持久结果", - then=["断源恢复模型任务只补未执行步骤并保持原预算与候选"], - contract="docs/系统架构/新版设计/迁移与验收.md#备份与恢复入口", -) -def test_断源恢复模型任务只补未执行步骤并保持原预算与候选__29f005( - 生成环境, 新空目标库, 隔离数据库URL, tmp_path -): - env = 生成环境 - config = env["装配"].配置 - app = 构建默认运行(config, 计价=写手测试.合成计价()) - author = env["作者"] - # 第二个装配另有常驻池,必须自己进入生命周期。 - with app.生命周期(): - original = app.要求正文().读取正文(author, "ch-3") - task_id = 发起生成正文( - app, - author, - "model-backup", - "new_chapter", - work_id="gen-work", - chapter_id="ch-3", - 配置ID="gen-config", - )["task_id"] - 预算管理(env["库"], "synthetic").登记策略(额度策略("synthetic", "1", Decimal("20"), 40)) - app.任务运行.批准作者预算( - task_id, - author.作者, - 任务预算计划( - Decimal("10"), - (角色预算("writer", 8, 8, Decimal("1")),), - "synthetic-backup-budget", - datetime.now(UTC) + timedelta(minutes=10), - ), - ) - budget = app.任务运行.读取作者预算(task_id, author.作者) - env["剧本"].extend( - 写手测试.正常剧本( - [ - "雨点敲着铁皮屋顶,林深把退回的信压在掌心。", - "他沿跳板走向仓库,门后传来一声应答。", - ] - ) - ) - assert 推进作者任务(app, author.作者, task_id)["executed_step"]["step_id"] == "预组装" - assert 推进作者任务(app, author.作者, task_id)["executed_step"]["step_id"] == "受限探索" - assert len(env["收到"]) == 4 - source_steps = app.任务运行.读取任务(task_id).步骤 - backup_config = replace(config, 数据库=env["库组"][用途.维护].引用, 运行用途=用途.维护) - archive = 创建备份(backup_config, tmp_path / "backup") - source_name = conninfo_to_dict(Path(config.数据库.位置).read_text())["dbname"] - with psycopg.connect(隔离数据库URL, autocommit=True) as admin: - admin.execute( - sql.SQL("ALTER DATABASE {} ALLOW_CONNECTIONS false").format( - sql.Identifier(source_name) - ) - ) - # 停用本例生成的旧暂存目录,恢复必须使用新目录;供应方凭据仍在受控存储。 - raw = Path(config.原文暂存) - raw.rename(tmp_path / "offline-original-raw") - restored_raw = tmp_path / "restored-raw" - restore_config = replace( - backup_config, - 数据库=新空目标库.工厂.引用, - 原文暂存=str(restored_raw), - ) - restored = 恢复备份(tmp_path / "backup", restore_config, archive["backup_id"]) - assert restored["status"] == "verified" and not restored["services_started"] - params = conninfo_to_dict(Path(新空目标库.工厂.引用.位置).read_text()) - params["user"] = "muse_app" - secret = tmp_path / "restored-app.txt" - secret.write_text(make_conninfo(**params)) - secret.chmod(0o600) - fresh = 构建默认运行( - replace(config, 数据库=数据库引用("受控存储", str(secret)), 原文暂存=str(restored_raw)), - 计价=写手测试.合成计价(), - ) - with fresh.生命周期(): - assert fresh.任务运行.读取作者预算(task_id, author.作者) == budget - assert fresh.任务运行.读取任务(task_id).步骤 == source_steps - assert len(env["收到"]) == 4 - for expected in ("冻结回放", "无工具写作", "检查与候选"): - result = 推进作者任务(fresh, author.作者, task_id) - assert result["executed_step"]["step_id"] == expected - assert result["state"] == "completed" and len(env["收到"]) == 5 - final = next(s["result"] for s in result["steps"] if s["step_id"] == "检查与候选") - candidate = fresh.要求正文().读取候选(author, final["candidate_id"]) - assert candidate["origin"] == "model" and candidate["decision"] == "undecided" - assert fresh.要求正文().读取正文(author, "ch-3") == original diff --git a/tests/集成/test_正式变更事务.py b/tests/集成/test_正式变更事务.py index 3cb699b..d9ea8e7 100644 --- a/tests/集成/test_正式变更事务.py +++ b/tests/集成/test_正式变更事务.py @@ -127,7 +127,10 @@ class 合成依赖: @pytest.fixture def 变更环境(应用测试库): with 应用测试库[用途.维护].连接() as 连: - 连.execute("""CREATE TABLE s01_test_document( + # 共享库模式下例间残留同名表;先幂等清理再建。 + 连.execute("""DROP TABLE IF EXISTS s01_test_document, s01_test_candidate, + s01_test_source, s01_test_audit CASCADE; + CREATE TABLE s01_test_document( id text PRIMARY KEY, owner text,revision int,content text); CREATE TABLE s01_test_candidate( id text PRIMARY KEY,revision int,content text,check_state text); diff --git a/tests/集成/test_生产评测权限隔离.py b/tests/集成/test_生产评测权限隔离.py index b9716f6..c6ffda3 100644 --- a/tests/集成/test_生产评测权限隔离.py +++ b/tests/集成/test_生产评测权限隔离.py @@ -191,13 +191,21 @@ def test_答案写入失败回滚整个发布__251003(应用测试库): "CREATE TRIGGER fail_answer BEFORE INSERT ON oracle.muse_dataset_answers " "FOR EACH ROW EXECUTE FUNCTION oracle.fail_answer()" ) - with pytest.raises(评测错误, match="评测存储操作失败"): - 评测服务(pool).发布数据集(_身份(用途.维护), _数据()) - with pool.连接(只读=True) as conn: - assert ( - conn.execute("SELECT count(*) FROM evaluation.muse_dataset_version").fetchone()[0] == 0 - ) - assert conn.execute("SELECT count(*) FROM oracle.muse_dataset_answers").fetchone()[0] == 0 + try: + with pytest.raises(评测错误, match="评测存储操作失败"): + 评测服务(pool).发布数据集(_身份(用途.维护), _数据()) + with pool.连接(只读=True) as conn: + assert ( + conn.execute("SELECT count(*) FROM evaluation.muse_dataset_version").fetchone()[0] + == 0 + ) + assert ( + conn.execute("SELECT count(*) FROM oracle.muse_dataset_answers").fetchone()[0] == 0 + ) + finally: + # 共享库例间只清业务数据;失败触发器与函数必须自愈,否则污染后续用例。 + with pool.连接() as conn, conn.transaction(): + conn.execute("DROP FUNCTION IF EXISTS oracle.fail_answer() CASCADE") @pytest.mark.case_id( @@ -390,16 +398,25 @@ def test_匿名映射中途失败回滚全部实验并能原命令重试__251009 "CREATE TRIGGER fail_assignment BEFORE INSERT ON oracle.muse_blind_assignment " "FOR EACH ROW EXECUTE FUNCTION oracle.fail_assignment()" ) - with pytest.raises(评测错误, match="评测存储操作失败"): - svc.创建实验(_身份(用途.评测), "recover", req) - with pools[用途.评测].连接(只读=True) as conn: - assert conn.execute("SELECT count(*) FROM evaluation.muse_experiment").fetchone()[0] == 0 - assert conn.execute("SELECT count(*) FROM oracle.muse_blind_assignment").fetchone()[0] == 0 - with pools[用途.维护].连接() as conn, conn.transaction(): - conn.execute("DROP TRIGGER fail_assignment ON oracle.muse_blind_assignment") - result = svc.创建实验(_身份(用途.评测), "recover", req) - assert len(result["sample_ids"]) == 3 - assert svc.创建实验(_身份(用途.评测), "recover", req) == result + try: + with pytest.raises(评测错误, match="评测存储操作失败"): + svc.创建实验(_身份(用途.评测), "recover", req) + with pools[用途.评测].连接(只读=True) as conn: + assert ( + conn.execute("SELECT count(*) FROM evaluation.muse_experiment").fetchone()[0] == 0 + ) + assert ( + conn.execute("SELECT count(*) FROM oracle.muse_blind_assignment").fetchone()[0] == 0 + ) + with pools[用途.维护].连接() as conn, conn.transaction(): + conn.execute("DROP TRIGGER fail_assignment ON oracle.muse_blind_assignment") + result = svc.创建实验(_身份(用途.评测), "recover", req) + assert len(result["sample_ids"]) == 3 + assert svc.创建实验(_身份(用途.评测), "recover", req) == result + finally: + # 共享库例间只清业务数据;失败触发器与函数必须自愈,否则污染后续用例。 + with pools[用途.维护].连接() as conn, conn.transaction(): + conn.execute("DROP FUNCTION IF EXISTS oracle.fail_assignment() CASCADE") @pytest.mark.case_id( diff --git a/tests/集成/test_系统管理与版本保护.py b/tests/集成/test_系统管理与版本保护.py index dbbd60b..90e9abf 100644 --- a/tests/集成/test_系统管理与版本保护.py +++ b/tests/集成/test_系统管理与版本保护.py @@ -22,6 +22,21 @@ pytestmark = pytest.mark.数据库 交付环境 = 定稿测试.交付环境 +@pytest.fixture +def 脏账本还原(应用测试库): + """账本污染用例的例后还原;muse_migration 属种子表不被例间清空,必须自愈。""" + from muse.基础设施.数据库.迁移 import 列出迁移 + + yield 应用测试库 + 基线 = 列出迁移()[0] + with 应用测试库[用途.维护].连接() as conn, conn.transaction(): + conn.execute("DELETE FROM muse_migration WHERE version > %s", (基线.版本,)) + conn.execute( + "UPDATE muse_migration SET name=%s, checksum=%s WHERE version=%s", + (基线.文件名, 基线.校验和, 基线.版本), + ) + + def _配置(pool, path): cfg = 接入测试._配置文件(pool, path) cfg.write_text( @@ -125,6 +140,7 @@ def test_系统页核实际代码资源版本且配置草案不启用__28b001( @pytest.mark.parametrize("mode", ["future", "checksum"]) def test_未知数据库版本或校验和漂移拒绝HTTP写入保留只读核对__28b002( 应用测试库, + 脏账本还原, tmp_path, mode, ): @@ -166,7 +182,7 @@ def test_未知数据库版本或校验和漂移拒绝HTTP写入保留只读核 then=["不兼容时CLI拒绝配置写入而系统诊断可读"], contract="docs/系统架构/新版设计/文件设计/工程配置与部署.md", ) -def test_不兼容时CLI拒绝配置写入而系统诊断可读__28b003(应用测试库, tmp_path, capsys): +def test_不兼容时CLI拒绝配置写入而系统诊断可读__28b003(应用测试库, 脏账本还原, tmp_path, capsys): _配置(应用测试库[用途.生产], tmp_path) cfg = next(tmp_path.glob("*.toml")) with 应用测试库[用途.维护].连接() as conn, conn.transaction(): diff --git a/tests/集成/test_结构版本与并发保护.py b/tests/集成/test_结构版本与并发保护.py deleted file mode 100644 index 31d9ddb..0000000 --- a/tests/集成/test_结构版本与并发保护.py +++ /dev/null @@ -1,338 +0,0 @@ -"""真实 PostgreSQL 验证元数据版本与调用方提交点;每例独占可销毁数据库。""" - -from __future__ import annotations - -from collections.abc import Iterator -from pathlib import Path - -import psycopg -import pytest - -from muse.元数据.接口 import ( - 元数据服务, - 元数据错误, - 导入内置结构, - 读取内置种子, -) -from muse.共享.调用身份 import 用途 -from muse.基础设施.数据库.连接 import 连接 -from muse.配置 import 数据库引用 - -pytestmark = pytest.mark.数据库 - - -@pytest.fixture -def 元数据库(数据库底座, tmp_path: Path) -> Iterator[数据库引用]: - # 此模板不导入种子;导入幂等、结构发布仍由每个测试实际执行。 - with 数据库底座.借库(tmp_path / "元数据引用", (1, 2)) as 工厂: - yield 工厂[用途.维护].引用 - - -@pytest.mark.case_id( - "NC-meta-seed-import-pg", - environment="隔离 PostgreSQL,每例独占新库", - given="隔离空库", - when="两次导入种子", - then=["24 个固定版本可回读且没有隐式绑定。"], - contract="docs/系统架构/新版设计/接口契约/元数据投影与版本.md", -) -def test_内置发布可重复且不自动启用__a42001(元数据库: 数据库引用) -> None: - """given 隔离空库;when 两次导入种子;then 24 个固定版本可回读且没有隐式绑定。""" - with 连接(元数据库, 用途标记=用途.维护) as 连: - 服务 = 元数据服务(连) - with 连.transaction(): - 初次 = 导入内置结构(服务) - 再次 = 导入内置结构(服务) - assert len(初次) == len(再次) == 24 - assert sum(not f.field_id.startswith("common.") for 项 in 初次 for f in 项.字段) == 216 - assert sum(f.field_id.startswith("common.") for 项 in 初次 for f in 项.字段) == 88 - for 种子 in 读取内置种子(): - assert 服务.读取结构(种子.结构.schema_id, 1) == 种子.结构 - with pytest.raises(元数据错误) as 错误: - 服务.读取绑定("work-a:character") - assert 错误.value.错误码 == "SCHEMA_UNKNOWN" - - -def 安装动态结构(连: psycopg.Connection): - from muse.元数据.接口 import ( - 值规则, - 合成结构, - 启用命令, - 字段定义, - 字段用途, - 类型定义, - 结构定义, - ) - - 服务 = 元数据服务(连) - 类型 = 类型定义("weather_spirit", "天气精灵", "world", "entity", ("entity",)) - 基础 = 结构定义( - "weather_spirit", - "weather_spirit", - 1, - ( - 字段定义( - "weather.name", - "名称", - "名称", - 值规则("text"), - 必填=True, - 用途=字段用途(aiContext=True), - ), - ), - ) - 服务.登记类型(类型) - 服务.登记结构候选(基础) - 服务.发布结构(基础.schema_id, 1, 基础.内容哈希) - 有效 = 合成结构(基础) - 命令 = 启用命令("activate-initial", 有效.effective_schema_hash, 0, "author-a", "work-a:spirit") - 绑定 = 服务.启用绑定("work-a:spirit", "work-a", 有效, 命令) - return 服务, 基础, 有效, 绑定, 命令 - - -@pytest.mark.case_id( - "NC-meta-binding-rollback-history", - environment="隔离 PostgreSQL,每例独占新库", - given="已启用结构", - when="发布作品扩展、回滚与重复内置导入", - then=["版本固定且旧值可回读。"], - contract="docs/系统架构/新版设计/接口契约/元数据投影与版本.md", -) -def test_扩展发布保留历史绑定且回滚不留半成品__a42002(元数据库: 数据库引用) -> None: - """given 已启用结构;when 发布作品扩展、回滚与重复内置导入;then 版本固定且旧值可回读。""" - from muse.元数据.接口 import 作品扩展, 值规则, 启用命令, 字段定义 - - with 连接(元数据库, 用途标记=用途.维护) as 连: - with 连.transaction(): - 服务, 基础, _, 旧绑定, 原命令 = 安装动态结构(连) - 扩展 = 作品扩展( - "work-a", - 基础.schema_id, - 1, - 1, - ( - 字段定义( - "work-a.affinity", "天气亲和", "天气亲和", 值规则("enum", 枚举=("雨", "雪")) - ), - ), - ) - 服务.发布扩展(扩展, 扩展.内容哈希) - 服务.发布扩展(扩展, 扩展.内容哈希) - 新结构 = 服务.读取有效结构(基础.schema_id, 1, work_id="work-a", extension_version=1) - assert 服务.读取绑定("work-a:spirit") == 旧绑定 - with pytest.raises(RuntimeError), 连.transaction(): - 服务.启用绑定( - "work-a:spirit", - "work-a", - 新结构, - 启用命令( - "activate-fail", 新结构.effective_schema_hash, 1, "author-a", "work-a:spirit" - ), - ) - raise RuntimeError("第二参与者失败") - with 连.transaction(): - assert 服务.读取绑定("work-a:spirit") == 旧绑定 - 新绑定 = 服务.启用绑定( - "work-a:spirit", - "work-a", - 新结构, - 启用命令( - "activate-ok", 新结构.effective_schema_hash, 1, "author-a", "work-a:spirit" - ), - ) - assert 新绑定.extension_version == 1 - 导入内置结构(服务) - assert 服务.读取绑定("work-a:spirit") == 新绑定 - assert 服务.读取结构(基础.schema_id, 1) == 基础 - # 原命令重放返回当时回执,不把当前绑定降回原版本。 - assert ( - 服务.启用绑定( - "work-a:spirit", "work-a", 服务.读取有效结构(基础.schema_id, 1), 原命令 - ) - == 旧绑定 - ) - assert 服务.读取绑定("work-a:spirit") == 新绑定 - - -@pytest.mark.case_id( - "NC-meta-reviewed-version-binding", - environment="隔离 PostgreSQL,每例独占新库", - given="已启用结构", - when="候选未发布或预期版本过期", - then=["不改变当前绑定。"], - contract="docs/系统架构/新版设计/接口契约/元数据投影与版本.md", -) -def test_候选未发布与过期绑定均不可启用__a42003(元数据库: 数据库引用) -> None: - """given 已启用结构;when 候选未发布或预期版本过期;then 不改变当前绑定。""" - from dataclasses import replace - - from muse.元数据.接口 import 合成结构, 启用命令 - - with 连接(元数据库, 用途标记=用途.维护) as 连: - with 连.transaction(): - 服务, 基础, _, 绑定, _ = 安装动态结构(连) - 新版 = replace(基础, schema_version=2, 父版本=1) - 服务.登记结构候选(新版) - 新 = 合成结构(新版) - with pytest.raises(元数据错误) as 错误: - 服务.启用绑定( - 绑定.target_ref, - 绑定.work_id, - 新, - 启用命令("draft", 新.effective_schema_hash, 1, "author-a", 绑定.target_ref), - ) - assert 错误.value.错误码 == "SCHEMA_UNKNOWN" - 服务.发布结构(新版.schema_id, 2, 新版.内容哈希) - with pytest.raises(元数据错误) as 错误: - 服务.启用绑定( - 绑定.target_ref, - 绑定.work_id, - 新, - 启用命令("stale", 新.effective_schema_hash, 0, "author-a", 绑定.target_ref), - ) - assert 错误.value.错误码 == "SCHEMA_STALE" - assert 服务.读取绑定(绑定.target_ref) == 绑定 - - -@pytest.mark.case_id( - "NC-meta-concurrent-submit-guard", - environment="隔离 PostgreSQL,每例独占新库", - given="已预览候选", - when="提交持有结构锁且另连接切换", - then=["切换等待且旧请求在切换后拒绝。"], - contract="docs/系统架构/新版设计/接口契约/元数据投影与版本.md", -) -@pytest.mark.parametrize( - "变更类别", ["structure", "policy"], ids=["schema-switch", "policy-revoke"] -) -def test_结构策略切换与业务提交共享锁__a42004(元数据库: 数据库引用, 变更类别: str) -> None: - """given 已预览候选;when 提交持有结构锁且另连接切换;then 切换等待且旧请求在切换后拒绝。""" - from concurrent.futures import ThreadPoolExecutor - from dataclasses import asdict, replace - - from muse.元数据.接口 import ( - 合成结构, - 启用命令, - 字段限制, - 定义哈希, - 投影字段, - 授权摘要, - 策略快照, - ) - - 授权 = 授权摘要("author-v1", "source-v1") - with 连接(元数据库, 用途标记=用途.维护) as 连: - with 连.transaction(): - 服务, 基础, 原结构, 绑定, _ = 安装动态结构(连) - 新版 = replace(基础, schema_version=2, 父版本=1) - 服务.登记结构候选(新版) - 服务.发布结构(新版.schema_id, 2, 新版.内容哈希) - 新结构 = 合成结构(新版) - # 仅夹具业务 owner 拥有此表;元数据模块从不访问它。 - 连.execute("CREATE TABLE public.meta_owner_probe (id int PRIMARY KEY, body text)") - 预览 = 投影字段( - 原结构, - 服务.当前策略(基础.type_id), - 授权, - 字段用途名="userEditable", - 内容用途="planning", - 运行用途="production", - ) - - def 切换(限时: bool) -> None: - with 连接(元数据库, 用途标记=用途.维护) as 第二连, 第二连.transaction(): - if 限时: - 第二连.execute("SET LOCAL lock_timeout='250ms'") - 第二服务 = 元数据服务(第二连) - if 变更类别 == "structure": - 第二服务.启用绑定( - 绑定.target_ref, - 绑定.work_id, - 新结构, - 启用命令( - "switch", 新结构.effective_schema_hash, 1, "author-a", 绑定.target_ref - ), - ) - else: - 新策略 = 策略快照( - 基础.type_id, 1, (字段限制("weather.name", ("userEditable",)),) - ) - 第二服务.更新策略( - 新策略, - 启用命令( - "revoke", - 定义哈希(asdict(新策略)), - 0, - "author-a", - f"type:{基础.type_id}", - ), - ) - - with 连.transaction(): - 服务.保护提交( - 绑定.target_ref, - 预览.effective_schema_hash, - 预览.projection_version, - 授权, - 字段用途名="userEditable", - 内容用途="planning", - 运行用途="production", - ) - with ThreadPoolExecutor(max_workers=1) as 池: - with pytest.raises(psycopg.errors.LockNotAvailable): - 池.submit(切换, True).result(timeout=5) - 连.execute("INSERT INTO public.meta_owner_probe VALUES (1, '作者确认的天气精灵')") - 切换(False) - with 连.transaction(): - with pytest.raises(元数据错误) as 错误: - 服务.保护提交( - 绑定.target_ref, - 预览.effective_schema_hash, - 预览.projection_version, - 授权, - 字段用途名="userEditable", - 内容用途="planning", - 运行用途="production", - ) - assert 错误.value.错误码 == ( - "SCHEMA_STALE" if 变更类别 == "structure" else "PROJECTION_STALE" - ) - assert 连.execute("SELECT id FROM public.meta_owner_probe").fetchall() == [(1,)] - - -@pytest.mark.case_id( - "NC-meta-immutable-extensions", - environment="隔离 PostgreSQL,每例独占新库", - given="已发布结构与作品扩展", - when="覆盖同版本或删除既有扩展", - then=["历史定义保持不变。"], - contract="docs/系统架构/新版设计/接口契约/元数据投影与版本.md", -) -def test_已发布定义与扩展追加合同不可绕过__a42005(元数据库: 数据库引用) -> None: - """given 已发布结构与作品扩展;when 覆盖同版本或删除既有扩展;then 历史定义保持不变。""" - from dataclasses import replace - - from muse.元数据.接口 import 作品扩展, 值规则, 字段定义 - - with 连接(元数据库, 用途标记=用途.维护) as 连, 连.transaction(): - 服务, 基础, _, _, _ = 安装动态结构(连) - assert 服务.读取类型(基础.type_id).实例族 == ("entity",) - with pytest.raises(元数据错误) as 错误: - 服务.登记结构候选(replace(基础, 字段=())) - assert 错误.value.错误码 == "SCHEMA_CONFLICT" - 扩展 = 作品扩展( - "work-a", - 基础.schema_id, - 1, - 1, - (字段定义("work-a.temp", "体温", "体温", 值规则("number")),), - ) - 服务.发布扩展(扩展, 扩展.内容哈希) - 丢字段 = replace(扩展, extension_version=2, 字段=()) - with pytest.raises(元数据错误) as 错误: - 服务.发布扩展(丢字段, 丢字段.内容哈希) - assert 错误.value.错误码 == "FIELD_NOT_ALLOWED" - assert 服务.读取结构(基础.schema_id, 1) == 基础 - assert ( - 服务.读取有效结构(基础.schema_id, 1, work_id="work-a", extension_version=1).扩展 == 扩展 - ) diff --git a/tests/集成/test_预算预留与结算.py b/tests/集成/test_预算预留与结算.py index 15e9de7..dcd0817 100644 --- a/tests/集成/test_预算预留与结算.py +++ b/tests/集成/test_预算预留与结算.py @@ -1,28 +1,22 @@ -"""真实 PG 的预算原子预留、成本状态与配置版本;不调用外部模型。""" +"""预算的核心保护:并发不超额、重复调用不重复计费。 -from __future__ import annotations +按简化决策删除其余变体用例;夹具从按例克隆改为共享库以消除建库开销。 +""" -import dataclasses -import time import uuid from concurrent.futures import ThreadPoolExecutor from datetime import UTC, datetime, timedelta from decimal import Decimal from pathlib import Path -from threading import Barrier -import psycopg import pytest -from muse.任务运行.接口 import 任务服务, 任务请求, 步骤处理器, 步骤结果, 步骤计划 -from muse.任务运行.模型 import 内容哈希 -from muse.任务运行.配置版本 import ( - 凭据引用, - 提供方配置, - 运行配置内容, - 配置版本管理, - 配置版本错误, - 配置验证证据, +from muse.任务运行.接口 import ( + 任务服务, + 任务请求, + 步骤处理器, + 步骤结果, + 步骤计划, ) from muse.任务运行.预算管理 import ( 任务预算计划, @@ -41,8 +35,7 @@ pytestmark = pytest.mark.数据库 @pytest.fixture def 预算环境(数据库底座, monkeypatch: pytest.MonkeyPatch, tmp_path: Path): - with 数据库底座.借库(tmp_path / "连接引用") as 工厂: - # 子进程恢复入口继承相同的按例数据库,仍跨真实连接验证提交。 + with 数据库底座.共享库(tmp_path / "连接引用") as 工厂: for 声明, 当前 in 工厂.items(): monkeypatch.setenv(f"MUSE_BUDGET_{声明.name}_URL", Path(当前.引用.位置).read_text()) yield 工厂 @@ -102,6 +95,8 @@ def 建预算(工厂: 数据库工厂, 任务ID: str, *, 窗口金额="24", 单 contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", ) def test_并发预留共享窗口且不超额__a61001(预算环境) -> None: + from threading import Barrier + A, 领取A = 新任务(预算环境[用途.生产]) B, 领取B = 新任务(预算环境[用途.生产]) 预算A = 建预算(预算环境[用途.生产], A, 窗口金额="10") @@ -144,237 +139,3 @@ def test_重复预留发送和结算不重复计费__a61002(预算环境) -> Non 预算.结算("call-1", Decimal("0.2"), 回执ID="changed") assert 预算.窗口余额()["已知成本"] == Decimal("0.125") assert 预算.窗口余额()["已占次数"] == 1 - - -@pytest.mark.case_id( - "NC-budget-unknown-across-window", - environment="隔离 PostgreSQL;配置验证器为显式协议替身", - given="已发送无成本回执的调用且注入旧窗口", - when="尝试新调用并进行可信对账", - then=["未知不计零且跨窗阻断,对账后恢复"], - contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", -) -def test_未知成本跨窗口仍阻止后续调用直至对账__a61003(预算环境) -> None: - 身份, 领取 = 新任务(预算环境[用途.生产]) - 预算 = 建预算(预算环境[用途.生产], 身份) - 预算.预留(领取, "unknown", "writer") - 预算.标记已发送(领取, "unknown", 最长秒=30) - 未知 = 预算.结算("unknown", None, 回执ID="missing-cost") - assert 未知.实际金额 is None and 未知.状态 == "unknown" - with 预算环境[用途.维护].连接() as 连: - 连.execute( - "UPDATE public.muse_budget_reservation SET window_start=window_start-interval '1 " - "day',window_end=window_end-interval '1 day' WHERE call_id='unknown'" - ) - assert 预算.窗口余额()["未知调用数"] == 1 - with pytest.raises(预算不足, match="未知成本"): - 预算.预留(领取, "next", "writer") - 预算.结算("unknown", Decimal("0.2"), 回执ID="resolved-receipt") - assert 预算.预留(领取, "next", "writer").状态 == "reserved" - - -@pytest.mark.case_id( - "NC-budget-cancellation", - environment="隔离 PostgreSQL;配置验证器为显式协议替身", - given="未发送或已发送的预留", - when="关闭任务预算", - then=["未发送释放、已发送未知且任务不再外发"], - contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", -) -@pytest.mark.parametrize("已发出", [False, True], ids=["before-send", "after-send"]) -def test_取消保留已发送调用的未知成本__a61004(预算环境, 已发出: bool) -> None: - 身份, 领取 = 新任务(预算环境[用途.生产]) - 预算 = 建预算(预算环境[用途.生产], 身份) - 预算.预留(领取, "cancel", "writer") - if 已发出: - 预算.标记已发送(领取, "cancel", 最长秒=30) - 预算.关闭任务预算(身份) - assert 预算.读取("cancel").状态 == ("unknown" if 已发出 else "released") - with pytest.raises(预算不足): - 预算.预留(领取, "blocked", "writer") - - -@pytest.mark.case_id( - "NC-budget-expiration", - environment="隔离 PostgreSQL;配置验证器为显式协议替身", - given="未发送或在途预留期限到达", - when="真实时间过期后回收", - then=["未发送释放,在途保留未知成本"], - contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", -) -@pytest.mark.parametrize("已发出", [False, True], ids=["reserved", "in-flight"]) -def test_过期只释放尚未发送的预留__a61005(预算环境, 已发出: bool) -> None: - 身份, 领取 = 新任务(预算环境[用途.生产]) - 预算 = 建预算(预算环境[用途.生产], 身份) - 预算.预留(领取, "expire", "writer", 有效秒=0.08 if not 已发出 else 30) - if 已发出: - 预算.标记已发送(领取, "expire", 最长秒=0.08) - time.sleep(0.12) - 预算.回收过期() - assert 预算.读取("expire").状态 == ("unknown" if 已发出 else "released") - if not 已发出: - assert 预算.窗口余额()["在途预留"] == 0 - assert 预算.预留(领取, "fresh", "writer").状态 == "reserved" - - -@pytest.mark.case_id( - "NC-budget-actual-over-cap", - environment="隔离 PostgreSQL;配置验证器为显式协议替身", - given="实际成本超过单次预留金额", - when="用真实回执结算", - then=["保存真实金额和超额标记,停止任务预算"], - contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", -) -def test_超单次成本先保存事实并关闭任务预算__a61006(预算环境) -> None: - 身份, 领取 = 新任务(预算环境[用途.生产]) - 预算 = 建预算(预算环境[用途.生产], 身份) - 预算.预留(领取, "over", "writer") - 预算.标记已发送(领取, "over", 最长秒=30) - 已记 = 预算.结算("over", Decimal("7"), 回执ID="actual-over") - assert 已记.超预算 and 已记.实际金额 == Decimal("7") - assert 预算.窗口余额()["已知成本"] == Decimal("7") - with pytest.raises(预算不足): - 预算.预留(领取, "next", "writer") - - -@pytest.mark.case_id( - "NC-budget-settlement-rollback", - environment="隔离 PostgreSQL;配置验证器为显式协议替身", - given="调用在途及PG注入结算失败触发器", - when="结算回滚后移除故障再结算", - then=["故障保留在途标记和未知实际金额,可恢复结算"], - contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", -) -def test_结算失败回滚仍保留在途标记__a61007(预算环境) -> None: - 身份, 领取 = 新任务(预算环境[用途.生产]) - 预算 = 建预算(预算环境[用途.生产], 身份) - 预算.预留(领取, "atomic", "writer") - 预算.标记已发送(领取, "atomic", 最长秒=30) - with 预算环境[用途.维护].连接() as 连: - 连.execute( - "CREATE FUNCTION public.reject_settlement() RETURNS trigger LANGUAGE plpgsql AS $$ " - "BEGIN IF NEW.state='settled' THEN RAISE EXCEPTION 'synthetic failure'; END IF; " - "RETURN NEW; END $$" - ) - 连.execute( - "CREATE TRIGGER reject_settlement BEFORE UPDATE ON public.muse_budget_reservation " - "FOR EACH ROW EXECUTE FUNCTION public.reject_settlement()" - ) - with pytest.raises(psycopg.errors.RaiseException): - 预算.结算("atomic", Decimal("1"), 回执ID="receipt") - assert 预算.读取("atomic").状态 == "in_flight" - assert 预算.读取("atomic").实际金额 is None - with 预算环境[用途.维护].连接() as 连: - 连.execute("DROP TRIGGER reject_settlement ON public.muse_budget_reservation") - assert 预算.结算("atomic", Decimal("1"), 回执ID="receipt").状态 == "settled" - - -@pytest.mark.case_id( - "NC-budget-call-limits", - environment="隔离 PostgreSQL;配置验证器为显式协议替身", - given="窗口次数或任务计划只剩一次", - when="结算零成本调用后尝试下一次", - then=["两类次数限制都独立生效"], - contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", -) -@pytest.mark.parametrize("模式", ["window", "task"], ids=["window", "task"]) -def test_窗口次数和任务计划分别限制调用__a61008(预算环境, 模式: str) -> None: - 身份, 领取 = 新任务(预算环境[用途.生产]) - 预算 = 建预算( - 预算环境[用途.生产], - 身份, - 窗口次数=1 if 模式 == "window" else 6000, - 次数=3 if 模式 == "window" else 1, - ) - 预算.预留(领取, "first", "writer") - 预算.标记已发送(领取, "first", 最长秒=30) - 预算.结算("first", Decimal("0"), 回执ID="free-but-called") - with pytest.raises(预算不足, match="次数"): - 预算.预留(领取, "second", "writer") - - -class 合成配置验证器: - 身份 = "synthetic-contract-check-v1" - - def 验证(self, 内容: 运行配置内容, 执行用途: 用途) -> 配置验证证据: - assert 内容.角色配置["writer"]["model"] == "model" - return 配置验证证据( - 内容哈希(内容.冻结()), - 内容.角色策略版本, - 内容.资源发布身份, - 执行用途, - ("synthetic-protocol-result",), - "offline_contract", - ) - - -def 配置内容(版本="1"): - return 运行配置内容( - "direct", - 版本, - "policy-1", - "release-1", - "quota-1", - {"writer": {"provider": "provider", "model": "model", "thinking": "high"}}, - (凭据引用("api", "环境变量", "MUSE_API_KEY"),), - (提供方配置("provider", "responses", "https://provider.invalid/v1/responses", "api"),), - "price-1", - ) - - -@pytest.mark.case_id( - "NC-config-version-freeze", - environment="隔离 PostgreSQL;配置验证器为显式协议替身", - given="显式合成验证器和两版配置", - when="验证启用、任务冻结、升级和停用", - then=["版本不可覆盖,CAS与回执匹配,旧任务副本保留"], - contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", -) -def test_配置验证启用与任务冻结版本互不覆盖__a61009(预算环境) -> None: - 管理 = 配置版本管理(预算环境[用途.评测], 合成配置验证器()) - A, _ = 新任务(预算环境[用途.评测]) - 原 = 管理.保存草案("config", "1", 配置内容()) - with pytest.raises(配置版本错误): - 管理.冻结到任务(A, "config") - with pytest.raises(配置版本错误): - 管理.保存草案("config", "1", 配置内容("changed")) - R1 = 管理.验证版本("config", "1") - assert 管理.启用("config", "1", 验证回执=R1, 批准引用="approve-1", 预期代次=0) == 1 - assert 管理.启用("config", "1", 验证回执=R1, 批准引用="approve-1", 预期代次=0) == 1 - 冻结 = 管理.冻结到任务(A, "config") - 管理.保存草案("config", "2", 配置内容("2")) - R2 = 管理.验证版本("config", "2") - with pytest.raises(配置版本错误): - 管理.启用("config", "2", 验证回执=R1, 批准引用="approve-2", 预期代次=1) - assert 管理.启用("config", "2", 验证回执=R2, 批准引用="approve-2", 预期代次=1) == 2 - assert 管理.冻结到任务(A, "config") == 冻结 == 原 - B, _ = 新任务(预算环境[用途.评测]) - assert 管理.冻结到任务(B, "config").版本 == "2" - 管理.停用("config", 预期代次=2) - C, _ = 新任务(预算环境[用途.评测]) - with pytest.raises(配置版本错误): - 管理.冻结到任务(C, "config") - assert 管理.冻结到任务(A, "config").版本 == "1" - - -@pytest.mark.case_id( - "NC-config-validation-binding", - environment="隔离 PostgreSQL;配置验证器为显式协议替身", - given="陈旧绑定或离线证据用于生产", - when="验证配置版本", - then=["绑定不符和离线生产都拒绝"], - contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md", -) -def test_配置不接受陈旧验证或离线证据启用生产__a6100a(预算环境) -> None: - class 陈旧验证器(合成配置验证器): - def 验证(self, 内容, 执行用途): - return dataclasses.replace(super().验证(内容, 执行用途), 配置哈希="old-hash") - - 管理 = 配置版本管理(预算环境[用途.评测], 陈旧验证器()) - 管理.保存草案("config", "1", 配置内容()) - with pytest.raises(配置版本错误, match="绑定"): - 管理.验证版本("config", "1") - 生产 = 配置版本管理(预算环境[用途.生产], 合成配置验证器()) - 生产.保存草案("config", "1", 配置内容()) - with pytest.raises(配置版本错误, match="离线"): - 生产.验证版本("config", "1") diff --git a/数据库/迁移/V0001__共享标识与版本.sql b/数据库/迁移/V0001__共享标识与版本.sql deleted file mode 100644 index 2f9342c..0000000 --- a/数据库/迁移/V0001__共享标识与版本.sql +++ /dev/null @@ -1,64 +0,0 @@ --- V0001 共享标识与版本:新版数据库的共享基础。 --- 内容:迁移账本 + 跨模块共用的身份域(用途、内容用途、候选状态、审阅动作)。 --- 边界:只建立共享基础;业务对象表由 V0005 起各模块迁移建立, --- 不在本版本预建业务列,也不复用旧库 DDL。 - --- 迁移账本:版本、校验和与应用时间是数据演进的唯一事实(迁移执行器维护) -CREATE TABLE muse_migration ( - version integer PRIMARY KEY CHECK (version >= 1), - name text NOT NULL, - checksum text NOT NULL CHECK (length(checksum) = 64), - applied_at timestamptz NOT NULL DEFAULT now() -); - --- 执行隔离用途:与 src/muse/共享/调用身份.py 的 StrEnum 一一对应 -CREATE TYPE muse_purpose AS ENUM ( - 'production', - 'evaluation', - 'maintenance' -); - --- 内容消费用途:任务与工具按此裁剪可见字段 -CREATE TYPE muse_content_purpose AS ENUM ( - 'planning', - 'generation', - 'detection', - 'extraction' -); - --- 候选状态:候选先审后入的状态轴(各业务模块实例共用同一解释) -CREATE TYPE muse_candidate_state AS ENUM ( - 'draft', - 'candidate', - 'adopted', - 'rejected', - 'retired' -); - --- 审阅动作:作者决策的闭合集合 -CREATE TYPE muse_review_action AS ENUM ( - 'adopt', - 'reject', - 'revise' -); - --- 固定角色在目标环境初始化,迁移必须由 muse_maint 执行。 --- schema 负责用途边界;业务模块后续迁移在相应用途中建立自己的对象。 -REVOKE ALL ON SCHEMA public FROM PUBLIC; -GRANT USAGE ON SCHEMA public TO muse_app, muse_eval; -CREATE SCHEMA evaluation AUTHORIZATION muse_maint; -CREATE SCHEMA oracle AUTHORIZATION muse_maint; -REVOKE ALL ON SCHEMA evaluation, oracle FROM PUBLIC; -GRANT USAGE ON SCHEMA evaluation, oracle TO muse_eval; - --- 维护账本不授予运行角色写权限;后续生产表只允许生产角色读写。 -ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA public - GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO muse_app; -ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA public - GRANT USAGE, SELECT ON SEQUENCES TO muse_app; -ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA evaluation - GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO muse_eval; -ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA evaluation - GRANT USAGE, SELECT ON SEQUENCES TO muse_eval; -ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA oracle - GRANT SELECT ON TABLES TO muse_eval; diff --git a/数据库/迁移/V0001__基线.sql b/数据库/迁移/V0001__基线.sql new file mode 100644 index 0000000..67a5938 --- /dev/null +++ b/数据库/迁移/V0001__基线.sql @@ -0,0 +1,10085 @@ +-- V0001 基线:51 步迁移链(V0009-V0061 时代结构)压扁后的完整快照。 +-- 内容 = 当前全部表结构 + 系统种子数据 + 角色授权;不含迁移账本数据行。 +-- 改表流程:修改本文件 + 在正式库手动执行对应 ALTER;动前先备份。 +-- 等价验证:旧链全量执行库与本基线库的 pg_dump 逐字节一致(见 docs/运行手册.md)。 + +-- +-- PostgreSQL database dump +-- + + +-- Dumped from database version 18.6 (Homebrew) +-- Dumped by pg_dump version 18.6 (Homebrew) + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: evaluation; Type: SCHEMA; Schema: -; Owner: muse_maint +-- + +CREATE SCHEMA evaluation; + + +ALTER SCHEMA evaluation OWNER TO muse_maint; + +-- +-- Name: metadata; Type: SCHEMA; Schema: -; Owner: muse_maint +-- + +CREATE SCHEMA metadata; + + +ALTER SCHEMA metadata OWNER TO muse_maint; + +-- +-- Name: oracle; Type: SCHEMA; Schema: -; Owner: muse_maint +-- + +CREATE SCHEMA oracle; + + +ALTER SCHEMA oracle OWNER TO muse_maint; + +-- +-- Name: public; Type: SCHEMA; Schema: -; Owner: qingse +-- + +-- *not* creating schema, since initdb creates it + + + +-- +-- Name: muse_candidate_state; Type: TYPE; Schema: public; Owner: muse_maint +-- + +CREATE TYPE public.muse_candidate_state AS ENUM ( + 'draft', + 'candidate', + 'adopted', + 'rejected', + 'retired' +); + + +ALTER TYPE public.muse_candidate_state OWNER TO muse_maint; + +-- +-- Name: muse_content_purpose; Type: TYPE; Schema: public; Owner: muse_maint +-- + +CREATE TYPE public.muse_content_purpose AS ENUM ( + 'planning', + 'generation', + 'detection', + 'extraction' +); + + +ALTER TYPE public.muse_content_purpose OWNER TO muse_maint; + +-- +-- Name: muse_purpose; Type: TYPE; Schema: public; Owner: muse_maint +-- + +CREATE TYPE public.muse_purpose AS ENUM ( + 'production', + 'evaluation', + 'maintenance' +); + + +ALTER TYPE public.muse_purpose OWNER TO muse_maint; + +-- +-- Name: muse_review_action; Type: TYPE; Schema: public; Owner: muse_maint +-- + +CREATE TYPE public.muse_review_action AS ENUM ( + 'adopt', + 'reject', + 'revise' +); + + +ALTER TYPE public.muse_review_action OWNER TO muse_maint; + +-- +-- Name: muse_guard_unit_binding(); Type: FUNCTION; Schema: evaluation; Owner: muse_maint +-- + +CREATE FUNCTION evaluation.muse_guard_unit_binding() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + IF TG_OP='DELETE' THEN RAISE EXCEPTION 'evaluation unit is immutable'; END IF; + IF OLD.task_id IS NOT NULL OR NEW.task_id IS NULL OR + (to_jsonb(OLD)-'task_id') <> (to_jsonb(NEW)-'task_id') THEN + RAISE EXCEPTION 'only first task binding is allowed'; + END IF; + RETURN NEW; +END $$; + + +ALTER FUNCTION evaluation.muse_guard_unit_binding() OWNER TO muse_maint; + +-- +-- Name: immutable_definition(); Type: FUNCTION; Schema: metadata; Owner: muse_maint +-- + +CREATE FUNCTION metadata.immutable_definition() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + IF TG_OP = 'DELETE' THEN + RAISE EXCEPTION '元数据历史版本不可删除'; + END IF; + IF NEW.definition IS DISTINCT FROM OLD.definition + OR NEW.content_hash IS DISTINCT FROM OLD.content_hash THEN + RAISE EXCEPTION '元数据定义不可修改,必须新增版本'; + END IF; + RETURN NEW; +END; +$$; + + +ALTER FUNCTION metadata.immutable_definition() OWNER TO muse_maint; + +-- +-- Name: muse_branch_source_immutable(); Type: FUNCTION; Schema: public; Owner: muse_maint +-- + +CREATE FUNCTION public.muse_branch_source_immutable() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + RAISE EXCEPTION 'branch and merge origins are immutable'; +END; +$$; + + +ALTER FUNCTION public.muse_branch_source_immutable() OWNER TO muse_maint; + +-- +-- Name: muse_guard_legacy_import_record(); Type: FUNCTION; Schema: public; Owner: muse_maint +-- + +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; +$$; + + +ALTER FUNCTION public.muse_guard_legacy_import_record() OWNER TO muse_maint; + +-- +-- Name: muse_guard_literary_history(); Type: FUNCTION; Schema: public; Owner: muse_maint +-- + +CREATE FUNCTION public.muse_guard_literary_history() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + RAISE EXCEPTION '文学片结果与报告只追加,不改写或删除历史'; +END; +$$; + + +ALTER FUNCTION public.muse_guard_literary_history() OWNER TO muse_maint; + +-- +-- Name: muse_guard_source_analysis(); Type: FUNCTION; Schema: public; Owner: muse_maint +-- + +CREATE FUNCTION public.muse_guard_source_analysis() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + RAISE EXCEPTION '分析版本只追加,不改写或删除历史'; +END; +$$; + + +ALTER FUNCTION public.muse_guard_source_analysis() OWNER TO muse_maint; + +-- +-- Name: muse_guard_source_slice(); Type: FUNCTION; Schema: public; Owner: muse_maint +-- + +CREATE FUNCTION public.muse_guard_source_slice() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + RAISE EXCEPTION '场景切片是派生数据,禁止原地改写;重建请整批删除后重算'; + END; + $$; + + +ALTER FUNCTION public.muse_guard_source_slice() OWNER TO muse_maint; + +-- +-- Name: muse_guard_voice_history(); Type: FUNCTION; Schema: public; Owner: muse_maint +-- + +CREATE FUNCTION public.muse_guard_voice_history() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + RAISE EXCEPTION '声音提案与历史版本只追加,不改写或删除'; +END; +$$; + + +ALTER FUNCTION public.muse_guard_voice_history() OWNER TO muse_maint; + +-- +-- Name: muse_method_index_changed(); Type: FUNCTION; Schema: public; Owner: muse_maint +-- + +CREATE FUNCTION public.muse_method_index_changed() RETURNS trigger + LANGUAGE plpgsql SECURITY DEFINER + SET search_path TO 'pg_catalog' + AS $$ +BEGIN + UPDATE public.muse_method_index_guard + SET generation = generation + 1 + WHERE singleton; + IF NOT FOUND THEN + RAISE EXCEPTION 'method index mutation guard is missing'; + END IF; + RETURN NULL; +END +$$; + + +ALTER FUNCTION public.muse_method_index_changed() OWNER TO muse_maint; + +-- +-- Name: muse_source_slice_changed(); Type: FUNCTION; Schema: public; Owner: muse_maint +-- + +CREATE FUNCTION public.muse_source_slice_changed() RETURNS trigger + LANGUAGE plpgsql SECURITY DEFINER + SET search_path TO 'pg_catalog' + AS $$ + BEGIN + UPDATE public.muse_source_slice_guard + SET generation = generation + 1 + WHERE singleton; + IF NOT FOUND THEN + RAISE EXCEPTION 'source slice mutation guard is missing'; + END IF; + RETURN NULL; + END; + $$; + + +ALTER FUNCTION public.muse_source_slice_changed() OWNER TO muse_maint; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: muse_attempt; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_attempt ( + attempt_id uuid NOT NULL, + task_id uuid NOT NULL, + step_id text NOT NULL, + worker_id text NOT NULL, + lease_token uuid NOT NULL, + lease_until timestamp with time zone NOT NULL, + scope_generation bigint, + heartbeat_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + state text NOT NULL, + call_state text DEFAULT 'not_sent'::text NOT NULL, + call_reference text, + result jsonb, + failure_code text, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_attempt_call_state_check CHECK ((call_state = ANY (ARRAY['not_sent'::text, 'sent'::text, 'unknown'::text, 'saved'::text]))), + CONSTRAINT muse_attempt_state_check CHECK ((state = ANY (ARRAY['running'::text, 'expired'::text, 'paused'::text, 'cancelled'::text, 'completed'::text, 'failed'::text, 'unknown'::text]))) +); + + +ALTER TABLE evaluation.muse_attempt OWNER TO muse_maint; + +-- +-- Name: muse_budget_account; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.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 +); + + +ALTER TABLE evaluation.muse_budget_account OWNER TO muse_maint; + +-- +-- Name: muse_budget_reservation; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.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, + attempt_id uuid NOT NULL, + role_id text NOT NULL, + request_hash text NOT NULL, + state text NOT NULL, + reserved_amount numeric(24,6) NOT NULL, + actual_amount numeric(24,6), + window_start timestamp with time zone NOT NULL, + window_end timestamp with time zone NOT NULL, + expires_at timestamp with time zone NOT NULL, + sent_at timestamp with time zone, + receipt_id text, + reason text, + over_budget boolean DEFAULT false NOT NULL, + CONSTRAINT muse_budget_reservation_actual_amount_check CHECK ((actual_amount >= (0)::numeric)), + CONSTRAINT muse_budget_reservation_check CHECK (((state = 'settled'::text) = (actual_amount IS NOT NULL))), + CONSTRAINT muse_budget_reservation_reserved_amount_check CHECK ((reserved_amount >= (0)::numeric)), + CONSTRAINT muse_budget_reservation_state_check CHECK ((state = ANY (ARRAY['reserved'::text, 'in_flight'::text, 'unknown'::text, 'settled'::text, 'released'::text]))) +); + + +ALTER TABLE evaluation.muse_budget_reservation OWNER TO muse_maint; + +-- +-- Name: muse_calibration_receipt; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_calibration_receipt ( + experiment_id uuid NOT NULL, + receipt_id uuid NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_calibration_receipt_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_calibration_receipt_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_calibration_receipt OWNER TO muse_maint; + +-- +-- Name: muse_call_reconciliation; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_call_reconciliation ( + task_id uuid NOT NULL, + command_id text NOT NULL, + request_hash text NOT NULL, + receipt jsonb NOT NULL, + CONSTRAINT muse_call_reconciliation_command_id_check CHECK ((btrim(command_id) <> ''::text)), + CONSTRAINT muse_call_reconciliation_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_call_reconciliation OWNER TO muse_maint; + +-- +-- Name: muse_call_settlement; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_call_settlement ( + task_id uuid NOT NULL, + command_id text NOT NULL, + receipt_id uuid NOT NULL, + request_hash text NOT NULL, + receipt jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_call_settlement_command_id_check CHECK ((btrim(command_id) <> ''::text)), + CONSTRAINT muse_call_settlement_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_call_settlement OWNER TO muse_maint; + +-- +-- Name: muse_comparison_rejection; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_comparison_rejection ( + unit_id uuid NOT NULL, + sequence smallint NOT NULL, + task_id uuid NOT NULL, + attempt_id uuid NOT NULL, + call_id text NOT NULL, + user_input_hash text NOT NULL, + output jsonb NOT NULL, + failure_code text NOT NULL, + previous_hash text, + record_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_comparison_rejection_failure_code_check CHECK ((failure_code = ANY (ARRAY['PAIRWISE_QUOTE_NOT_FOUND'::text, 'PAIRWISE_NOT_EXECUTED'::text]))), + CONSTRAINT muse_comparison_rejection_previous_hash_check CHECK ((previous_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_comparison_rejection_record_hash_check CHECK ((record_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_comparison_rejection_sequence_check CHECK (((sequence >= 1) AND (sequence <= 3))), + CONSTRAINT muse_comparison_rejection_user_input_hash_check CHECK ((user_input_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_comparison_rejection OWNER TO muse_maint; + +-- +-- Name: muse_config_probe_binding; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_config_probe_binding ( + task_id uuid NOT NULL, + config_id text NOT NULL, + version text NOT NULL, + content_hash text NOT NULL, + content jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_config_probe_binding_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_config_probe_binding OWNER TO muse_maint; + +-- +-- Name: muse_context_snapshot; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_context_snapshot ( + snapshot_id uuid NOT NULL, + run_purpose public.muse_purpose NOT NULL, + task_id uuid NOT NULL, + work_id text NOT NULL, + input_hash text NOT NULL, + frozen_scope jsonb NOT NULL, + assembly jsonb NOT NULL, + source_bindings jsonb NOT NULL, + created_by text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_context_snapshot_assembly_check CHECK ((assembly ? ALL (ARRAY['入选'::text, '省略'::text, '字节数'::text, '文本哈希'::text, '文本'::text]))), + CONSTRAINT muse_context_snapshot_source_bindings_check CHECK ((jsonb_typeof(source_bindings) = 'array'::text)) +); + + +ALTER TABLE evaluation.muse_context_snapshot OWNER TO muse_maint; + +-- +-- Name: muse_dataset_version; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_dataset_version ( + version_id uuid NOT NULL, + dataset_id text NOT NULL, + revision bigint NOT NULL, + public_manifest jsonb NOT NULL, + public_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_dataset_version_public_hash_check CHECK ((public_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_dataset_version_public_manifest_check CHECK ((jsonb_typeof(public_manifest) = 'object'::text)), + CONSTRAINT muse_dataset_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE evaluation.muse_dataset_version OWNER TO muse_maint; + +-- +-- Name: muse_effect_assessment; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_effect_assessment ( + experiment_id uuid NOT NULL, + receipt_id uuid NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE evaluation.muse_effect_assessment OWNER TO muse_maint; + +-- +-- Name: muse_evaluation_condition; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_evaluation_condition ( + unit_id uuid NOT NULL, + decision jsonb NOT NULL, + decision_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_evaluation_condition_decision_hash_check CHECK ((decision_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_evaluation_condition OWNER TO muse_maint; + +-- +-- Name: muse_evaluation_output; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_evaluation_output ( + unit_id uuid NOT NULL, + task_id uuid NOT NULL, + attempt_id uuid NOT NULL, + call_id text NOT NULL, + user_input_hash text NOT NULL, + output jsonb NOT NULL, + output_hash text NOT NULL, + evidence jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE evaluation.muse_evaluation_output OWNER TO muse_maint; + +-- +-- Name: muse_evaluation_reuse; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_evaluation_reuse ( + unit_id uuid NOT NULL, + source_unit_id uuid NOT NULL, + source_experiment_id uuid NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_evaluation_reuse_check CHECK ((unit_id <> source_unit_id)), + CONSTRAINT muse_evaluation_reuse_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_evaluation_reuse_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_evaluation_reuse OWNER TO muse_maint; + +-- +-- Name: muse_evaluation_unit; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_evaluation_unit ( + unit_id uuid NOT NULL, + experiment_id uuid NOT NULL, + sample_id text NOT NULL, + kind text NOT NULL, + specification jsonb NOT NULL, + specification_hash text NOT NULL, + task_id uuid, + CONSTRAINT muse_evaluation_unit_kind_check CHECK ((kind = ANY (ARRAY['generation'::text, 'comparison'::text, 'detection'::text]))) +); + + +ALTER TABLE evaluation.muse_evaluation_unit OWNER TO muse_maint; + +-- +-- Name: muse_experiment; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_experiment ( + experiment_id uuid NOT NULL, + author_id text NOT NULL, + command_id text NOT NULL, + request_hash text NOT NULL, + dataset_version_id uuid NOT NULL, + conditions jsonb NOT NULL, + conditions_hash text NOT NULL, + sample_ids jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_experiment_conditions_check CHECK ((jsonb_typeof(conditions) = 'object'::text)), + CONSTRAINT muse_experiment_conditions_hash_check CHECK ((conditions_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_experiment_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_experiment_sample_ids_check CHECK (((jsonb_typeof(sample_ids) = 'array'::text) AND (jsonb_array_length(sample_ids) > 0))) +); + + +ALTER TABLE evaluation.muse_experiment OWNER TO muse_maint; + +-- +-- Name: muse_experiment_execution; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_experiment_execution ( + experiment_id uuid NOT NULL, + request_hash text NOT NULL, + plan jsonb NOT NULL, + plan_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE evaluation.muse_experiment_execution OWNER TO muse_maint; + +-- +-- Name: muse_experiment_stop; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_experiment_stop ( + experiment_id uuid NOT NULL, + author_id text NOT NULL, + command_id text NOT NULL, + stopped_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE evaluation.muse_experiment_stop OWNER TO muse_maint; + +-- +-- Name: muse_flow_version; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_flow_version ( + run_purpose public.muse_purpose NOT NULL, + flow_id text NOT NULL, + version text NOT NULL, + definition jsonb NOT NULL, + definition_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE evaluation.muse_flow_version OWNER TO muse_maint; + +-- +-- Name: muse_model_delivery; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_model_delivery ( + call_id text NOT NULL, + task_id uuid NOT NULL, + attempt_id uuid NOT NULL, + response_evidence_id uuid NOT NULL, + response_hash text NOT NULL, + confirmed_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_model_delivery_response_hash_check CHECK ((response_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_model_delivery OWNER TO muse_maint; + +-- +-- Name: muse_raw_archive; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_raw_archive ( + archive_id uuid NOT NULL, + lease_id uuid, + legacy_ref text, + legacy_manifest jsonb, + authorization_id uuid NOT NULL, + tree_hash text NOT NULL, + entry_count integer NOT NULL, + total_bytes bigint NOT NULL, + receipt_id uuid NOT NULL, + created_at timestamp with time zone NOT NULL, + CONSTRAINT muse_raw_archive_check CHECK (((lease_id IS NULL) <> (legacy_ref IS NULL))), + CONSTRAINT muse_raw_archive_entry_count_check CHECK ((entry_count > 0)), + CONSTRAINT muse_raw_archive_total_bytes_check CHECK ((total_bytes >= 0)) +); + + +ALTER TABLE evaluation.muse_raw_archive OWNER TO muse_maint; + +-- +-- Name: muse_raw_archive_item; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_raw_archive_item ( + archive_id uuid NOT NULL, + content_hash text NOT NULL, + content bytea NOT NULL +); + + +ALTER TABLE evaluation.muse_raw_archive_item OWNER TO muse_maint; + +-- +-- Name: muse_raw_authorization; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_raw_authorization ( + authorization_id uuid NOT NULL, + task_id uuid NOT NULL, + command_id text NOT NULL, + approved_by text NOT NULL, + source_version text NOT NULL, + content_hashes text[] NOT NULL, + purpose text NOT NULL, + retention_mode text NOT NULL, + approved_at timestamp with time zone NOT NULL, + valid_until timestamp with time zone NOT NULL, + request_hash text NOT NULL, + revoked boolean DEFAULT false NOT NULL, + call_id text, + call_request_hash text, + response_hash text, + parent_authorization_id uuid, + attempt_id uuid, + derivation_kind text, + evidence_refs uuid[] DEFAULT '{}'::uuid[] NOT NULL, + CONSTRAINT muse_raw_authorization_check CHECK (((call_id IS NULL) = (call_request_hash IS NULL))), + CONSTRAINT muse_raw_authorization_check1 CHECK (((response_hash IS NULL) OR (call_id IS NOT NULL))), + CONSTRAINT muse_raw_authorization_content_hashes_check CHECK ((cardinality(content_hashes) > 0)), + CONSTRAINT muse_raw_authorization_derivation_kind_check CHECK ((derivation_kind = ANY (ARRAY['model'::text, 'tool'::text]))), + CONSTRAINT muse_raw_authorization_retention_mode_check CHECK ((retention_mode = ANY (ARRAY['temporary'::text, 'archive'::text, 'persistent'::text]))) +); + + +ALTER TABLE evaluation.muse_raw_authorization OWNER TO muse_maint; + +-- +-- Name: muse_raw_lease; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_raw_lease ( + lease_id uuid NOT NULL, + task_id uuid NOT NULL, + authorization_id uuid NOT NULL, + command_id text NOT NULL, + created_at timestamp with time zone NOT NULL, + retain_until timestamp with time zone NOT NULL, + state text NOT NULL, + archive_id uuid, + archive_authorization_id uuid, + cleanup_receipt uuid, + failure_code text, + CONSTRAINT muse_raw_lease_check CHECK (((retain_until > created_at) AND (retain_until <= (created_at + '24:00:00'::interval)))), + CONSTRAINT muse_raw_lease_state_check CHECK ((state = ANY (ARRAY['open'::text, 'closed'::text, 'migrating'::text, 'migrated'::text]))) +); + + +ALTER TABLE evaluation.muse_raw_lease OWNER TO muse_maint; + +-- +-- Name: muse_raw_namespace; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_raw_namespace ( + singleton boolean DEFAULT true NOT NULL, + namespace_id uuid DEFAULT gen_random_uuid() NOT NULL, + CONSTRAINT muse_raw_namespace_singleton_check CHECK (singleton) +); + + +ALTER TABLE evaluation.muse_raw_namespace OWNER TO muse_maint; + +-- +-- Name: muse_raw_orphan_cleanup; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_raw_orphan_cleanup ( + run_purpose public.muse_purpose NOT NULL, + object_id uuid NOT NULL, + receipt_id uuid DEFAULT gen_random_uuid() NOT NULL, + state text NOT NULL, + removed boolean, + completed_at timestamp with time zone, + CONSTRAINT muse_raw_orphan_cleanup_state_check CHECK ((state = ANY (ARRAY['pending'::text, 'completed'::text]))) +); + + +ALTER TABLE evaluation.muse_raw_orphan_cleanup OWNER TO muse_maint; + +-- +-- Name: muse_role_session_authorization; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_role_session_authorization ( + authorization_id uuid NOT NULL, + 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, + max_tool_calls integer NOT NULL, + policy_hash text NOT NULL, + CONSTRAINT muse_role_session_authorization_max_model_calls_check CHECK ((max_model_calls > 0)), + CONSTRAINT muse_role_session_authorization_max_tool_calls_check CHECK ((max_tool_calls >= 0)) +); + + +ALTER TABLE evaluation.muse_role_session_authorization OWNER TO muse_maint; + +-- +-- Name: muse_rule_diagnostic_assessment; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_rule_diagnostic_assessment ( + run_id uuid NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_rule_diagnostic_assessment_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_rule_diagnostic_assessment_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_rule_diagnostic_assessment OWNER TO muse_maint; + +-- +-- Name: muse_rule_diagnostic_result; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_rule_diagnostic_result ( + run_id uuid NOT NULL, + sample_id text NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_rule_diagnostic_result_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_rule_diagnostic_result_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE evaluation.muse_rule_diagnostic_result OWNER TO muse_maint; + +-- +-- Name: muse_rule_diagnostic_run; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_rule_diagnostic_run ( + run_id uuid NOT NULL, + author_id text NOT NULL, + dataset_version_id uuid NOT NULL, + target jsonb NOT NULL, + policy jsonb NOT NULL, + policy_hash text NOT NULL, + plan_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_rule_diagnostic_run_plan_hash_check CHECK ((plan_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_rule_diagnostic_run_policy_check CHECK ((jsonb_typeof(policy) = 'object'::text)), + CONSTRAINT muse_rule_diagnostic_run_policy_hash_check CHECK ((policy_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_rule_diagnostic_run_target_check CHECK ((jsonb_typeof(target) = 'object'::text)) +); + + +ALTER TABLE evaluation.muse_rule_diagnostic_run OWNER TO muse_maint; + +-- +-- Name: muse_rule_diagnostic_stop; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_rule_diagnostic_stop ( + run_id uuid NOT NULL, + author_id text NOT NULL, + command_id text NOT NULL, + stopped_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE evaluation.muse_rule_diagnostic_stop OWNER TO muse_maint; + +-- +-- Name: muse_runtime_config_active; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_runtime_config_active ( + run_purpose public.muse_purpose NOT NULL, + config_id text NOT NULL, + version text, + validation_receipt uuid, + approval_ref text, + generation bigint DEFAULT 0 NOT NULL +); + + +ALTER TABLE evaluation.muse_runtime_config_active OWNER TO muse_maint; + +-- +-- Name: muse_runtime_config_validation; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_runtime_config_validation ( + receipt_id uuid NOT NULL, + 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 timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE evaluation.muse_runtime_config_validation OWNER TO muse_maint; + +-- +-- Name: muse_runtime_config_version; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.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 timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE evaluation.muse_runtime_config_version OWNER TO muse_maint; + +-- +-- Name: muse_runtime_evidence; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_runtime_evidence ( + evidence_id uuid NOT NULL, + task_id uuid NOT NULL, + attempt_id uuid NOT NULL, + kind text NOT NULL, + reference_id text NOT NULL, + content_hash text NOT NULL, + content bytea, + authorization_id uuid, + outcome text NOT NULL, + metadata jsonb NOT NULL, + revision integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_runtime_evidence_check CHECK (((content IS NULL) OR (authorization_id IS NOT NULL))), + CONSTRAINT muse_runtime_evidence_kind_check CHECK ((kind = ANY (ARRAY['model_input'::text, 'model_response'::text, 'model_dispatch'::text, 'tool_result'::text, 'failure'::text]))), + CONSTRAINT muse_runtime_evidence_outcome_check CHECK ((outcome = ANY (ARRAY['completed'::text, 'failed'::text, 'partial'::text]))) +); + + +ALTER TABLE evaluation.muse_runtime_evidence OWNER TO muse_maint; + +-- +-- Name: muse_step; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_step ( + task_id uuid NOT NULL, + step_id text NOT NULL, + processor_id text NOT NULL, + processor_version text NOT NULL, + dependencies text[] NOT NULL, + state text NOT NULL, + current_attempt uuid, + checkpoint jsonb DEFAULT '{}'::jsonb NOT NULL, + result jsonb, + CONSTRAINT muse_step_state_check CHECK ((state = ANY (ARRAY['pending'::text, 'running'::text, 'completed'::text, 'failed'::text, 'unknown'::text]))) +); + + +ALTER TABLE evaluation.muse_step OWNER TO muse_maint; + +-- +-- Name: muse_task; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_task ( + task_id uuid NOT NULL, + 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, + scope_key text, + scope_generation bigint, + last_sequence bigint DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + updated_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + accounting_revision bigint DEFAULT 0 NOT NULL, + CONSTRAINT muse_task_state_check CHECK ((state = ANY (ARRAY['queued'::text, 'running'::text, 'paused'::text, 'reconciling'::text, 'failed'::text, 'cancelled'::text, 'completed'::text]))) +); + + +ALTER TABLE evaluation.muse_task OWNER TO muse_maint; + +-- +-- Name: muse_task_budget; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_task_budget ( + task_id uuid NOT NULL, + account_id text NOT NULL, + plan jsonb NOT NULL, + plan_hash text NOT NULL, + stopped boolean DEFAULT false NOT NULL +); + + +ALTER TABLE evaluation.muse_task_budget OWNER TO muse_maint; + +-- +-- Name: muse_task_config_binding; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_task_config_binding ( + task_id uuid NOT NULL, + config_id text NOT NULL, + version text NOT NULL, + content_hash text NOT NULL, + content jsonb NOT NULL, + validation_receipt uuid NOT NULL +); + + +ALTER TABLE evaluation.muse_task_config_binding OWNER TO muse_maint; + +-- +-- Name: muse_task_control; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.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, + request_hash text NOT NULL, + receipt jsonb +); + + +ALTER TABLE evaluation.muse_task_control OWNER TO muse_maint; + +-- +-- Name: muse_task_event; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_task_event ( + event_id uuid NOT NULL, + task_id uuid NOT NULL, + step_id text, + attempt_id uuid, + sequence bigint NOT NULL, + event_type text NOT NULL, + occurred_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + payload_version integer NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL +); + + +ALTER TABLE evaluation.muse_task_event OWNER TO muse_maint; + +-- +-- Name: muse_task_inventory; Type: VIEW; Schema: evaluation; Owner: muse_maint +-- + +CREATE VIEW evaluation.muse_task_inventory WITH (security_barrier='true') AS + SELECT author_id, + run_purpose, + state, + count(*) AS task_count + FROM evaluation.muse_task + GROUP BY author_id, run_purpose, state; + + +ALTER VIEW evaluation.muse_task_inventory OWNER TO muse_maint; + +-- +-- Name: muse_task_scope_lease; Type: TABLE; Schema: evaluation; Owner: muse_maint +-- + +CREATE TABLE evaluation.muse_task_scope_lease ( + run_purpose public.muse_purpose NOT NULL, + scope_key text NOT NULL, + holder_task_id uuid, + generation bigint NOT NULL, + lease_until timestamp with time zone NOT NULL, + CONSTRAINT muse_task_scope_lease_generation_check CHECK ((generation > 0)) +); + + +ALTER TABLE evaluation.muse_task_scope_lease OWNER TO muse_maint; + +-- +-- Name: activation_receipt; Type: TABLE; Schema: metadata; Owner: muse_maint +-- + +CREATE TABLE metadata.activation_receipt ( + command_id text NOT NULL, + request_hash text NOT NULL, + result jsonb NOT NULL, + reviewed_by text NOT NULL, + change_scope text NOT NULL, + created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL +); + + +ALTER TABLE metadata.activation_receipt OWNER TO muse_maint; + +-- +-- Name: policy_version; Type: TABLE; Schema: metadata; Owner: muse_maint +-- + +CREATE TABLE metadata.policy_version ( + type_id text NOT NULL, + version bigint NOT NULL, + definition jsonb NOT NULL, + content_hash text NOT NULL, + CONSTRAINT policy_version_version_check CHECK ((version > 0)) +); + + +ALTER TABLE metadata.policy_version OWNER TO muse_maint; + +-- +-- Name: schema_binding; Type: TABLE; Schema: metadata; Owner: muse_maint +-- + +CREATE TABLE metadata.schema_binding ( + target_ref text NOT NULL, + work_id text NOT NULL, + type_id text NOT NULL, + schema_id text NOT NULL, + base_version bigint NOT NULL, + extension_version bigint, + effective_schema_hash text NOT NULL, + revision bigint NOT NULL, + CONSTRAINT schema_binding_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE metadata.schema_binding OWNER TO muse_maint; + +-- +-- Name: schema_version; Type: TABLE; Schema: metadata; Owner: muse_maint +-- + +CREATE TABLE metadata.schema_version ( + schema_id text NOT NULL, + schema_version bigint NOT NULL, + type_id text NOT NULL, + definition jsonb NOT NULL, + content_hash text NOT NULL, + state text NOT NULL, + CONSTRAINT schema_version_schema_version_check CHECK ((schema_version > 0)), + CONSTRAINT schema_version_state_check CHECK ((state = ANY (ARRAY['candidate'::text, 'published'::text]))) +); + + +ALTER TABLE metadata.schema_version OWNER TO muse_maint; + +-- +-- Name: type_registry; Type: TABLE; Schema: metadata; Owner: muse_maint +-- + +CREATE TABLE metadata.type_registry ( + type_id text NOT NULL, + definition jsonb NOT NULL, + content_hash text NOT NULL, + state text DEFAULT 'candidate'::text NOT NULL, + policy_revision bigint DEFAULT 0 NOT NULL, + CONSTRAINT type_registry_policy_revision_check CHECK ((policy_revision >= 0)), + CONSTRAINT type_registry_state_check CHECK ((state = ANY (ARRAY['candidate'::text, 'published'::text]))) +); + + +ALTER TABLE metadata.type_registry OWNER TO muse_maint; + +-- +-- Name: work_extension; Type: TABLE; Schema: metadata; Owner: muse_maint +-- + +CREATE TABLE metadata.work_extension ( + work_id text NOT NULL, + schema_id text NOT NULL, + base_version bigint NOT NULL, + extension_version bigint NOT NULL, + definition jsonb NOT NULL, + content_hash text NOT NULL, + state text NOT NULL, + CONSTRAINT work_extension_extension_version_check CHECK ((extension_version > 0)), + CONSTRAINT work_extension_state_check CHECK ((state = ANY (ARRAY['candidate'::text, 'published'::text]))) +); + + +ALTER TABLE metadata.work_extension OWNER TO muse_maint; + +-- +-- Name: muse_blind_assignment; Type: TABLE; Schema: oracle; Owner: muse_maint +-- + +CREATE TABLE oracle.muse_blind_assignment ( + assignment_id uuid NOT NULL, + experiment_id uuid NOT NULL, + sample_id text NOT NULL, + arm_order jsonb NOT NULL, + CONSTRAINT muse_blind_assignment_arm_order_check CHECK ((jsonb_typeof(arm_order) = 'array'::text)) +); + + +ALTER TABLE oracle.muse_blind_assignment OWNER TO muse_maint; + +-- +-- Name: muse_calibration_gold; Type: TABLE; Schema: oracle; Owner: muse_maint +-- + +CREATE TABLE oracle.muse_calibration_gold ( + experiment_id uuid NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_calibration_gold_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_calibration_gold_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE oracle.muse_calibration_gold OWNER TO muse_maint; + +-- +-- Name: muse_dataset_answers; Type: TABLE; Schema: oracle; Owner: muse_maint +-- + +CREATE TABLE oracle.muse_dataset_answers ( + version_id uuid NOT NULL, + answers jsonb NOT NULL, + answer_hash text NOT NULL, + CONSTRAINT muse_dataset_answers_answer_hash_check CHECK ((answer_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_dataset_answers_answers_check CHECK ((jsonb_typeof(answers) = 'array'::text)) +); + + +ALTER TABLE oracle.muse_dataset_answers OWNER TO muse_maint; + +-- +-- Name: muse_attempt; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_attempt ( + attempt_id uuid NOT NULL, + task_id uuid NOT NULL, + step_id text NOT NULL, + worker_id text NOT NULL, + lease_token uuid NOT NULL, + lease_until timestamp with time zone NOT NULL, + scope_generation bigint, + heartbeat_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + state text NOT NULL, + call_state text DEFAULT 'not_sent'::text NOT NULL, + call_reference text, + result jsonb, + failure_code text, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_attempt_call_state_check CHECK ((call_state = ANY (ARRAY['not_sent'::text, 'sent'::text, 'unknown'::text, 'saved'::text]))), + CONSTRAINT muse_attempt_state_check CHECK ((state = ANY (ARRAY['running'::text, 'expired'::text, 'paused'::text, 'cancelled'::text, 'completed'::text, 'failed'::text, 'unknown'::text]))) +); + + +ALTER TABLE public.muse_attempt OWNER TO muse_maint; + +-- +-- Name: muse_author_feedback; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_author_feedback ( + feedback_id uuid NOT NULL, + author_id text NOT NULL, + command_id text NOT NULL, + payload jsonb NOT NULL, + content_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_author_feedback_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_author_feedback OWNER TO muse_maint; + +-- +-- Name: muse_author_observation; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_author_observation ( + observation_id uuid NOT NULL, + author_id text NOT NULL, + command_id text NOT NULL, + feedback_ids uuid[] NOT NULL, + improvement_id uuid, + improvement_revision integer, + payload jsonb NOT NULL, + content_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_author_observation_check CHECK (((improvement_id IS NULL) = (improvement_revision IS NULL))), + CONSTRAINT muse_author_observation_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_author_observation_feedback_ids_check CHECK ((cardinality(feedback_ids) > 0)) +); + + +ALTER TABLE public.muse_author_observation OWNER TO muse_maint; + +-- +-- Name: muse_author_review; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_author_review ( + review_id uuid NOT NULL, + author_id text NOT NULL, + entry_id text NOT NULL, + target_ref text NOT NULL, + content_hash text NOT NULL, + snapshot jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE public.muse_author_review OWNER TO muse_maint; + +-- +-- Name: muse_branch_merge_source; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_branch_merge_source ( + candidate_id uuid NOT NULL, + candidate_revision bigint NOT NULL, + source_document_id uuid NOT NULL, + source_revision bigint NOT NULL, + source_hash text NOT NULL, + merge_basis jsonb NOT NULL +); + + +ALTER TABLE public.muse_branch_merge_source OWNER TO muse_maint; + +-- +-- Name: muse_budget_account; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.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 +); + + +ALTER TABLE public.muse_budget_account OWNER TO muse_maint; + +-- +-- Name: muse_budget_reservation; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.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, + attempt_id uuid NOT NULL, + role_id text NOT NULL, + request_hash text NOT NULL, + state text NOT NULL, + reserved_amount numeric(24,6) NOT NULL, + actual_amount numeric(24,6), + window_start timestamp with time zone NOT NULL, + window_end timestamp with time zone NOT NULL, + expires_at timestamp with time zone NOT NULL, + sent_at timestamp with time zone, + receipt_id text, + reason text, + over_budget boolean DEFAULT false NOT NULL, + CONSTRAINT muse_budget_reservation_actual_amount_check CHECK ((actual_amount >= (0)::numeric)), + CONSTRAINT muse_budget_reservation_check CHECK (((state = 'settled'::text) = (actual_amount IS NOT NULL))), + CONSTRAINT muse_budget_reservation_reserved_amount_check CHECK ((reserved_amount >= (0)::numeric)), + CONSTRAINT muse_budget_reservation_state_check CHECK ((state = ANY (ARRAY['reserved'::text, 'in_flight'::text, 'unknown'::text, 'settled'::text, 'released'::text]))) +); + + +ALTER TABLE public.muse_budget_reservation OWNER TO muse_maint; + +-- +-- Name: muse_call_reconciliation; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_call_reconciliation ( + task_id uuid NOT NULL, + command_id text NOT NULL, + request_hash text NOT NULL, + receipt jsonb NOT NULL, + CONSTRAINT muse_call_reconciliation_command_id_check CHECK ((btrim(command_id) <> ''::text)), + CONSTRAINT muse_call_reconciliation_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_call_reconciliation OWNER TO muse_maint; + +-- +-- Name: muse_call_settlement; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_call_settlement ( + task_id uuid NOT NULL, + command_id text NOT NULL, + receipt_id uuid NOT NULL, + request_hash text NOT NULL, + receipt jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_call_settlement_command_id_check CHECK ((btrim(command_id) <> ''::text)), + CONSTRAINT muse_call_settlement_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_call_settlement OWNER TO muse_maint; + +-- +-- Name: muse_candidate_decision; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_candidate_decision ( + candidate_id text NOT NULL, + candidate_revision bigint NOT NULL, + decision text NOT NULL, + author_id text NOT NULL, + review_id uuid NOT NULL, + command_id text NOT NULL, + CONSTRAINT muse_candidate_decision_decision_check CHECK ((decision = ANY (ARRAY['adopt'::text, 'reject'::text, 'defer'::text]))) +); + + +ALTER TABLE public.muse_candidate_decision OWNER TO muse_maint; + +-- +-- Name: muse_change_command; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_change_command ( + author_id text NOT NULL, + run_purpose public.muse_purpose NOT NULL, + command_id text NOT NULL, + request_hash text NOT NULL, + receipt jsonb, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_change_command_run_purpose_check CHECK ((run_purpose = 'production'::public.muse_purpose)) +); + + +ALTER TABLE public.muse_change_command OWNER TO muse_maint; + +-- +-- Name: muse_change_impact; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_change_impact ( + impact_id uuid NOT NULL, + receipt_id uuid NOT NULL, + target_ref text NOT NULL, + reason text NOT NULL, + before_version text NOT NULL, + after_version text NOT NULL, + state text DEFAULT 'pending'::text NOT NULL, + CONSTRAINT muse_change_impact_state_check CHECK ((state = ANY (ARRAY['pending'::text, 'handled'::text]))) +); + + +ALTER TABLE public.muse_change_impact OWNER TO muse_maint; + +-- +-- Name: muse_chapter; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_chapter ( + chapter_id text NOT NULL, + work_id text NOT NULL, + title text NOT NULL, + "position" integer NOT NULL, + CONSTRAINT muse_chapter_position_check CHECK (("position" > 0)) +); + + +ALTER TABLE public.muse_chapter OWNER TO muse_maint; + +-- +-- Name: muse_clean_candidate; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_clean_candidate ( + candidate_id uuid NOT NULL, + source_id uuid NOT NULL, + revision bigint NOT NULL, + removals jsonb NOT NULL, + status text NOT NULL, + cleaned_hash text, + cleaned_text text, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_clean_candidate_check CHECK (((status = 'applied'::text) = ((cleaned_hash IS NOT NULL) AND (cleaned_text IS NOT NULL)))), + CONSTRAINT muse_clean_candidate_removals_check CHECK ((jsonb_typeof(removals) = 'array'::text)), + CONSTRAINT muse_clean_candidate_status_check CHECK ((status = ANY (ARRAY['proposed'::text, 'applied'::text, 'rejected'::text]))) +); + + +ALTER TABLE public.muse_clean_candidate OWNER TO muse_maint; + +-- +-- Name: muse_config_probe_binding; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_config_probe_binding ( + task_id uuid NOT NULL, + config_id text NOT NULL, + version text NOT NULL, + content_hash text NOT NULL, + content jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_config_probe_binding_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_config_probe_binding OWNER TO muse_maint; + +-- +-- Name: muse_context_snapshot; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_context_snapshot ( + snapshot_id uuid NOT NULL, + run_purpose public.muse_purpose NOT NULL, + task_id uuid NOT NULL, + work_id text NOT NULL, + input_hash text NOT NULL, + frozen_scope jsonb NOT NULL, + assembly jsonb NOT NULL, + source_bindings jsonb NOT NULL, + created_by text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_context_snapshot_assembly_check CHECK ((assembly ? ALL (ARRAY['入选'::text, '省略'::text, '字节数'::text, '文本哈希'::text, '文本'::text]))), + CONSTRAINT muse_context_snapshot_source_bindings_check CHECK ((jsonb_typeof(source_bindings) = 'array'::text)) +); + + +ALTER TABLE public.muse_context_snapshot OWNER TO muse_maint; + +-- +-- Name: muse_delivery; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_delivery ( + delivery_id uuid NOT NULL, + author_id text NOT NULL, + work_id text NOT NULL, + revision integer NOT NULL, + manifest jsonb NOT NULL, + manifest_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_delivery_manifest_check CHECK ((jsonb_array_length((manifest -> 'chapters'::text)) > 0)), + CONSTRAINT muse_delivery_manifest_hash_check CHECK ((manifest_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_delivery_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_delivery OWNER TO muse_maint; + +-- +-- Name: muse_delivery_artifact; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_delivery_artifact ( + artifact_id uuid NOT NULL, + delivery_id uuid NOT NULL, + format text NOT NULL, + formatter_version text NOT NULL, + data bytea NOT NULL, + content_hash text NOT NULL, + verification jsonb NOT NULL, + task_id uuid, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_delivery_artifact_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_delivery_artifact_data_check CHECK ((octet_length(data) > 0)), + CONSTRAINT muse_delivery_artifact_format_check CHECK ((format = ANY (ARRAY['txt'::text, 'md'::text, 'docx'::text, 'epub'::text]))) +); + + +ALTER TABLE public.muse_delivery_artifact OWNER TO muse_maint; + +-- +-- Name: muse_delivery_artifact_validation; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_delivery_artifact_validation ( + artifact_id uuid NOT NULL, + validation_version text NOT NULL, + author_id text NOT NULL, + verification jsonb NOT NULL, + audited_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_delivery_artifact_validation_check CHECK ((((verification ->> 'validation_version'::text) = validation_version) IS TRUE)), + CONSTRAINT muse_delivery_artifact_validation_validation_version_check CHECK ((validation_version = 'delivery-validation-v2'::text)), + CONSTRAINT muse_delivery_artifact_validation_verification_check CHECK ((((verification -> 'verified'::text) = 'true'::jsonb) IS TRUE)), + CONSTRAINT muse_delivery_artifact_validation_verification_check1 CHECK (((jsonb_typeof((verification -> 'binding'::text)) = 'object'::text) IS TRUE)) +); + + +ALTER TABLE public.muse_delivery_artifact_validation OWNER TO muse_maint; + +-- +-- Name: muse_diagnosis; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_diagnosis ( + diagnosis_id uuid NOT NULL, + author_id text NOT NULL, + work_id text NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_diagnosis_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_diagnosis_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_diagnosis OWNER TO muse_maint; + +-- +-- Name: muse_directory_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_directory_version ( + work_id text NOT NULL, + revision bigint NOT NULL, + chapters jsonb NOT NULL, + nodes jsonb DEFAULT '[]'::jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_directory_version_revision_check CHECK ((revision >= 0)) +); + + +ALTER TABLE public.muse_directory_version OWNER TO muse_maint; + +-- +-- Name: muse_document; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_document ( + document_id uuid NOT NULL, + chapter_id text NOT NULL, + branch_id text NOT NULL, + current_revision bigint NOT NULL, + CONSTRAINT muse_document_current_revision_check CHECK ((current_revision > 0)) +); + + +ALTER TABLE public.muse_document OWNER TO muse_maint; + +-- +-- Name: muse_document_branch; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_document_branch ( + document_id uuid NOT NULL, + source_document_id uuid NOT NULL, + source_revision bigint NOT NULL, + source_hash text NOT NULL, + author_id text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_document_branch_check CHECK ((document_id <> source_document_id)) +); + + +ALTER TABLE public.muse_document_branch OWNER TO muse_maint; + +-- +-- Name: muse_document_index; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_document_index ( + document_id text NOT NULL, + revision bigint NOT NULL, + document_hash text NOT NULL, + "结构哈希" text NOT NULL, + summary text DEFAULT ''::text NOT NULL, + registered_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_document_index_revision_check CHECK ((revision >= 0)) +); + + +ALTER TABLE public.muse_document_index OWNER TO muse_maint; + +-- +-- Name: muse_document_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_document_version ( + document_id uuid NOT NULL, + revision bigint NOT NULL, + document jsonb NOT NULL, + document_hash text NOT NULL, + visible_text_hash text NOT NULL, + author_id text NOT NULL, + restored_from bigint, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_document_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_document_version OWNER TO muse_maint; + +-- +-- Name: muse_enablement_receipt; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_enablement_receipt ( + receipt_id uuid NOT NULL, + author_id text NOT NULL, + experiment_id uuid NOT NULL, + basis_experiment_ids uuid[] NOT NULL, + effect_receipt_id uuid NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + valid_until timestamp with time zone NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_enablement_receipt_basis_experiment_ids_check CHECK ((cardinality(basis_experiment_ids) > 0)), + CONSTRAINT muse_enablement_receipt_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_enablement_receipt_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_enablement_receipt OWNER TO muse_maint; + +-- +-- Name: muse_enablement_status; Type: VIEW; Schema: public; Owner: muse_maint +-- + +CREATE VIEW public.muse_enablement_status WITH (security_barrier='true') AS + SELECT receipt_id, + author_id, + experiment_id, + basis_experiment_ids, + effect_receipt_id, + payload, + payload_hash, + valid_until, + (EXISTS ( SELECT 1 + FROM evaluation.muse_experiment_stop s + WHERE (s.experiment_id = ANY (r.basis_experiment_ids)))) AS stopped + FROM public.muse_enablement_receipt r; + + +ALTER VIEW public.muse_enablement_status OWNER TO muse_maint; + +-- +-- Name: muse_exploration_selection; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_exploration_selection ( + work_id text NOT NULL, + current_revision bigint NOT NULL, + CONSTRAINT muse_exploration_selection_current_revision_check CHECK ((current_revision > 0)) +); + + +ALTER TABLE public.muse_exploration_selection OWNER TO muse_maint; + +-- +-- Name: muse_exploration_selection_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_exploration_selection_version ( + work_id text NOT NULL, + revision bigint NOT NULL, + snapshot jsonb NOT NULL, + selected_by text NOT NULL, + selected_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_exploration_selection_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_exploration_selection_version OWNER TO muse_maint; + +-- +-- Name: muse_fact_proposal; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_fact_proposal ( + proposal_id uuid NOT NULL, + work_id text NOT NULL, + object_id text NOT NULL, + current_revision bigint NOT NULL, + CONSTRAINT muse_fact_proposal_current_revision_check CHECK ((current_revision > 0)) +); + + +ALTER TABLE public.muse_fact_proposal OWNER TO muse_maint; + +-- +-- Name: muse_fact_proposal_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_fact_proposal_version ( + proposal_id uuid NOT NULL, + revision bigint NOT NULL, + request jsonb NOT NULL, + proposed_content jsonb NOT NULL, + proposal_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_fact_proposal_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_fact_proposal_version OWNER TO muse_maint; + +-- +-- Name: muse_flow_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_flow_version ( + run_purpose public.muse_purpose NOT NULL, + flow_id text NOT NULL, + version text NOT NULL, + definition jsonb NOT NULL, + definition_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE public.muse_flow_version OWNER TO muse_maint; + +-- +-- Name: muse_improvement; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_improvement ( + improvement_id uuid NOT NULL, + author_id text NOT NULL, + current_revision integer NOT NULL, + CONSTRAINT muse_improvement_current_revision_check CHECK ((current_revision > 0)) +); + + +ALTER TABLE public.muse_improvement OWNER TO muse_maint; + +-- +-- Name: muse_improvement_action; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_improvement_action ( + action_id uuid NOT NULL, + author_id text NOT NULL, + command_id text NOT NULL, + improvement_id uuid NOT NULL, + revision integer NOT NULL, + kind text NOT NULL, + payload jsonb NOT NULL, + content_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_improvement_action_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_improvement_action_kind_check CHECK ((kind = ANY (ARRAY['validation'::text, 'enable'::text, 'disable'::text]))) +); + + +ALTER TABLE public.muse_improvement_action OWNER TO muse_maint; + +-- +-- Name: muse_improvement_result; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_improvement_result ( + action_id uuid NOT NULL, + receipt jsonb NOT NULL, + receipt_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_improvement_result_receipt_hash_check CHECK ((receipt_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_improvement_result OWNER TO muse_maint; + +-- +-- Name: muse_improvement_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_improvement_version ( + improvement_id uuid NOT NULL, + revision integer NOT NULL, + payload jsonb NOT NULL, + content_hash text NOT NULL, + feedback_ids uuid[] NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_improvement_version_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_improvement_version_feedback_ids_check CHECK ((cardinality(feedback_ids) > 0)), + CONSTRAINT muse_improvement_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_improvement_version OWNER TO muse_maint; + +-- +-- Name: muse_legacy_import_record; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_legacy_import_record ( + author_id text NOT NULL, + run_purpose public.muse_purpose NOT NULL, + source_key text NOT NULL, + source_hash text NOT NULL, + mapping_hash text NOT NULL, + original jsonb NOT NULL, + command_id text NOT NULL, + route jsonb NOT NULL, + frozen_request jsonb, + state text DEFAULT 'reserved'::text NOT NULL, + reason_code text DEFAULT ''::text NOT NULL, + targets jsonb DEFAULT '[]'::jsonb NOT NULL, + receipt jsonb, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + updated_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_legacy_import_record_check CHECK (((state <> 'mapped'::text) OR ((frozen_request IS NOT NULL) AND (receipt IS NOT NULL) AND (jsonb_array_length(targets) > 0)))), + CONSTRAINT muse_legacy_import_record_check1 CHECK (((state = 'mapped'::text) OR ((receipt IS NULL) AND (targets = '[]'::jsonb)))), + CONSTRAINT muse_legacy_import_record_mapping_hash_check CHECK ((mapping_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_legacy_import_record_original_check CHECK ((jsonb_typeof(original) = 'object'::text)), + CONSTRAINT muse_legacy_import_record_route_check CHECK ((jsonb_typeof(route) = 'object'::text)), + CONSTRAINT muse_legacy_import_record_run_purpose_check CHECK ((run_purpose = 'production'::public.muse_purpose)), + CONSTRAINT muse_legacy_import_record_source_hash_check CHECK ((source_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_legacy_import_record_source_key_check CHECK ((length(source_key) > 0)), + CONSTRAINT muse_legacy_import_record_state_check CHECK ((state = ANY (ARRAY['reserved'::text, 'mapped'::text, 'historical'::text, 'quarantined'::text]))), + CONSTRAINT muse_legacy_import_record_targets_check CHECK ((jsonb_typeof(targets) = 'array'::text)) +); + + +ALTER TABLE public.muse_legacy_import_record OWNER TO muse_maint; + +-- +-- Name: muse_legacy_target; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_legacy_target ( + singleton boolean DEFAULT true NOT NULL, + target_id uuid NOT NULL, + system_identifier text NOT NULL, + data_directory text NOT NULL, + host text NOT NULL, + port integer NOT NULL, + database_name text NOT NULL, + database_oid oid NOT NULL, + role_name text NOT NULL, + run_purpose public.muse_purpose NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_legacy_target_port_check CHECK (((port >= 1) AND (port <= 65535))), + CONSTRAINT muse_legacy_target_role_name_check CHECK ((role_name = 'muse_app'::text)), + CONSTRAINT muse_legacy_target_run_purpose_check CHECK ((run_purpose = 'production'::public.muse_purpose)), + CONSTRAINT muse_legacy_target_singleton_check CHECK (singleton) +); + + +ALTER TABLE public.muse_legacy_target OWNER TO muse_maint; + +-- +-- Name: muse_literary_report; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_literary_report ( + report_id uuid NOT NULL, + task_id uuid NOT NULL, + author_id text NOT NULL, + revision bigint DEFAULT 1 NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_literary_report_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_literary_report_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_literary_report_revision_check CHECK ((revision = 1)) +); + + +ALTER TABLE public.muse_literary_report OWNER TO muse_maint; + +-- +-- Name: muse_literary_shard; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_literary_shard ( + task_id uuid NOT NULL, + shard_id text NOT NULL, + attempt_id uuid NOT NULL, + call_id text NOT NULL, + author_id text NOT NULL, + snapshot_id uuid NOT NULL, + basis_hash text NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + evidence jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_literary_shard_basis_hash_check CHECK ((basis_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_literary_shard_evidence_check CHECK ((jsonb_typeof(evidence) = 'object'::text)), + CONSTRAINT muse_literary_shard_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_literary_shard_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_literary_shard_shard_id_check CHECK ((shard_id ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_literary_shard OWNER TO muse_maint; + +-- +-- Name: muse_method; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method ( + method_id uuid NOT NULL, + owner text NOT NULL, + type_id text NOT NULL, + title text NOT NULL, + state text NOT NULL, + content_hash text NOT NULL, + current_version bigint DEFAULT 0 NOT NULL, + created_by text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + updated_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_method_current_version_check CHECK ((current_version >= 0)), + CONSTRAINT muse_method_state_check CHECK ((state = ANY (ARRAY['proposed'::text, 'confirmed'::text, 'enabled'::text, 'disabled'::text, 'withdrawn'::text]))), + CONSTRAINT muse_method_title_check CHECK ((title <> ''::text)) +); + + +ALTER TABLE public.muse_method OWNER TO muse_maint; + +-- +-- Name: muse_method_binding; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method_binding ( + binding_id uuid NOT NULL, + work_id text NOT NULL, + target_kind text NOT NULL, + target_ref text NOT NULL, + method_id uuid NOT NULL, + version_id uuid NOT NULL, + bound_by text NOT NULL, + bound_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + released_at timestamp with time zone, + CONSTRAINT muse_method_binding_target_kind_check CHECK ((target_kind = ANY (ARRAY['work'::text, 'planning'::text]))), + CONSTRAINT muse_method_binding_target_ref_check CHECK ((target_ref <> ''::text)) +); + + +ALTER TABLE public.muse_method_binding OWNER TO muse_maint; + +-- +-- Name: muse_method_evidence; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method_evidence ( + evidence_id uuid NOT NULL, + method_id uuid NOT NULL, + kind text NOT NULL, + ref jsonb NOT NULL, + note text DEFAULT ''::text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_method_evidence_kind_check CHECK ((kind = ANY (ARRAY['source'::text, 'sample'::text, 'counter'::text, 'exception'::text, 'static_ref'::text]))), + CONSTRAINT muse_method_evidence_ref_check CHECK ((jsonb_typeof(ref) = 'object'::text)) +); + + +ALTER TABLE public.muse_method_evidence OWNER TO muse_maint; + +-- +-- Name: muse_method_index; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method_index ( + method_version_id uuid NOT NULL, + "检索文本" text NOT NULL, + "检索文本哈希" text NOT NULL, + vector double precision[] NOT NULL, + embedder text NOT NULL, + built_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_method_index_vector_check CHECK ((array_length(vector, 1) > 0)) +); + + +ALTER TABLE public.muse_method_index OWNER TO muse_maint; + +-- +-- Name: muse_method_index_guard; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method_index_guard ( + singleton boolean DEFAULT true NOT NULL, + generation bigint DEFAULT 0 NOT NULL, + CONSTRAINT muse_method_index_guard_generation_check CHECK ((generation >= 0)), + CONSTRAINT muse_method_index_guard_singleton_check CHECK (singleton) +); + + +ALTER TABLE public.muse_method_index_guard OWNER TO muse_maint; + +-- +-- Name: muse_method_index_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method_index_version ( + ledger_id bigint NOT NULL, + "索引身份" text NOT NULL, + embedder text NOT NULL, + method_count integer NOT NULL, + built_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + active boolean DEFAULT false NOT NULL, + CONSTRAINT muse_method_index_version_method_count_check CHECK ((method_count >= 0)) +); + + +ALTER TABLE public.muse_method_index_version OWNER TO muse_maint; + +-- +-- Name: muse_method_index_version_ledger_id_seq; Type: SEQUENCE; Schema: public; Owner: muse_maint +-- + +ALTER TABLE public.muse_method_index_version ALTER COLUMN ledger_id ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME public.muse_method_index_version_ledger_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- Name: muse_method_proposal; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method_proposal ( + proposal_id uuid NOT NULL, + method_id uuid NOT NULL, + revision bigint NOT NULL, + request jsonb NOT NULL, + proposal_hash text NOT NULL, + created_by text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_method_proposal_request_check CHECK ((jsonb_typeof(request) = 'object'::text)), + CONSTRAINT muse_method_proposal_revision_check CHECK ((revision >= 1)) +); + + +ALTER TABLE public.muse_method_proposal OWNER TO muse_maint; + +-- +-- Name: muse_method_usage; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method_usage ( + usage_id uuid NOT NULL, + method_version_id uuid NOT NULL, + kind text NOT NULL, + context_ref text NOT NULL, + fragment_hash text NOT NULL, + result_ref text, + task_id uuid, + created_by text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_method_usage_kind_check CHECK ((kind = ANY (ARRAY['generation'::text, 'review'::text, 'planning'::text, 'enablement'::text]))) +); + + +ALTER TABLE public.muse_method_usage OWNER TO muse_maint; + +-- +-- Name: muse_method_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_method_version ( + version_id uuid NOT NULL, + method_id uuid NOT NULL, + version bigint NOT NULL, + content jsonb NOT NULL, + content_hash text NOT NULL, + "参数上限" jsonb NOT NULL, + schema_id text NOT NULL, + schema_version integer NOT NULL, + effective_schema_hash text NOT NULL, + proposal_id uuid, + confirmed_by text NOT NULL, + confirmed_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_method_version_content_check CHECK ((jsonb_typeof(content) = 'object'::text)), + CONSTRAINT muse_method_version_version_check CHECK ((version > 0)), + CONSTRAINT "muse_method_version_参数上限_check" CHECK ((jsonb_typeof("参数上限") = 'object'::text)) +); + + +ALTER TABLE public.muse_method_version OWNER TO muse_maint; + +-- +-- Name: muse_migration; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_migration ( + version integer NOT NULL, + name text NOT NULL, + checksum text NOT NULL, + applied_at timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT muse_migration_checksum_check CHECK ((length(checksum) = 64)), + CONSTRAINT muse_migration_version_check CHECK ((version >= 1)) +); + + +ALTER TABLE public.muse_migration OWNER TO muse_maint; + +-- +-- Name: muse_model_candidate; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_model_candidate ( + candidate_id uuid NOT NULL, + task_id uuid NOT NULL, + snapshot_id uuid NOT NULL, + flow_version text NOT NULL, + processor_versions jsonb NOT NULL, + model_evidence jsonb NOT NULL, + prompt_hashes jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_model_candidate_model_evidence_check CHECK ((jsonb_typeof(model_evidence) = 'array'::text)), + CONSTRAINT muse_model_candidate_processor_versions_check CHECK ((jsonb_typeof(processor_versions) = 'object'::text)), + CONSTRAINT muse_model_candidate_prompt_hashes_check CHECK ((jsonb_typeof(prompt_hashes) = 'object'::text)) +); + + +ALTER TABLE public.muse_model_candidate OWNER TO muse_maint; + +-- +-- Name: muse_model_delivery; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_model_delivery ( + call_id text NOT NULL, + task_id uuid NOT NULL, + attempt_id uuid NOT NULL, + response_evidence_id uuid NOT NULL, + response_hash text NOT NULL, + confirmed_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_model_delivery_response_hash_check CHECK ((response_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_model_delivery OWNER TO muse_maint; + +-- +-- Name: muse_model_plan_candidate; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_model_plan_candidate ( + candidate_id uuid NOT NULL, + task_id uuid NOT NULL, + snapshot_id uuid NOT NULL, + call_id text NOT NULL, + model_evidence jsonb NOT NULL, + prompt_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_model_plan_candidate_model_evidence_check CHECK ((jsonb_typeof(model_evidence) = 'object'::text)) +); + + +ALTER TABLE public.muse_model_plan_candidate OWNER TO muse_maint; + +-- +-- Name: muse_plan; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_plan ( + plan_id text NOT NULL, + work_id text NOT NULL, + type_id text NOT NULL, + chapter_id text, + node_id text, + current_revision bigint NOT NULL, + CONSTRAINT muse_plan_current_revision_check CHECK ((current_revision > 0)) +); + + +ALTER TABLE public.muse_plan OWNER TO muse_maint; + +-- +-- Name: muse_plan_candidate; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_plan_candidate ( + candidate_id uuid NOT NULL, + work_id text NOT NULL, + plan_id text NOT NULL, + current_revision bigint NOT NULL, + CONSTRAINT muse_plan_candidate_current_revision_check CHECK ((current_revision > 0)) +); + + +ALTER TABLE public.muse_plan_candidate OWNER TO muse_maint; + +-- +-- Name: muse_plan_candidate_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_plan_candidate_version ( + candidate_id uuid NOT NULL, + revision bigint NOT NULL, + request jsonb NOT NULL, + content jsonb NOT NULL, + source_dependencies jsonb NOT NULL, + candidate_hash text NOT NULL, + CONSTRAINT muse_plan_candidate_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_plan_candidate_version OWNER TO muse_maint; + +-- +-- Name: muse_plan_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_plan_version ( + plan_id text NOT NULL, + revision bigint NOT NULL, + request jsonb NOT NULL, + content jsonb NOT NULL, + content_hash text NOT NULL, + schema_binding jsonb NOT NULL, + source_dependencies jsonb NOT NULL, + author_id text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_plan_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_plan_version OWNER TO muse_maint; + +-- +-- Name: muse_preference; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_preference ( + preference_id uuid NOT NULL, + author_id text NOT NULL, + current_revision integer NOT NULL, + CONSTRAINT muse_preference_current_revision_check CHECK ((current_revision > 0)) +); + + +ALTER TABLE public.muse_preference OWNER TO muse_maint; + +-- +-- Name: muse_preference_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_preference_version ( + preference_id uuid NOT NULL, + revision integer NOT NULL, + payload jsonb NOT NULL, + content_hash text NOT NULL, + state text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_preference_version_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_preference_version_revision_check CHECK ((revision > 0)), + CONSTRAINT muse_preference_version_state_check CHECK ((state = ANY (ARRAY['pending'::text, 'active'::text, 'withdrawn'::text]))) +); + + +ALTER TABLE public.muse_preference_version OWNER TO muse_maint; + +-- +-- Name: muse_quality_case; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_quality_case ( + case_id uuid NOT NULL, + author_id text NOT NULL, + current_revision bigint NOT NULL, + CONSTRAINT muse_quality_case_current_revision_check CHECK ((current_revision > 0)) +); + + +ALTER TABLE public.muse_quality_case OWNER TO muse_maint; + +-- +-- Name: muse_quality_case_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_quality_case_version ( + case_id uuid NOT NULL, + revision bigint NOT NULL, + state text NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_quality_case_version_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_quality_case_version_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_quality_case_version_revision_check CHECK ((revision > 0)), + CONSTRAINT muse_quality_case_version_state_check CHECK ((state = ANY (ARRAY['shadow'::text, 'confirmed'::text, 'withdrawn'::text]))) +); + + +ALTER TABLE public.muse_quality_case_version OWNER TO muse_maint; + +-- +-- Name: muse_ranking_snapshot; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_ranking_snapshot ( + snapshot_id uuid NOT NULL, + ranking_id text NOT NULL, + captured_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + status text NOT NULL, + failure_reason text, + items jsonb, + CONSTRAINT muse_ranking_snapshot_check CHECK (((status = 'ok'::text) = (items IS NOT NULL))), + CONSTRAINT muse_ranking_snapshot_items_check CHECK (((items IS NULL) OR (jsonb_typeof(items) = 'array'::text))), + CONSTRAINT muse_ranking_snapshot_status_check CHECK ((status = ANY (ARRAY['ok'::text, 'failed'::text]))) +); + + +ALTER TABLE public.muse_ranking_snapshot OWNER TO muse_maint; + +-- +-- Name: muse_ranking_source; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_ranking_source ( + ranking_id text NOT NULL, + name text NOT NULL, + url text NOT NULL, + "采集方式" text NOT NULL +); + + +ALTER TABLE public.muse_ranking_source OWNER TO muse_maint; + +-- +-- Name: muse_raw_archive; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_raw_archive ( + archive_id uuid NOT NULL, + lease_id uuid, + legacy_ref text, + legacy_manifest jsonb, + authorization_id uuid NOT NULL, + tree_hash text NOT NULL, + entry_count integer NOT NULL, + total_bytes bigint NOT NULL, + receipt_id uuid NOT NULL, + created_at timestamp with time zone NOT NULL, + CONSTRAINT muse_raw_archive_check CHECK (((lease_id IS NULL) <> (legacy_ref IS NULL))), + CONSTRAINT muse_raw_archive_entry_count_check CHECK ((entry_count > 0)), + CONSTRAINT muse_raw_archive_total_bytes_check CHECK ((total_bytes >= 0)) +); + + +ALTER TABLE public.muse_raw_archive OWNER TO muse_maint; + +-- +-- Name: muse_raw_archive_item; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_raw_archive_item ( + archive_id uuid NOT NULL, + content_hash text NOT NULL, + content bytea NOT NULL +); + + +ALTER TABLE public.muse_raw_archive_item OWNER TO muse_maint; + +-- +-- Name: muse_raw_authorization; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_raw_authorization ( + authorization_id uuid NOT NULL, + task_id uuid NOT NULL, + command_id text NOT NULL, + approved_by text NOT NULL, + source_version text NOT NULL, + content_hashes text[] NOT NULL, + purpose text NOT NULL, + retention_mode text NOT NULL, + approved_at timestamp with time zone NOT NULL, + valid_until timestamp with time zone NOT NULL, + request_hash text NOT NULL, + revoked boolean DEFAULT false NOT NULL, + call_id text, + call_request_hash text, + response_hash text, + parent_authorization_id uuid, + attempt_id uuid, + derivation_kind text, + evidence_refs uuid[] DEFAULT '{}'::uuid[] NOT NULL, + CONSTRAINT muse_raw_authorization_check CHECK (((call_id IS NULL) = (call_request_hash IS NULL))), + CONSTRAINT muse_raw_authorization_check1 CHECK (((response_hash IS NULL) OR (call_id IS NOT NULL))), + CONSTRAINT muse_raw_authorization_content_hashes_check CHECK ((cardinality(content_hashes) > 0)), + CONSTRAINT muse_raw_authorization_derivation_kind_check CHECK ((derivation_kind = ANY (ARRAY['model'::text, 'tool'::text]))), + CONSTRAINT muse_raw_authorization_retention_mode_check CHECK ((retention_mode = ANY (ARRAY['temporary'::text, 'archive'::text, 'persistent'::text]))) +); + + +ALTER TABLE public.muse_raw_authorization OWNER TO muse_maint; + +-- +-- Name: muse_raw_lease; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_raw_lease ( + lease_id uuid NOT NULL, + task_id uuid NOT NULL, + authorization_id uuid NOT NULL, + command_id text NOT NULL, + created_at timestamp with time zone NOT NULL, + retain_until timestamp with time zone NOT NULL, + state text NOT NULL, + archive_id uuid, + archive_authorization_id uuid, + cleanup_receipt uuid, + failure_code text, + CONSTRAINT muse_raw_lease_check CHECK (((retain_until > created_at) AND (retain_until <= (created_at + '24:00:00'::interval)))), + CONSTRAINT muse_raw_lease_state_check CHECK ((state = ANY (ARRAY['open'::text, 'closed'::text, 'migrating'::text, 'migrated'::text]))) +); + + +ALTER TABLE public.muse_raw_lease OWNER TO muse_maint; + +-- +-- Name: muse_raw_namespace; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_raw_namespace ( + singleton boolean DEFAULT true NOT NULL, + namespace_id uuid DEFAULT gen_random_uuid() NOT NULL, + CONSTRAINT muse_raw_namespace_singleton_check CHECK (singleton) +); + + +ALTER TABLE public.muse_raw_namespace OWNER TO muse_maint; + +-- +-- Name: muse_raw_orphan_cleanup; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_raw_orphan_cleanup ( + run_purpose public.muse_purpose NOT NULL, + object_id uuid NOT NULL, + receipt_id uuid DEFAULT gen_random_uuid() NOT NULL, + state text NOT NULL, + removed boolean, + completed_at timestamp with time zone, + CONSTRAINT muse_raw_orphan_cleanup_state_check CHECK ((state = ANY (ARRAY['pending'::text, 'completed'::text]))) +); + + +ALTER TABLE public.muse_raw_orphan_cleanup OWNER TO muse_maint; + +-- +-- Name: muse_reader_feedback; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_reader_feedback ( + feedback_id uuid NOT NULL, + author_id text NOT NULL, + work_id text NOT NULL, + release_id uuid, + payload jsonb NOT NULL, + content_hash text NOT NULL +); + + +ALTER TABLE public.muse_reader_feedback OWNER TO muse_maint; + +-- +-- Name: muse_release; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_release ( + release_id uuid NOT NULL, + author_id text NOT NULL, + work_id text NOT NULL, + delivery_id uuid NOT NULL, + payload jsonb NOT NULL, + content_hash text NOT NULL +); + + +ALTER TABLE public.muse_release OWNER TO muse_maint; + +-- +-- Name: muse_review_report; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_review_report ( + report_id uuid NOT NULL, + candidate_id uuid NOT NULL, + candidate_revision bigint NOT NULL, + snapshot_id uuid NOT NULL, + basic jsonb NOT NULL, + continuity jsonb NOT NULL, + verdict text NOT NULL, + coverage jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_review_report_basic_check CHECK ((basic ? ALL (ARRAY['checks'::text, 'verdict'::text]))), + CONSTRAINT muse_review_report_candidate_revision_check CHECK ((candidate_revision > 0)), + CONSTRAINT muse_review_report_continuity_check CHECK ((continuity ? ALL (ARRAY['findings'::text, 'coverage'::text]))), + CONSTRAINT muse_review_report_coverage_check CHECK ((jsonb_typeof(coverage) = 'object'::text)), + CONSTRAINT muse_review_report_verdict_check CHECK ((verdict = ANY (ARRAY['passed'::text, 'failed'::text]))) +); + + +ALTER TABLE public.muse_review_report OWNER TO muse_maint; + +-- +-- Name: muse_revision_comparison_receipt; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_revision_comparison_receipt ( + receipt_id uuid NOT NULL, + author_id text NOT NULL, + experiment_id uuid NOT NULL, + session_id uuid NOT NULL, + round_number integer NOT NULL, + candidate_id uuid NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_revision_comparison_receipt_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_revision_comparison_receipt_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_revision_comparison_receipt_round_number_check CHECK (((round_number >= 1) AND (round_number <= 5))) +); + + +ALTER TABLE public.muse_revision_comparison_receipt OWNER TO muse_maint; + +-- +-- Name: muse_revision_comparison_status; Type: VIEW; Schema: public; Owner: muse_maint +-- + +CREATE VIEW public.muse_revision_comparison_status WITH (security_barrier='true') AS + SELECT receipt_id, + author_id, + experiment_id, + session_id, + round_number, + candidate_id, + payload, + payload_hash, + (EXISTS ( SELECT 1 + FROM evaluation.muse_experiment_stop s + WHERE (s.experiment_id = r.experiment_id))) AS stopped + FROM public.muse_revision_comparison_receipt r; + + +ALTER VIEW public.muse_revision_comparison_status OWNER TO muse_maint; + +-- +-- Name: muse_revision_result; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_revision_result ( + task_id uuid NOT NULL, + author_id text NOT NULL, + attempt_id uuid NOT NULL, + call_id text NOT NULL, + diagnosis_id uuid, + candidate_id uuid, + outcome text NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + source_kind text DEFAULT 'diagnosis'::text NOT NULL, + CONSTRAINT muse_revision_result_check CHECK (((outcome = 'candidate'::text) = (candidate_id IS NOT NULL))), + CONSTRAINT muse_revision_result_outcome_check CHECK ((outcome = ANY (ARRAY['candidate'::text, 'original'::text, 'rejected'::text]))), + CONSTRAINT muse_revision_result_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_revision_result_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_revision_result_source_kind_check CHECK ((source_kind = ANY (ARRAY['diagnosis'::text, 'selection'::text]))), + CONSTRAINT revision_source_kind_check CHECK (((source_kind = 'diagnosis'::text) = (diagnosis_id IS NOT NULL))) +); + + +ALTER TABLE public.muse_revision_result OWNER TO muse_maint; + +-- +-- Name: muse_revision_round; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_revision_round ( + session_id uuid NOT NULL, + round_number integer NOT NULL, + task_command_id text NOT NULL, + task_request_hash text NOT NULL, + task_id uuid, + state text NOT NULL, + outcome text, + candidate_id uuid, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + updated_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_revision_round_check CHECK (((task_id IS NULL) = (state = 'preparing'::text))), + CONSTRAINT muse_revision_round_check1 CHECK (((outcome IS NULL) = (state = ANY (ARRAY['preparing'::text, 'running'::text])))), + CONSTRAINT muse_revision_round_check2 CHECK (((outcome = 'candidate'::text) = (candidate_id IS NOT NULL))), + CONSTRAINT muse_revision_round_outcome_check CHECK ((outcome = ANY (ARRAY['candidate'::text, 'original'::text, 'rejected'::text]))), + CONSTRAINT muse_revision_round_round_number_check CHECK (((round_number >= 1) AND (round_number <= 5))), + CONSTRAINT muse_revision_round_state_check CHECK ((state = ANY (ARRAY['preparing'::text, 'running'::text, 'candidate'::text, 'original'::text, 'rejected'::text]))), + CONSTRAINT muse_revision_round_task_request_hash_check CHECK ((task_request_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_revision_round OWNER TO muse_maint; + +-- +-- Name: muse_revision_session; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_revision_session ( + session_id uuid NOT NULL, + author_id text NOT NULL, + create_command_id text NOT NULL, + request_hash text NOT NULL, + work_id text NOT NULL, + chapter_id text NOT NULL, + branch_id text NOT NULL, + original_revision bigint NOT NULL, + original_document_hash text NOT NULL, + source_kind text NOT NULL, + basis_hash text NOT NULL, + "authorization" jsonb NOT NULL, + authorization_hash text NOT NULL, + config_id text NOT NULL, + max_rounds integer NOT NULL, + current_round integer DEFAULT 1 NOT NULL, + state text NOT NULL, + stop_reason text, + stop_detail text, + author_choice text, + selected_candidate_id uuid, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + updated_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_revision_session_author_choice_check CHECK ((author_choice = ANY (ARRAY['original'::text, 'candidate'::text]))), + CONSTRAINT muse_revision_session_authorization_check CHECK ((jsonb_typeof("authorization") = 'object'::text)), + CONSTRAINT muse_revision_session_authorization_hash_check CHECK ((authorization_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_revision_session_basis_hash_check CHECK ((basis_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_revision_session_check CHECK ((current_round <= max_rounds)), + CONSTRAINT muse_revision_session_check1 CHECK (((state = 'closed'::text) = (stop_reason IS NOT NULL))), + CONSTRAINT muse_revision_session_check2 CHECK ((((author_choice IS NULL) AND (selected_candidate_id IS NULL)) OR ((author_choice = 'original'::text) AND (selected_candidate_id IS NULL)) OR ((author_choice = 'candidate'::text) AND (selected_candidate_id IS NOT NULL)))), + CONSTRAINT muse_revision_session_current_round_check CHECK (((current_round >= 1) AND (current_round <= 5))), + CONSTRAINT muse_revision_session_max_rounds_check CHECK (((max_rounds >= 1) AND (max_rounds <= 5))), + CONSTRAINT muse_revision_session_original_document_hash_check CHECK ((original_document_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_revision_session_original_revision_check CHECK ((original_revision > 0)), + CONSTRAINT muse_revision_session_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_revision_session_source_kind_check CHECK ((source_kind = ANY (ARRAY['diagnosis'::text, 'selection'::text]))), + CONSTRAINT muse_revision_session_state_check CHECK ((state = ANY (ARRAY['preparing'::text, 'running'::text, 'awaiting_author'::text, 'closed'::text]))) +); + + +ALTER TABLE public.muse_revision_session OWNER TO muse_maint; + +-- +-- Name: muse_revision_session_action; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_revision_session_action ( + action_id uuid NOT NULL, + session_id uuid NOT NULL, + author_id text NOT NULL, + command_id text NOT NULL, + expected_round integer NOT NULL, + candidate_id uuid NOT NULL, + choice text NOT NULL, + request_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_revision_session_action_choice_check CHECK ((choice = ANY (ARRAY['original'::text, 'candidate'::text, 'retry'::text]))), + CONSTRAINT muse_revision_session_action_expected_round_check CHECK (((expected_round >= 1) AND (expected_round <= 5))), + CONSTRAINT muse_revision_session_action_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_revision_session_action OWNER TO muse_maint; + +-- +-- Name: muse_role_session_authorization; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_role_session_authorization ( + authorization_id uuid NOT NULL, + 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, + max_tool_calls integer NOT NULL, + policy_hash text NOT NULL, + CONSTRAINT muse_role_session_authorization_max_model_calls_check CHECK ((max_model_calls > 0)), + CONSTRAINT muse_role_session_authorization_max_tool_calls_check CHECK ((max_tool_calls >= 0)) +); + + +ALTER TABLE public.muse_role_session_authorization OWNER TO muse_maint; + +-- +-- Name: muse_rule_activation; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_rule_activation ( + author_id text NOT NULL, + rule_id text NOT NULL, + version_id uuid NOT NULL, + evaluation_ref text NOT NULL, + approval_ref text NOT NULL +); + + +ALTER TABLE public.muse_rule_activation OWNER TO muse_maint; + +-- +-- Name: muse_rule_activation_current; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_rule_activation_current ( + author_id text NOT NULL, + rule_id text NOT NULL, + activation_revision bigint NOT NULL, + version_id uuid NOT NULL, + state text NOT NULL, + credential_id uuid, + latest_event_id uuid NOT NULL, + updated_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_rule_activation_current_activation_revision_check CHECK ((activation_revision > 0)), + CONSTRAINT muse_rule_activation_current_state_check CHECK ((state = ANY (ARRAY['active'::text, 'disabled'::text]))) +); + + +ALTER TABLE public.muse_rule_activation_current OWNER TO muse_maint; + +-- +-- Name: muse_rule_activation_event; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_rule_activation_event ( + event_id uuid NOT NULL, + author_id text NOT NULL, + rule_id text NOT NULL, + activation_revision bigint NOT NULL, + version_id uuid NOT NULL, + action text NOT NULL, + credential_id uuid, + candidate_id text NOT NULL, + candidate_hash text NOT NULL, + review_id uuid NOT NULL, + command_id text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_rule_activation_event_action_check CHECK ((action = ANY (ARRAY['enable'::text, 'disable'::text]))), + CONSTRAINT muse_rule_activation_event_activation_revision_check CHECK ((activation_revision > 0)), + CONSTRAINT muse_rule_activation_event_candidate_hash_check CHECK ((candidate_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_rule_activation_event OWNER TO muse_maint; + +-- +-- Name: muse_rule_diagnostic_receipt; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_rule_diagnostic_receipt ( + receipt_id uuid NOT NULL, + author_id text NOT NULL, + run_id uuid NOT NULL, + rule_version_id uuid NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + valid_until timestamp with time zone NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_rule_diagnostic_receipt_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_rule_diagnostic_receipt_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_rule_diagnostic_receipt OWNER TO muse_maint; + +-- +-- Name: muse_rule_diagnostic_status; Type: VIEW; Schema: public; Owner: muse_maint +-- + +CREATE VIEW public.muse_rule_diagnostic_status WITH (security_barrier='true') AS + SELECT receipt_id, + author_id, + run_id, + rule_version_id, + payload, + payload_hash, + valid_until, + (EXISTS ( SELECT 1 + FROM evaluation.muse_rule_diagnostic_stop s + WHERE (s.run_id = r.run_id))) AS stopped + FROM public.muse_rule_diagnostic_receipt r; + + +ALTER VIEW public.muse_rule_diagnostic_status OWNER TO muse_maint; + +-- +-- Name: muse_rule_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_rule_version ( + version_id uuid NOT NULL, + author_id text NOT NULL, + rule_id text NOT NULL, + revision bigint NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_rule_version_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_rule_version_payload_hash_check CHECK ((payload_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_rule_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_rule_version OWNER TO muse_maint; + +-- +-- Name: muse_run_observation; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_run_observation ( + observation_id uuid NOT NULL, + author_id text NOT NULL, + source_ids uuid[] NOT NULL, + source_set_hash text NOT NULL, + phenomenon text NOT NULL, + issue_key text DEFAULT ''::text NOT NULL, + state text DEFAULT 'observation'::text NOT NULL, + request_hash text NOT NULL, + payload jsonb NOT NULL, + content_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_run_observation_author_id_check CHECK ((btrim(author_id) <> ''::text)), + CONSTRAINT muse_run_observation_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_run_observation_phenomenon_check CHECK (((length(btrim(phenomenon)) >= 1) AND (length(btrim(phenomenon)) <= 200))), + CONSTRAINT muse_run_observation_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_run_observation_source_ids_nonempty CHECK (((cardinality(source_ids) > 0) AND (array_position(source_ids, NULL::uuid) IS NULL))), + CONSTRAINT muse_run_observation_source_set_hash_check CHECK ((source_set_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_run_observation_sources_present CHECK ( +CASE + WHEN (jsonb_typeof((payload -> 'sources'::text)) = 'array'::text) THEN ((jsonb_array_length((payload -> 'sources'::text)) > 0) AND (NOT jsonb_path_exists(payload, '$."sources"[*]?((((((((!(exists (@."runtime"."task_id")) || !(exists (@."runtime"."attempt_id"))) || !(exists (@."locator"."content_hash"))) || @."runtime"."task_id".type() != "string") || @."runtime"."attempt_id".type() != "string") || @."locator"."content_hash".type() != "string") || @."runtime"."task_id" == "") || @."runtime"."attempt_id" == "") || @."locator"."content_hash" == "")'::jsonpath))) + ELSE false +END), + CONSTRAINT muse_run_observation_state_check CHECK ((state = 'observation'::text)) +); + + +ALTER TABLE public.muse_run_observation OWNER TO muse_maint; + +-- +-- Name: muse_run_observation_command; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_run_observation_command ( + author_id text NOT NULL, + command_id text NOT NULL, + observation_id uuid NOT NULL, + request_hash text NOT NULL, + CONSTRAINT muse_run_observation_command_command_id_check CHECK ((btrim(command_id) <> ''::text)), + CONSTRAINT muse_run_observation_command_request_hash_check CHECK ((request_hash ~ '^[0-9a-f]{64}$'::text)) +); + + +ALTER TABLE public.muse_run_observation_command OWNER TO muse_maint; + +-- +-- Name: muse_runtime_config_active; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_runtime_config_active ( + run_purpose public.muse_purpose NOT NULL, + config_id text NOT NULL, + version text, + validation_receipt uuid, + approval_ref text, + generation bigint DEFAULT 0 NOT NULL +); + + +ALTER TABLE public.muse_runtime_config_active OWNER TO muse_maint; + +-- +-- Name: muse_runtime_config_validation; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_runtime_config_validation ( + receipt_id uuid NOT NULL, + 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 timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE public.muse_runtime_config_validation OWNER TO muse_maint; + +-- +-- Name: muse_runtime_config_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.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 timestamp with time zone DEFAULT clock_timestamp() NOT NULL +); + + +ALTER TABLE public.muse_runtime_config_version OWNER TO muse_maint; + +-- +-- Name: muse_runtime_evidence; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_runtime_evidence ( + evidence_id uuid NOT NULL, + task_id uuid NOT NULL, + attempt_id uuid NOT NULL, + kind text NOT NULL, + reference_id text NOT NULL, + content_hash text NOT NULL, + content bytea, + authorization_id uuid, + outcome text NOT NULL, + metadata jsonb NOT NULL, + revision integer DEFAULT 1 NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_runtime_evidence_check CHECK (((content IS NULL) OR (authorization_id IS NOT NULL))), + CONSTRAINT muse_runtime_evidence_kind_check CHECK ((kind = ANY (ARRAY['model_input'::text, 'model_response'::text, 'model_dispatch'::text, 'tool_result'::text, 'failure'::text]))), + CONSTRAINT muse_runtime_evidence_outcome_check CHECK ((outcome = ANY (ARRAY['completed'::text, 'failed'::text, 'partial'::text]))) +); + + +ALTER TABLE public.muse_runtime_evidence OWNER TO muse_maint; + +-- +-- Name: muse_serial_plan; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_serial_plan ( + plan_id uuid NOT NULL, + author_id text NOT NULL, + work_id text NOT NULL, + revision integer NOT NULL, + CONSTRAINT muse_serial_plan_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_serial_plan OWNER TO muse_maint; + +-- +-- Name: muse_serial_plan_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_serial_plan_version ( + plan_id uuid NOT NULL, + revision integer NOT NULL, + payload jsonb NOT NULL, + content_hash text NOT NULL, + CONSTRAINT muse_serial_plan_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_serial_plan_version OWNER TO muse_maint; + +-- +-- Name: muse_source; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_source ( + source_id uuid NOT NULL, + kind text NOT NULL, + title text NOT NULL, + origin text NOT NULL, + authorized_uses jsonb DEFAULT '[]'::jsonb NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + authorization_revision bigint DEFAULT 1 NOT NULL, + CONSTRAINT muse_source_authorization_revision_check CHECK ((authorization_revision >= 1)), + CONSTRAINT muse_source_authorized_uses_check CHECK ((jsonb_typeof(authorized_uses) = 'array'::text)), + CONSTRAINT muse_source_kind_check CHECK ((kind = ANY (ARRAY['author_draft'::text, 'reference'::text, 'web'::text, 'note'::text, 'inspiration'::text]))) +); + + +ALTER TABLE public.muse_source OWNER TO muse_maint; + +-- +-- Name: muse_source_analysis; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_source_analysis ( + author_id text NOT NULL, + analysis_id text NOT NULL, + revision bigint DEFAULT 1 NOT NULL, + source_id uuid NOT NULL, + source_revision bigint NOT NULL, + source_content_hash text NOT NULL, + origin text NOT NULL, + payload jsonb NOT NULL, + content_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_source_analysis_content_hash_check CHECK ((content_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_source_analysis_origin_check CHECK ((origin = ANY (ARRAY['model'::text, 'checkpoint_history'::text, 'legacy_import'::text]))), + CONSTRAINT muse_source_analysis_payload_check CHECK ((jsonb_typeof(payload) = 'object'::text)), + CONSTRAINT muse_source_analysis_revision_check CHECK ((revision = 1)), + CONSTRAINT muse_source_analysis_source_content_hash_check CHECK ((source_content_hash ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT muse_source_analysis_source_revision_check CHECK ((source_revision > 0)) +); + + +ALTER TABLE public.muse_source_analysis OWNER TO muse_maint; + +-- +-- Name: muse_source_slice; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_source_slice ( + slice_id uuid NOT NULL, + source_id uuid NOT NULL, + revision bigint NOT NULL, + "起点" integer NOT NULL, + "终点" integer NOT NULL, + "窗计划哈希" text NOT NULL, + "检索文本" text NOT NULL, + "检索文本哈希" text NOT NULL, + built_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_source_slice_check CHECK (("终点" > "起点")), + CONSTRAINT muse_source_slice_revision_check CHECK ((revision > 0)), + CONSTRAINT "muse_source_slice_检索文本哈希_check" CHECK (("检索文本哈希" ~ '^[0-9a-f]{64}$'::text)), + CONSTRAINT "muse_source_slice_起点_check" CHECK (("起点" >= 0)) +); + + +ALTER TABLE public.muse_source_slice OWNER TO muse_maint; + +-- +-- Name: muse_source_slice_guard; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_source_slice_guard ( + singleton boolean DEFAULT true NOT NULL, + generation bigint DEFAULT 0 NOT NULL, + CONSTRAINT muse_source_slice_guard_generation_check CHECK ((generation >= 0)), + CONSTRAINT muse_source_slice_guard_singleton_check CHECK (singleton) +); + + +ALTER TABLE public.muse_source_slice_guard OWNER TO muse_maint; + +-- +-- Name: muse_source_slice_index; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_source_slice_index ( + slice_id uuid NOT NULL, + "检索文本" text NOT NULL, + "检索文本哈希" text NOT NULL, + vector double precision[] NOT NULL, + embedder text NOT NULL, + built_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_source_slice_index_vector_check CHECK ((array_length(vector, 1) > 0)) +); + + +ALTER TABLE public.muse_source_slice_index OWNER TO muse_maint; + +-- +-- Name: muse_source_slice_index_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_source_slice_index_version ( + ledger_id bigint NOT NULL, + "索引身份" text NOT NULL, + embedder text NOT NULL, + slice_count integer NOT NULL, + built_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + active boolean DEFAULT false NOT NULL, + CONSTRAINT muse_source_slice_index_version_slice_count_check CHECK ((slice_count >= 0)) +); + + +ALTER TABLE public.muse_source_slice_index_version OWNER TO muse_maint; + +-- +-- Name: muse_source_slice_index_version_ledger_id_seq; Type: SEQUENCE; Schema: public; Owner: muse_maint +-- + +ALTER TABLE public.muse_source_slice_index_version ALTER COLUMN ledger_id ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME public.muse_source_slice_index_version_ledger_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- Name: muse_source_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_source_version ( + source_id uuid NOT NULL, + revision bigint NOT NULL, + content_hash text NOT NULL, + content text NOT NULL, + import_result jsonb NOT NULL, + imported_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_source_version_import_result_check CHECK ((jsonb_typeof(import_result) = 'object'::text)), + CONSTRAINT muse_source_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_source_version OWNER TO muse_maint; + +-- +-- Name: muse_step; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_step ( + task_id uuid NOT NULL, + step_id text NOT NULL, + processor_id text NOT NULL, + processor_version text NOT NULL, + dependencies text[] NOT NULL, + state text NOT NULL, + current_attempt uuid, + checkpoint jsonb DEFAULT '{}'::jsonb NOT NULL, + result jsonb, + CONSTRAINT muse_step_state_check CHECK ((state = ANY (ARRAY['pending'::text, 'running'::text, 'completed'::text, 'failed'::text, 'unknown'::text]))) +); + + +ALTER TABLE public.muse_step OWNER TO muse_maint; + +-- +-- Name: muse_task; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_task ( + task_id uuid NOT NULL, + 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, + scope_key text, + scope_generation bigint, + last_sequence bigint DEFAULT 0 NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + updated_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + accounting_revision bigint DEFAULT 0 NOT NULL, + CONSTRAINT muse_task_state_check CHECK ((state = ANY (ARRAY['queued'::text, 'running'::text, 'paused'::text, 'reconciling'::text, 'failed'::text, 'cancelled'::text, 'completed'::text]))) +); + + +ALTER TABLE public.muse_task OWNER TO muse_maint; + +-- +-- Name: muse_task_budget; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_task_budget ( + task_id uuid NOT NULL, + account_id text NOT NULL, + plan jsonb NOT NULL, + plan_hash text NOT NULL, + stopped boolean DEFAULT false NOT NULL +); + + +ALTER TABLE public.muse_task_budget OWNER TO muse_maint; + +-- +-- Name: muse_task_config_binding; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_task_config_binding ( + task_id uuid NOT NULL, + config_id text NOT NULL, + version text NOT NULL, + content_hash text NOT NULL, + content jsonb NOT NULL, + validation_receipt uuid NOT NULL +); + + +ALTER TABLE public.muse_task_config_binding OWNER TO muse_maint; + +-- +-- Name: muse_task_control; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.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, + request_hash text NOT NULL, + receipt jsonb +); + + +ALTER TABLE public.muse_task_control OWNER TO muse_maint; + +-- +-- Name: muse_task_event; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_task_event ( + event_id uuid NOT NULL, + task_id uuid NOT NULL, + step_id text, + attempt_id uuid, + sequence bigint NOT NULL, + event_type text NOT NULL, + occurred_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + payload_version integer NOT NULL, + payload jsonb NOT NULL, + payload_hash text NOT NULL +); + + +ALTER TABLE public.muse_task_event OWNER TO muse_maint; + +-- +-- Name: muse_task_inventory; Type: VIEW; Schema: public; Owner: muse_maint +-- + +CREATE VIEW public.muse_task_inventory WITH (security_barrier='true') AS + SELECT author_id, + run_purpose, + state, + count(*) AS task_count + FROM public.muse_task + GROUP BY author_id, run_purpose, state; + + +ALTER VIEW public.muse_task_inventory OWNER TO muse_maint; + +-- +-- Name: muse_task_scope_lease; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_task_scope_lease ( + run_purpose public.muse_purpose NOT NULL, + scope_key text NOT NULL, + holder_task_id uuid, + generation bigint NOT NULL, + lease_until timestamp with time zone NOT NULL, + CONSTRAINT muse_task_scope_lease_generation_check CHECK ((generation > 0)) +); + + +ALTER TABLE public.muse_task_scope_lease OWNER TO muse_maint; + +-- +-- Name: muse_voice_current; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_voice_current ( + work_id text NOT NULL, + version_id uuid NOT NULL +); + + +ALTER TABLE public.muse_voice_current OWNER TO muse_maint; + +-- +-- Name: muse_voice_proposal; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_voice_proposal ( + proposal_id uuid NOT NULL, + author_id text NOT NULL, + work_id text NOT NULL, + revision bigint DEFAULT 1 NOT NULL, + base_revision bigint NOT NULL, + request jsonb NOT NULL, + proposal_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_voice_proposal_base_revision_check CHECK ((base_revision >= 0)), + CONSTRAINT muse_voice_proposal_request_check CHECK ((jsonb_typeof(request) = 'object'::text)), + CONSTRAINT muse_voice_proposal_revision_check CHECK ((revision = 1)) +); + + +ALTER TABLE public.muse_voice_proposal OWNER TO muse_maint; + +-- +-- Name: muse_voice_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_voice_version ( + version_id uuid NOT NULL, + work_id text NOT NULL, + revision bigint NOT NULL, + proposal_id uuid NOT NULL, + content_hash text NOT NULL, + effective_schema_hash text NOT NULL, + projection_version text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_voice_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_voice_version OWNER TO muse_maint; + +-- +-- Name: muse_work; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_work ( + work_id text NOT NULL, + author_id text NOT NULL, + current_revision bigint NOT NULL, + directory_revision bigint DEFAULT 0 NOT NULL, + CONSTRAINT muse_work_current_revision_check CHECK ((current_revision > 0)), + CONSTRAINT muse_work_directory_revision_check CHECK ((directory_revision >= 0)) +); + + +ALTER TABLE public.muse_work OWNER TO muse_maint; + +-- +-- Name: muse_work_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_work_version ( + work_id text NOT NULL, + revision bigint NOT NULL, + content jsonb NOT NULL, + schema_binding jsonb NOT NULL, + content_hash text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_work_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_work_version OWNER TO muse_maint; + +-- +-- Name: muse_world_clock; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_world_clock ( + work_id text NOT NULL, + system_revision bigint NOT NULL, + CONSTRAINT muse_world_clock_system_revision_check CHECK ((system_revision >= 0)) +); + + +ALTER TABLE public.muse_world_clock OWNER TO muse_maint; + +-- +-- Name: muse_world_object; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_world_object ( + object_id text NOT NULL, + work_id text NOT NULL, + type_id text NOT NULL, + instance_family text NOT NULL, + current_revision bigint NOT NULL, + CONSTRAINT muse_world_object_current_revision_check CHECK ((current_revision > 0)), + CONSTRAINT muse_world_object_instance_family_check CHECK ((instance_family = ANY (ARRAY['entity'::text, 'relation'::text]))) +); + + +ALTER TABLE public.muse_world_object OWNER TO muse_maint; + +-- +-- Name: muse_world_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_world_version ( + object_id text NOT NULL, + revision bigint NOT NULL, + system_revision bigint NOT NULL, + content jsonb NOT NULL, + content_hash text NOT NULL, + schema_binding jsonb NOT NULL, + sources jsonb NOT NULL, + independent boolean NOT NULL, + effective_from text, + knowledge_mode text NOT NULL, + known_to jsonb NOT NULL, + reader_visible boolean NOT NULL, + planned_window jsonb, + author_id text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_world_version_knowledge_mode_check CHECK ((knowledge_mode = ANY (ARRAY['fact'::text, 'belief'::text, 'plan'::text, 'setting'::text]))), + CONSTRAINT muse_world_version_revision_check CHECK ((revision > 0)), + CONSTRAINT muse_world_version_system_revision_check CHECK ((system_revision > 0)) +); + + +ALTER TABLE public.muse_world_version OWNER TO muse_maint; + +-- +-- Name: muse_writing_candidate; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_writing_candidate ( + candidate_id uuid NOT NULL, + chapter_id text NOT NULL, + branch_id text NOT NULL, + origin text NOT NULL, + current_revision bigint NOT NULL, + CONSTRAINT muse_writing_candidate_current_revision_check CHECK ((current_revision > 0)), + CONSTRAINT writing_candidate_origin_check CHECK ((origin = ANY (ARRAY['author'::text, 'model'::text]))) +); + + +ALTER TABLE public.muse_writing_candidate OWNER TO muse_maint; + +-- +-- Name: muse_writing_candidate_version; Type: TABLE; Schema: public; Owner: muse_maint +-- + +CREATE TABLE public.muse_writing_candidate_version ( + candidate_id uuid NOT NULL, + revision bigint NOT NULL, + base_revision bigint NOT NULL, + base_hash text NOT NULL, + document jsonb NOT NULL, + document_hash text NOT NULL, + visible_text_hash text NOT NULL, + candidate_hash text NOT NULL, + checks jsonb NOT NULL, + author_id text NOT NULL, + created_at timestamp with time zone DEFAULT clock_timestamp() NOT NULL, + CONSTRAINT muse_writing_candidate_version_base_revision_check CHECK ((base_revision >= 0)), + CONSTRAINT muse_writing_candidate_version_revision_check CHECK ((revision > 0)) +); + + +ALTER TABLE public.muse_writing_candidate_version OWNER TO muse_maint; + +-- +-- Data for Name: muse_attempt; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_budget_account; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_budget_reservation; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_calibration_receipt; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_call_reconciliation; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_call_settlement; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_comparison_rejection; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_config_probe_binding; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_context_snapshot; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_dataset_version; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_effect_assessment; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_evaluation_condition; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_evaluation_output; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_evaluation_reuse; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_evaluation_unit; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_experiment; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_experiment_execution; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_experiment_stop; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_flow_version; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_model_delivery; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_archive; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_archive_item; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_authorization; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_lease; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_namespace; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + +INSERT INTO evaluation.muse_raw_namespace VALUES (true, '4ae9c5ba-7aee-44bc-b6e2-b0db879015fe'); + + +-- +-- Data for Name: muse_raw_orphan_cleanup; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_role_session_authorization; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_diagnostic_assessment; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_diagnostic_result; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_diagnostic_run; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_diagnostic_stop; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_runtime_config_active; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_runtime_config_validation; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_runtime_config_version; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_runtime_evidence; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_step; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_budget; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_config_binding; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_control; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_event; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_scope_lease; Type: TABLE DATA; Schema: evaluation; Owner: muse_maint +-- + + + +-- +-- Data for Name: activation_receipt; Type: TABLE DATA; Schema: metadata; Owner: muse_maint +-- + + + +-- +-- Data for Name: policy_version; Type: TABLE DATA; Schema: metadata; Owner: muse_maint +-- + + + +-- +-- Data for Name: schema_binding; Type: TABLE DATA; Schema: metadata; Owner: muse_maint +-- + + + +-- +-- Data for Name: schema_version; Type: TABLE DATA; Schema: metadata; Owner: muse_maint +-- + + + +-- +-- Data for Name: type_registry; Type: TABLE DATA; Schema: metadata; Owner: muse_maint +-- + + + +-- +-- Data for Name: work_extension; Type: TABLE DATA; Schema: metadata; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_blind_assignment; Type: TABLE DATA; Schema: oracle; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_calibration_gold; Type: TABLE DATA; Schema: oracle; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_dataset_answers; Type: TABLE DATA; Schema: oracle; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_attempt; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_author_feedback; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_author_observation; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_author_review; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_branch_merge_source; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_budget_account; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_budget_reservation; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_call_reconciliation; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_call_settlement; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_candidate_decision; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_change_command; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_change_impact; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_chapter; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_clean_candidate; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_config_probe_binding; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_context_snapshot; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_delivery; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_delivery_artifact; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_delivery_artifact_validation; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_diagnosis; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_directory_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_document; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_document_branch; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_document_index; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_document_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_enablement_receipt; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_exploration_selection; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_exploration_selection_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_fact_proposal; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_fact_proposal_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_flow_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_improvement; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_improvement_action; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_improvement_result; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_improvement_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_legacy_import_record; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_legacy_target; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_literary_report; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_literary_shard; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_method; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_method_binding; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_method_evidence; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_method_index; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_method_index_guard; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + +INSERT INTO public.muse_method_index_guard VALUES (true, 0); + + +-- +-- Data for Name: muse_method_index_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_method_proposal; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_method_usage; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_method_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_migration; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_model_candidate; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_model_delivery; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_model_plan_candidate; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_plan; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_plan_candidate; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_plan_candidate_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_plan_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_preference; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_preference_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_quality_case; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_quality_case_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_ranking_snapshot; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_ranking_source; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_archive; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_archive_item; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_authorization; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_lease; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_raw_namespace; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + +INSERT INTO public.muse_raw_namespace VALUES (true, '6d617698-3e8d-4852-8a56-720810222caa'); + + +-- +-- Data for Name: muse_raw_orphan_cleanup; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_reader_feedback; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_release; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_review_report; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_revision_comparison_receipt; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_revision_result; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_revision_round; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_revision_session; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_revision_session_action; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_role_session_authorization; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_activation; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_activation_current; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_activation_event; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_diagnostic_receipt; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_rule_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_run_observation; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_run_observation_command; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_runtime_config_active; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_runtime_config_validation; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_runtime_config_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_runtime_evidence; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_serial_plan; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_serial_plan_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_source; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_source_analysis; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_source_slice; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_source_slice_guard; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + +INSERT INTO public.muse_source_slice_guard VALUES (true, 0); + + +-- +-- Data for Name: muse_source_slice_index; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_source_slice_index_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_source_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_step; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_budget; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_config_binding; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_control; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_event; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_task_scope_lease; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_voice_current; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_voice_proposal; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_voice_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_work; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_work_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_world_clock; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_world_object; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_world_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_writing_candidate; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Data for Name: muse_writing_candidate_version; Type: TABLE DATA; Schema: public; Owner: muse_maint +-- + + + +-- +-- Name: muse_method_index_version_ledger_id_seq; Type: SEQUENCE SET; Schema: public; Owner: muse_maint +-- + +SELECT pg_catalog.setval('public.muse_method_index_version_ledger_id_seq', 1, false); + + +-- +-- Name: muse_source_slice_index_version_ledger_id_seq; Type: SEQUENCE SET; Schema: public; Owner: muse_maint +-- + +SELECT pg_catalog.setval('public.muse_source_slice_index_version_ledger_id_seq', 1, false); + + +-- +-- Name: muse_attempt muse_attempt_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_attempt + ADD CONSTRAINT muse_attempt_pkey PRIMARY KEY (attempt_id); + + +-- +-- Name: muse_budget_account muse_budget_account_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_budget_account + ADD CONSTRAINT muse_budget_account_pkey PRIMARY KEY (run_purpose, account_id); + + +-- +-- Name: muse_budget_reservation muse_budget_reservation_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_budget_reservation + ADD CONSTRAINT muse_budget_reservation_pkey PRIMARY KEY (run_purpose, call_id); + + +-- +-- Name: muse_calibration_receipt muse_calibration_receipt_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_calibration_receipt + ADD CONSTRAINT muse_calibration_receipt_pkey PRIMARY KEY (experiment_id); + + +-- +-- Name: muse_calibration_receipt muse_calibration_receipt_receipt_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_calibration_receipt + ADD CONSTRAINT muse_calibration_receipt_receipt_id_key UNIQUE (receipt_id); + + +-- +-- Name: muse_call_reconciliation muse_call_reconciliation_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_call_reconciliation + ADD CONSTRAINT muse_call_reconciliation_pkey PRIMARY KEY (task_id, command_id); + + +-- +-- Name: muse_call_settlement muse_call_settlement_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_call_settlement + ADD CONSTRAINT muse_call_settlement_pkey PRIMARY KEY (task_id, command_id); + + +-- +-- Name: muse_call_settlement muse_call_settlement_receipt_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_call_settlement + ADD CONSTRAINT muse_call_settlement_receipt_id_key UNIQUE (receipt_id); + + +-- +-- Name: muse_comparison_rejection muse_comparison_rejection_call_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_comparison_rejection + ADD CONSTRAINT muse_comparison_rejection_call_id_key UNIQUE (call_id); + + +-- +-- Name: muse_comparison_rejection muse_comparison_rejection_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_comparison_rejection + ADD CONSTRAINT muse_comparison_rejection_pkey PRIMARY KEY (unit_id, sequence); + + +-- +-- Name: muse_config_probe_binding muse_config_probe_binding_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_config_probe_binding + ADD CONSTRAINT muse_config_probe_binding_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_context_snapshot muse_context_snapshot_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_context_snapshot + ADD CONSTRAINT muse_context_snapshot_pkey PRIMARY KEY (snapshot_id); + + +-- +-- Name: muse_context_snapshot muse_context_snapshot_run_purpose_task_id_input_hash_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_context_snapshot + ADD CONSTRAINT muse_context_snapshot_run_purpose_task_id_input_hash_key UNIQUE (run_purpose, task_id, input_hash); + + +-- +-- Name: muse_dataset_version muse_dataset_version_dataset_id_revision_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_dataset_version + ADD CONSTRAINT muse_dataset_version_dataset_id_revision_key UNIQUE (dataset_id, revision); + + +-- +-- Name: muse_dataset_version muse_dataset_version_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_dataset_version + ADD CONSTRAINT muse_dataset_version_pkey PRIMARY KEY (version_id); + + +-- +-- Name: muse_effect_assessment muse_effect_assessment_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_effect_assessment + ADD CONSTRAINT muse_effect_assessment_pkey PRIMARY KEY (experiment_id); + + +-- +-- Name: muse_effect_assessment muse_effect_assessment_receipt_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_effect_assessment + ADD CONSTRAINT muse_effect_assessment_receipt_id_key UNIQUE (receipt_id); + + +-- +-- Name: muse_evaluation_condition muse_evaluation_condition_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_condition + ADD CONSTRAINT muse_evaluation_condition_pkey PRIMARY KEY (unit_id); + + +-- +-- Name: muse_evaluation_output muse_evaluation_output_call_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_output + ADD CONSTRAINT muse_evaluation_output_call_id_key UNIQUE (call_id); + + +-- +-- Name: muse_evaluation_output muse_evaluation_output_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_output + ADD CONSTRAINT muse_evaluation_output_pkey PRIMARY KEY (unit_id); + + +-- +-- Name: muse_evaluation_reuse muse_evaluation_reuse_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_reuse + ADD CONSTRAINT muse_evaluation_reuse_pkey PRIMARY KEY (unit_id); + + +-- +-- Name: muse_evaluation_unit muse_evaluation_unit_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_unit + ADD CONSTRAINT muse_evaluation_unit_pkey PRIMARY KEY (unit_id); + + +-- +-- Name: muse_evaluation_unit muse_evaluation_unit_task_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_unit + ADD CONSTRAINT muse_evaluation_unit_task_id_key UNIQUE (task_id); + + +-- +-- Name: muse_experiment muse_experiment_author_id_command_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_experiment + ADD CONSTRAINT muse_experiment_author_id_command_id_key UNIQUE (author_id, command_id); + + +-- +-- Name: muse_experiment_execution muse_experiment_execution_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_experiment_execution + ADD CONSTRAINT muse_experiment_execution_pkey PRIMARY KEY (experiment_id); + + +-- +-- Name: muse_experiment muse_experiment_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_experiment + ADD CONSTRAINT muse_experiment_pkey PRIMARY KEY (experiment_id); + + +-- +-- Name: muse_experiment_stop muse_experiment_stop_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_experiment_stop + ADD CONSTRAINT muse_experiment_stop_pkey PRIMARY KEY (experiment_id); + + +-- +-- Name: muse_flow_version muse_flow_version_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_flow_version + ADD CONSTRAINT muse_flow_version_pkey PRIMARY KEY (run_purpose, flow_id, version); + + +-- +-- Name: muse_model_delivery muse_model_delivery_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_model_delivery + ADD CONSTRAINT muse_model_delivery_pkey PRIMARY KEY (call_id); + + +-- +-- Name: muse_raw_archive_item muse_raw_archive_item_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_archive_item + ADD CONSTRAINT muse_raw_archive_item_pkey PRIMARY KEY (archive_id, content_hash); + + +-- +-- Name: muse_raw_archive muse_raw_archive_lease_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_lease_id_key UNIQUE (lease_id); + + +-- +-- Name: muse_raw_archive muse_raw_archive_legacy_ref_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_legacy_ref_key UNIQUE (legacy_ref); + + +-- +-- Name: muse_raw_archive muse_raw_archive_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_pkey PRIMARY KEY (archive_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_pkey PRIMARY KEY (authorization_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_task_id_command_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_task_id_command_id_key UNIQUE (task_id, command_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_pkey PRIMARY KEY (lease_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_task_id_command_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_task_id_command_id_key UNIQUE (task_id, command_id); + + +-- +-- Name: muse_raw_namespace muse_raw_namespace_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_namespace + ADD CONSTRAINT muse_raw_namespace_pkey PRIMARY KEY (singleton); + + +-- +-- Name: muse_raw_orphan_cleanup muse_raw_orphan_cleanup_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_orphan_cleanup + ADD CONSTRAINT muse_raw_orphan_cleanup_pkey PRIMARY KEY (run_purpose, object_id); + + +-- +-- Name: muse_role_session_authorization muse_role_session_authorization_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_role_session_authorization + ADD CONSTRAINT muse_role_session_authorization_pkey PRIMARY KEY (authorization_id); + + +-- +-- Name: muse_rule_diagnostic_assessment muse_rule_diagnostic_assessment_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_assessment + ADD CONSTRAINT muse_rule_diagnostic_assessment_pkey PRIMARY KEY (run_id); + + +-- +-- Name: muse_rule_diagnostic_result muse_rule_diagnostic_result_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_result + ADD CONSTRAINT muse_rule_diagnostic_result_pkey PRIMARY KEY (run_id, sample_id); + + +-- +-- Name: muse_rule_diagnostic_run muse_rule_diagnostic_run_author_id_dataset_version_id_polic_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_run + ADD CONSTRAINT muse_rule_diagnostic_run_author_id_dataset_version_id_polic_key UNIQUE (author_id, dataset_version_id, policy_hash); + + +-- +-- Name: muse_rule_diagnostic_run muse_rule_diagnostic_run_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_run + ADD CONSTRAINT muse_rule_diagnostic_run_pkey PRIMARY KEY (run_id); + + +-- +-- Name: muse_rule_diagnostic_stop muse_rule_diagnostic_stop_author_id_command_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_stop + ADD CONSTRAINT muse_rule_diagnostic_stop_author_id_command_id_key UNIQUE (author_id, command_id); + + +-- +-- Name: muse_rule_diagnostic_stop muse_rule_diagnostic_stop_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_stop + ADD CONSTRAINT muse_rule_diagnostic_stop_pkey PRIMARY KEY (run_id); + + +-- +-- Name: muse_runtime_config_active muse_runtime_config_active_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_config_active + ADD CONSTRAINT muse_runtime_config_active_pkey PRIMARY KEY (run_purpose, config_id); + + +-- +-- Name: muse_runtime_config_validation muse_runtime_config_validation_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_config_validation + ADD CONSTRAINT muse_runtime_config_validation_pkey PRIMARY KEY (receipt_id); + + +-- +-- Name: muse_runtime_config_version muse_runtime_config_version_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_config_version + ADD CONSTRAINT muse_runtime_config_version_pkey PRIMARY KEY (run_purpose, config_id, version); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_attempt_id_kind_reference_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_attempt_id_kind_reference_id_key UNIQUE (attempt_id, kind, reference_id); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_pkey PRIMARY KEY (evidence_id); + + +-- +-- Name: muse_step muse_step_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_step + ADD CONSTRAINT muse_step_pkey PRIMARY KEY (task_id, step_id); + + +-- +-- Name: muse_task_budget muse_task_budget_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_budget + ADD CONSTRAINT muse_task_budget_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_task_config_binding muse_task_config_binding_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_config_binding + ADD CONSTRAINT muse_task_config_binding_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_task_control muse_task_control_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_control + ADD CONSTRAINT muse_task_control_pkey PRIMARY KEY (run_purpose, author_id, command_id); + + +-- +-- Name: muse_task_event muse_task_event_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_event + ADD CONSTRAINT muse_task_event_pkey PRIMARY KEY (event_id); + + +-- +-- Name: muse_task_event muse_task_event_task_id_sequence_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_event + ADD CONSTRAINT muse_task_event_task_id_sequence_key UNIQUE (task_id, sequence); + + +-- +-- Name: muse_task muse_task_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task + ADD CONSTRAINT muse_task_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_task muse_task_run_purpose_author_id_command_id_key; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task + ADD CONSTRAINT muse_task_run_purpose_author_id_command_id_key UNIQUE (run_purpose, author_id, command_id); + + +-- +-- Name: muse_task_scope_lease muse_task_scope_lease_pkey; Type: CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_scope_lease + ADD CONSTRAINT muse_task_scope_lease_pkey PRIMARY KEY (run_purpose, scope_key); + + +-- +-- Name: activation_receipt activation_receipt_pkey; Type: CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.activation_receipt + ADD CONSTRAINT activation_receipt_pkey PRIMARY KEY (command_id); + + +-- +-- Name: policy_version policy_version_pkey; Type: CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.policy_version + ADD CONSTRAINT policy_version_pkey PRIMARY KEY (type_id, version); + + +-- +-- Name: schema_binding schema_binding_pkey; Type: CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.schema_binding + ADD CONSTRAINT schema_binding_pkey PRIMARY KEY (target_ref); + + +-- +-- Name: schema_version schema_version_pkey; Type: CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.schema_version + ADD CONSTRAINT schema_version_pkey PRIMARY KEY (schema_id, schema_version); + + +-- +-- Name: type_registry type_registry_pkey; Type: CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.type_registry + ADD CONSTRAINT type_registry_pkey PRIMARY KEY (type_id); + + +-- +-- Name: work_extension work_extension_pkey; Type: CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.work_extension + ADD CONSTRAINT work_extension_pkey PRIMARY KEY (work_id, schema_id, base_version, extension_version); + + +-- +-- Name: muse_blind_assignment muse_blind_assignment_experiment_id_sample_id_key; Type: CONSTRAINT; Schema: oracle; Owner: muse_maint +-- + +ALTER TABLE ONLY oracle.muse_blind_assignment + ADD CONSTRAINT muse_blind_assignment_experiment_id_sample_id_key UNIQUE (experiment_id, sample_id); + + +-- +-- Name: muse_blind_assignment muse_blind_assignment_pkey; Type: CONSTRAINT; Schema: oracle; Owner: muse_maint +-- + +ALTER TABLE ONLY oracle.muse_blind_assignment + ADD CONSTRAINT muse_blind_assignment_pkey PRIMARY KEY (assignment_id); + + +-- +-- Name: muse_calibration_gold muse_calibration_gold_pkey; Type: CONSTRAINT; Schema: oracle; Owner: muse_maint +-- + +ALTER TABLE ONLY oracle.muse_calibration_gold + ADD CONSTRAINT muse_calibration_gold_pkey PRIMARY KEY (experiment_id); + + +-- +-- Name: muse_dataset_answers muse_dataset_answers_pkey; Type: CONSTRAINT; Schema: oracle; Owner: muse_maint +-- + +ALTER TABLE ONLY oracle.muse_dataset_answers + ADD CONSTRAINT muse_dataset_answers_pkey PRIMARY KEY (version_id); + + +-- +-- Name: muse_method_usage method_usage_call_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_usage + ADD CONSTRAINT method_usage_call_key UNIQUE (method_version_id, kind, context_ref, fragment_hash, task_id, result_ref); + + +-- +-- Name: muse_attempt muse_attempt_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_attempt + ADD CONSTRAINT muse_attempt_pkey PRIMARY KEY (attempt_id); + + +-- +-- Name: muse_author_feedback muse_author_feedback_author_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_author_feedback + ADD CONSTRAINT muse_author_feedback_author_id_command_id_key UNIQUE (author_id, command_id); + + +-- +-- Name: muse_author_feedback muse_author_feedback_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_author_feedback + ADD CONSTRAINT muse_author_feedback_pkey PRIMARY KEY (feedback_id); + + +-- +-- Name: muse_author_observation muse_author_observation_author_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_author_observation + ADD CONSTRAINT muse_author_observation_author_id_command_id_key UNIQUE (author_id, command_id); + + +-- +-- Name: muse_author_observation muse_author_observation_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_author_observation + ADD CONSTRAINT muse_author_observation_pkey PRIMARY KEY (observation_id); + + +-- +-- Name: muse_author_review muse_author_review_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_author_review + ADD CONSTRAINT muse_author_review_pkey PRIMARY KEY (review_id); + + +-- +-- Name: muse_branch_merge_source muse_branch_merge_source_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_branch_merge_source + ADD CONSTRAINT muse_branch_merge_source_pkey PRIMARY KEY (candidate_id, candidate_revision); + + +-- +-- Name: muse_budget_account muse_budget_account_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_budget_account + ADD CONSTRAINT muse_budget_account_pkey PRIMARY KEY (run_purpose, account_id); + + +-- +-- Name: muse_budget_reservation muse_budget_reservation_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_budget_reservation + ADD CONSTRAINT muse_budget_reservation_pkey PRIMARY KEY (run_purpose, call_id); + + +-- +-- Name: muse_call_reconciliation muse_call_reconciliation_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_call_reconciliation + ADD CONSTRAINT muse_call_reconciliation_pkey PRIMARY KEY (task_id, command_id); + + +-- +-- Name: muse_call_settlement muse_call_settlement_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_call_settlement + ADD CONSTRAINT muse_call_settlement_pkey PRIMARY KEY (task_id, command_id); + + +-- +-- Name: muse_call_settlement muse_call_settlement_receipt_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_call_settlement + ADD CONSTRAINT muse_call_settlement_receipt_id_key UNIQUE (receipt_id); + + +-- +-- Name: muse_candidate_decision muse_candidate_decision_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_candidate_decision + ADD CONSTRAINT muse_candidate_decision_pkey PRIMARY KEY (candidate_id, candidate_revision); + + +-- +-- Name: muse_change_command muse_change_command_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_change_command + ADD CONSTRAINT muse_change_command_pkey PRIMARY KEY (author_id, run_purpose, command_id); + + +-- +-- Name: muse_change_impact muse_change_impact_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_change_impact + ADD CONSTRAINT muse_change_impact_pkey PRIMARY KEY (impact_id); + + +-- +-- Name: muse_change_impact muse_change_impact_receipt_id_target_ref_reason_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_change_impact + ADD CONSTRAINT muse_change_impact_receipt_id_target_ref_reason_key UNIQUE (receipt_id, target_ref, reason); + + +-- +-- Name: muse_chapter muse_chapter_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_chapter + ADD CONSTRAINT muse_chapter_pkey PRIMARY KEY (chapter_id); + + +-- +-- Name: muse_chapter muse_chapter_work_id_position_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_chapter + ADD CONSTRAINT muse_chapter_work_id_position_key UNIQUE (work_id, "position") DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_clean_candidate muse_clean_candidate_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_clean_candidate + ADD CONSTRAINT muse_clean_candidate_pkey PRIMARY KEY (candidate_id); + + +-- +-- Name: muse_clean_candidate muse_clean_candidate_source_id_revision_candidate_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_clean_candidate + ADD CONSTRAINT muse_clean_candidate_source_id_revision_candidate_id_key UNIQUE (source_id, revision, candidate_id); + + +-- +-- Name: muse_config_probe_binding muse_config_probe_binding_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_config_probe_binding + ADD CONSTRAINT muse_config_probe_binding_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_context_snapshot muse_context_snapshot_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_context_snapshot + ADD CONSTRAINT muse_context_snapshot_pkey PRIMARY KEY (snapshot_id); + + +-- +-- Name: muse_context_snapshot muse_context_snapshot_run_purpose_task_id_input_hash_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_context_snapshot + ADD CONSTRAINT muse_context_snapshot_run_purpose_task_id_input_hash_key UNIQUE (run_purpose, task_id, input_hash); + + +-- +-- Name: muse_delivery_artifact muse_delivery_artifact_delivery_id_format_formatter_version_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery_artifact + ADD CONSTRAINT muse_delivery_artifact_delivery_id_format_formatter_version_key UNIQUE (delivery_id, format, formatter_version); + + +-- +-- Name: muse_delivery_artifact muse_delivery_artifact_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery_artifact + ADD CONSTRAINT muse_delivery_artifact_pkey PRIMARY KEY (artifact_id); + + +-- +-- Name: muse_delivery_artifact_validation muse_delivery_artifact_validation_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery_artifact_validation + ADD CONSTRAINT muse_delivery_artifact_validation_pkey PRIMARY KEY (artifact_id, validation_version); + + +-- +-- Name: muse_delivery muse_delivery_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery + ADD CONSTRAINT muse_delivery_pkey PRIMARY KEY (delivery_id); + + +-- +-- Name: muse_delivery muse_delivery_work_id_revision_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery + ADD CONSTRAINT muse_delivery_work_id_revision_key UNIQUE (work_id, revision); + + +-- +-- Name: muse_delivery muse_delivery_work_identity; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery + ADD CONSTRAINT muse_delivery_work_identity UNIQUE (delivery_id, work_id); + + +-- +-- Name: muse_diagnosis muse_diagnosis_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_diagnosis + ADD CONSTRAINT muse_diagnosis_pkey PRIMARY KEY (diagnosis_id); + + +-- +-- Name: muse_directory_version muse_directory_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_directory_version + ADD CONSTRAINT muse_directory_version_pkey PRIMARY KEY (work_id, revision); + + +-- +-- Name: muse_document_branch muse_document_branch_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document_branch + ADD CONSTRAINT muse_document_branch_pkey PRIMARY KEY (document_id); + + +-- +-- Name: muse_document muse_document_chapter_id_branch_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document + ADD CONSTRAINT muse_document_chapter_id_branch_id_key UNIQUE (chapter_id, branch_id); + + +-- +-- Name: muse_document_index muse_document_index_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document_index + ADD CONSTRAINT muse_document_index_pkey PRIMARY KEY (document_id, revision); + + +-- +-- Name: muse_document muse_document_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document + ADD CONSTRAINT muse_document_pkey PRIMARY KEY (document_id); + + +-- +-- Name: muse_document_version muse_document_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document_version + ADD CONSTRAINT muse_document_version_pkey PRIMARY KEY (document_id, revision); + + +-- +-- Name: muse_enablement_receipt muse_enablement_receipt_author_id_experiment_id_payload_has_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_enablement_receipt + ADD CONSTRAINT muse_enablement_receipt_author_id_experiment_id_payload_has_key UNIQUE (author_id, experiment_id, payload_hash); + + +-- +-- Name: muse_enablement_receipt muse_enablement_receipt_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_enablement_receipt + ADD CONSTRAINT muse_enablement_receipt_pkey PRIMARY KEY (receipt_id); + + +-- +-- Name: muse_exploration_selection muse_exploration_selection_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_exploration_selection + ADD CONSTRAINT muse_exploration_selection_pkey PRIMARY KEY (work_id); + + +-- +-- Name: muse_exploration_selection_version muse_exploration_selection_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_exploration_selection_version + ADD CONSTRAINT muse_exploration_selection_version_pkey PRIMARY KEY (work_id, revision); + + +-- +-- Name: muse_fact_proposal muse_fact_proposal_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_fact_proposal + ADD CONSTRAINT muse_fact_proposal_pkey PRIMARY KEY (proposal_id); + + +-- +-- Name: muse_fact_proposal_version muse_fact_proposal_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_fact_proposal_version + ADD CONSTRAINT muse_fact_proposal_version_pkey PRIMARY KEY (proposal_id, revision); + + +-- +-- Name: muse_flow_version muse_flow_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_flow_version + ADD CONSTRAINT muse_flow_version_pkey PRIMARY KEY (run_purpose, flow_id, version); + + +-- +-- Name: muse_improvement_action muse_improvement_action_author_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_improvement_action + ADD CONSTRAINT muse_improvement_action_author_id_command_id_key UNIQUE (author_id, command_id); + + +-- +-- Name: muse_improvement_action muse_improvement_action_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_improvement_action + ADD CONSTRAINT muse_improvement_action_pkey PRIMARY KEY (action_id); + + +-- +-- Name: muse_improvement muse_improvement_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_improvement + ADD CONSTRAINT muse_improvement_pkey PRIMARY KEY (improvement_id); + + +-- +-- Name: muse_improvement_result muse_improvement_result_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_improvement_result + ADD CONSTRAINT muse_improvement_result_pkey PRIMARY KEY (action_id); + + +-- +-- Name: muse_improvement_version muse_improvement_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_improvement_version + ADD CONSTRAINT muse_improvement_version_pkey PRIMARY KEY (improvement_id, revision); + + +-- +-- Name: muse_legacy_import_record muse_legacy_import_record_author_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_legacy_import_record + ADD CONSTRAINT muse_legacy_import_record_author_id_command_id_key UNIQUE (author_id, command_id); + + +-- +-- Name: muse_legacy_import_record muse_legacy_import_record_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_legacy_import_record + ADD CONSTRAINT muse_legacy_import_record_pkey PRIMARY KEY (author_id, source_key); + + +-- +-- Name: muse_legacy_target muse_legacy_target_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_legacy_target + ADD CONSTRAINT muse_legacy_target_pkey PRIMARY KEY (singleton); + + +-- +-- Name: muse_legacy_target muse_legacy_target_target_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_legacy_target + ADD CONSTRAINT muse_legacy_target_target_id_key UNIQUE (target_id); + + +-- +-- Name: muse_literary_report muse_literary_report_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_literary_report + ADD CONSTRAINT muse_literary_report_pkey PRIMARY KEY (report_id); + + +-- +-- Name: muse_literary_report muse_literary_report_task_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_literary_report + ADD CONSTRAINT muse_literary_report_task_id_key UNIQUE (task_id); + + +-- +-- Name: muse_literary_shard muse_literary_shard_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_literary_shard + ADD CONSTRAINT muse_literary_shard_pkey PRIMARY KEY (task_id, shard_id); + + +-- +-- Name: muse_literary_shard muse_literary_shard_task_id_call_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_literary_shard + ADD CONSTRAINT muse_literary_shard_task_id_call_id_key UNIQUE (task_id, call_id); + + +-- +-- Name: muse_method_binding muse_method_binding_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_binding + ADD CONSTRAINT muse_method_binding_pkey PRIMARY KEY (binding_id); + + +-- +-- Name: muse_method_evidence muse_method_evidence_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_evidence + ADD CONSTRAINT muse_method_evidence_pkey PRIMARY KEY (evidence_id); + + +-- +-- Name: muse_method_index_guard muse_method_index_guard_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_index_guard + ADD CONSTRAINT muse_method_index_guard_pkey PRIMARY KEY (singleton); + + +-- +-- Name: muse_method_index muse_method_index_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_index + ADD CONSTRAINT muse_method_index_pkey PRIMARY KEY (method_version_id); + + +-- +-- Name: muse_method_index_version muse_method_index_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_index_version + ADD CONSTRAINT muse_method_index_version_pkey PRIMARY KEY (ledger_id); + + +-- +-- Name: muse_method muse_method_owner_content_hash_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method + ADD CONSTRAINT muse_method_owner_content_hash_key UNIQUE (owner, content_hash); + + +-- +-- Name: muse_method muse_method_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method + ADD CONSTRAINT muse_method_pkey PRIMARY KEY (method_id); + + +-- +-- Name: muse_method_proposal muse_method_proposal_method_id_revision_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_proposal + ADD CONSTRAINT muse_method_proposal_method_id_revision_key UNIQUE (method_id, revision); + + +-- +-- Name: muse_method_proposal muse_method_proposal_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_proposal + ADD CONSTRAINT muse_method_proposal_pkey PRIMARY KEY (proposal_id); + + +-- +-- Name: muse_method_usage muse_method_usage_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_usage + ADD CONSTRAINT muse_method_usage_pkey PRIMARY KEY (usage_id); + + +-- +-- Name: muse_method_version muse_method_version_method_id_content_hash_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_version + ADD CONSTRAINT muse_method_version_method_id_content_hash_key UNIQUE (method_id, content_hash); + + +-- +-- Name: muse_method_version muse_method_version_method_id_version_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_version + ADD CONSTRAINT muse_method_version_method_id_version_key UNIQUE (method_id, version); + + +-- +-- Name: muse_method_version muse_method_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_version + ADD CONSTRAINT muse_method_version_pkey PRIMARY KEY (version_id); + + +-- +-- Name: muse_migration muse_migration_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_migration + ADD CONSTRAINT muse_migration_pkey PRIMARY KEY (version); + + +-- +-- Name: muse_model_candidate muse_model_candidate_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_candidate + ADD CONSTRAINT muse_model_candidate_pkey PRIMARY KEY (candidate_id); + + +-- +-- Name: muse_model_delivery muse_model_delivery_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_delivery + ADD CONSTRAINT muse_model_delivery_pkey PRIMARY KEY (call_id); + + +-- +-- Name: muse_model_plan_candidate muse_model_plan_candidate_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_plan_candidate + ADD CONSTRAINT muse_model_plan_candidate_pkey PRIMARY KEY (candidate_id); + + +-- +-- Name: muse_model_plan_candidate muse_model_plan_candidate_task_id_call_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_plan_candidate + ADD CONSTRAINT muse_model_plan_candidate_task_id_call_id_key UNIQUE (task_id, call_id); + + +-- +-- Name: muse_plan_candidate muse_plan_candidate_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan_candidate + ADD CONSTRAINT muse_plan_candidate_pkey PRIMARY KEY (candidate_id); + + +-- +-- Name: muse_plan_candidate_version muse_plan_candidate_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan_candidate_version + ADD CONSTRAINT muse_plan_candidate_version_pkey PRIMARY KEY (candidate_id, revision); + + +-- +-- Name: muse_plan muse_plan_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan + ADD CONSTRAINT muse_plan_pkey PRIMARY KEY (plan_id); + + +-- +-- Name: muse_plan_version muse_plan_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan_version + ADD CONSTRAINT muse_plan_version_pkey PRIMARY KEY (plan_id, revision); + + +-- +-- Name: muse_preference muse_preference_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_preference + ADD CONSTRAINT muse_preference_pkey PRIMARY KEY (preference_id); + + +-- +-- Name: muse_preference_version muse_preference_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_preference_version + ADD CONSTRAINT muse_preference_version_pkey PRIMARY KEY (preference_id, revision); + + +-- +-- Name: muse_quality_case muse_quality_case_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_quality_case + ADD CONSTRAINT muse_quality_case_pkey PRIMARY KEY (case_id); + + +-- +-- Name: muse_quality_case_version muse_quality_case_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_quality_case_version + ADD CONSTRAINT muse_quality_case_version_pkey PRIMARY KEY (case_id, revision); + + +-- +-- Name: muse_ranking_snapshot muse_ranking_snapshot_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_ranking_snapshot + ADD CONSTRAINT muse_ranking_snapshot_pkey PRIMARY KEY (snapshot_id); + + +-- +-- Name: muse_ranking_source muse_ranking_source_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_ranking_source + ADD CONSTRAINT muse_ranking_source_pkey PRIMARY KEY (ranking_id); + + +-- +-- Name: muse_raw_archive_item muse_raw_archive_item_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_archive_item + ADD CONSTRAINT muse_raw_archive_item_pkey PRIMARY KEY (archive_id, content_hash); + + +-- +-- Name: muse_raw_archive muse_raw_archive_lease_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_lease_id_key UNIQUE (lease_id); + + +-- +-- Name: muse_raw_archive muse_raw_archive_legacy_ref_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_legacy_ref_key UNIQUE (legacy_ref); + + +-- +-- Name: muse_raw_archive muse_raw_archive_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_pkey PRIMARY KEY (archive_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_pkey PRIMARY KEY (authorization_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_task_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_task_id_command_id_key UNIQUE (task_id, command_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_pkey PRIMARY KEY (lease_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_task_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_task_id_command_id_key UNIQUE (task_id, command_id); + + +-- +-- Name: muse_raw_namespace muse_raw_namespace_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_namespace + ADD CONSTRAINT muse_raw_namespace_pkey PRIMARY KEY (singleton); + + +-- +-- Name: muse_raw_orphan_cleanup muse_raw_orphan_cleanup_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_orphan_cleanup + ADD CONSTRAINT muse_raw_orphan_cleanup_pkey PRIMARY KEY (run_purpose, object_id); + + +-- +-- Name: muse_reader_feedback muse_reader_feedback_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_reader_feedback + ADD CONSTRAINT muse_reader_feedback_pkey PRIMARY KEY (feedback_id); + + +-- +-- Name: muse_release muse_release_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_release + ADD CONSTRAINT muse_release_pkey PRIMARY KEY (release_id); + + +-- +-- Name: muse_release muse_release_work_identity; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_release + ADD CONSTRAINT muse_release_work_identity UNIQUE (release_id, work_id); + + +-- +-- Name: muse_review_report muse_review_report_candidate_id_candidate_revision_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_review_report + ADD CONSTRAINT muse_review_report_candidate_id_candidate_revision_key UNIQUE (candidate_id, candidate_revision); + + +-- +-- Name: muse_review_report muse_review_report_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_review_report + ADD CONSTRAINT muse_review_report_pkey PRIMARY KEY (report_id); + + +-- +-- Name: muse_revision_comparison_receipt muse_revision_comparison_rece_author_id_experiment_id_paylo_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_comparison_receipt + ADD CONSTRAINT muse_revision_comparison_rece_author_id_experiment_id_paylo_key UNIQUE (author_id, experiment_id, payload_hash); + + +-- +-- Name: muse_revision_comparison_receipt muse_revision_comparison_receipt_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_comparison_receipt + ADD CONSTRAINT muse_revision_comparison_receipt_pkey PRIMARY KEY (receipt_id); + + +-- +-- Name: muse_revision_result muse_revision_result_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_result + ADD CONSTRAINT muse_revision_result_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_revision_round muse_revision_round_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_round + ADD CONSTRAINT muse_revision_round_pkey PRIMARY KEY (session_id, round_number); + + +-- +-- Name: muse_revision_round muse_revision_round_task_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_round + ADD CONSTRAINT muse_revision_round_task_command_id_key UNIQUE (task_command_id); + + +-- +-- Name: muse_revision_round muse_revision_round_task_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_round + ADD CONSTRAINT muse_revision_round_task_id_key UNIQUE (task_id); + + +-- +-- Name: muse_revision_session_action muse_revision_session_action_author_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session_action + ADD CONSTRAINT muse_revision_session_action_author_id_command_id_key UNIQUE (author_id, command_id); + + +-- +-- Name: muse_revision_session_action muse_revision_session_action_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session_action + ADD CONSTRAINT muse_revision_session_action_pkey PRIMARY KEY (action_id); + + +-- +-- Name: muse_revision_session muse_revision_session_author_id_create_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session + ADD CONSTRAINT muse_revision_session_author_id_create_command_id_key UNIQUE (author_id, create_command_id); + + +-- +-- Name: muse_revision_session muse_revision_session_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session + ADD CONSTRAINT muse_revision_session_pkey PRIMARY KEY (session_id); + + +-- +-- Name: muse_revision_session muse_revision_session_session_id_author_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session + ADD CONSTRAINT muse_revision_session_session_id_author_id_key UNIQUE (session_id, author_id); + + +-- +-- Name: muse_role_session_authorization muse_role_session_authorization_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_role_session_authorization + ADD CONSTRAINT muse_role_session_authorization_pkey PRIMARY KEY (authorization_id); + + +-- +-- Name: muse_rule_activation_current muse_rule_activation_current_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_current + ADD CONSTRAINT muse_rule_activation_current_pkey PRIMARY KEY (author_id, rule_id); + + +-- +-- Name: muse_rule_activation_event muse_rule_activation_event_author_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_event + ADD CONSTRAINT muse_rule_activation_event_author_id_command_id_key UNIQUE (author_id, command_id); + + +-- +-- Name: muse_rule_activation_event muse_rule_activation_event_author_id_rule_id_activation_rev_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_event + ADD CONSTRAINT muse_rule_activation_event_author_id_rule_id_activation_rev_key UNIQUE (author_id, rule_id, activation_revision); + + +-- +-- Name: muse_rule_activation_event muse_rule_activation_event_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_event + ADD CONSTRAINT muse_rule_activation_event_pkey PRIMARY KEY (event_id); + + +-- +-- Name: muse_rule_activation muse_rule_activation_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation + ADD CONSTRAINT muse_rule_activation_pkey PRIMARY KEY (author_id, rule_id); + + +-- +-- Name: muse_rule_diagnostic_receipt muse_rule_diagnostic_receipt_author_id_run_id_payload_hash_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_diagnostic_receipt + ADD CONSTRAINT muse_rule_diagnostic_receipt_author_id_run_id_payload_hash_key UNIQUE (author_id, run_id, payload_hash); + + +-- +-- Name: muse_rule_diagnostic_receipt muse_rule_diagnostic_receipt_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_diagnostic_receipt + ADD CONSTRAINT muse_rule_diagnostic_receipt_pkey PRIMARY KEY (receipt_id); + + +-- +-- Name: muse_rule_version muse_rule_version_author_id_rule_id_revision_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_version + ADD CONSTRAINT muse_rule_version_author_id_rule_id_revision_key UNIQUE (author_id, rule_id, revision); + + +-- +-- Name: muse_rule_version muse_rule_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_version + ADD CONSTRAINT muse_rule_version_pkey PRIMARY KEY (version_id); + + +-- +-- Name: muse_run_observation muse_run_observation_author_id_source_set_hash_phenomenon_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_run_observation + ADD CONSTRAINT muse_run_observation_author_id_source_set_hash_phenomenon_key UNIQUE (author_id, source_set_hash, phenomenon); + + +-- +-- Name: muse_run_observation_command muse_run_observation_command_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_run_observation_command + ADD CONSTRAINT muse_run_observation_command_pkey PRIMARY KEY (author_id, command_id); + + +-- +-- Name: muse_run_observation muse_run_observation_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_run_observation + ADD CONSTRAINT muse_run_observation_pkey PRIMARY KEY (observation_id); + + +-- +-- Name: muse_runtime_config_active muse_runtime_config_active_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_config_active + ADD CONSTRAINT muse_runtime_config_active_pkey PRIMARY KEY (run_purpose, config_id); + + +-- +-- Name: muse_runtime_config_validation muse_runtime_config_validation_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_config_validation + ADD CONSTRAINT muse_runtime_config_validation_pkey PRIMARY KEY (receipt_id); + + +-- +-- Name: muse_runtime_config_version muse_runtime_config_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_config_version + ADD CONSTRAINT muse_runtime_config_version_pkey PRIMARY KEY (run_purpose, config_id, version); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_attempt_id_kind_reference_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_attempt_id_kind_reference_id_key UNIQUE (attempt_id, kind, reference_id); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_pkey PRIMARY KEY (evidence_id); + + +-- +-- Name: muse_serial_plan muse_serial_plan_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_serial_plan + ADD CONSTRAINT muse_serial_plan_pkey PRIMARY KEY (plan_id); + + +-- +-- Name: muse_serial_plan_version muse_serial_plan_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_serial_plan_version + ADD CONSTRAINT muse_serial_plan_version_pkey PRIMARY KEY (plan_id, revision); + + +-- +-- Name: muse_source_analysis muse_source_analysis_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_analysis + ADD CONSTRAINT muse_source_analysis_pkey PRIMARY KEY (analysis_id); + + +-- +-- Name: muse_source muse_source_origin_kind_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source + ADD CONSTRAINT muse_source_origin_kind_key UNIQUE (origin, kind); + + +-- +-- Name: muse_source muse_source_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source + ADD CONSTRAINT muse_source_pkey PRIMARY KEY (source_id); + + +-- +-- Name: muse_source_slice_guard muse_source_slice_guard_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_slice_guard + ADD CONSTRAINT muse_source_slice_guard_pkey PRIMARY KEY (singleton); + + +-- +-- Name: muse_source_slice_index muse_source_slice_index_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_slice_index + ADD CONSTRAINT muse_source_slice_index_pkey PRIMARY KEY (slice_id); + + +-- +-- Name: muse_source_slice_index_version muse_source_slice_index_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_slice_index_version + ADD CONSTRAINT muse_source_slice_index_version_pkey PRIMARY KEY (ledger_id); + + +-- +-- Name: muse_source_slice muse_source_slice_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_slice + ADD CONSTRAINT muse_source_slice_pkey PRIMARY KEY (slice_id); + + +-- +-- Name: muse_source_version muse_source_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_version + ADD CONSTRAINT muse_source_version_pkey PRIMARY KEY (source_id, revision); + + +-- +-- Name: muse_step muse_step_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_step + ADD CONSTRAINT muse_step_pkey PRIMARY KEY (task_id, step_id); + + +-- +-- Name: muse_task_budget muse_task_budget_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_budget + ADD CONSTRAINT muse_task_budget_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_task_config_binding muse_task_config_binding_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_config_binding + ADD CONSTRAINT muse_task_config_binding_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_task_control muse_task_control_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_control + ADD CONSTRAINT muse_task_control_pkey PRIMARY KEY (run_purpose, author_id, command_id); + + +-- +-- Name: muse_task_event muse_task_event_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_event + ADD CONSTRAINT muse_task_event_pkey PRIMARY KEY (event_id); + + +-- +-- Name: muse_task_event muse_task_event_task_id_sequence_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_event + ADD CONSTRAINT muse_task_event_task_id_sequence_key UNIQUE (task_id, sequence); + + +-- +-- Name: muse_task muse_task_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task + ADD CONSTRAINT muse_task_pkey PRIMARY KEY (task_id); + + +-- +-- Name: muse_task muse_task_run_purpose_author_id_command_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task + ADD CONSTRAINT muse_task_run_purpose_author_id_command_id_key UNIQUE (run_purpose, author_id, command_id); + + +-- +-- Name: muse_task_scope_lease muse_task_scope_lease_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_scope_lease + ADD CONSTRAINT muse_task_scope_lease_pkey PRIMARY KEY (run_purpose, scope_key); + + +-- +-- Name: muse_voice_current muse_voice_current_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_current + ADD CONSTRAINT muse_voice_current_pkey PRIMARY KEY (work_id); + + +-- +-- Name: muse_voice_proposal muse_voice_proposal_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_proposal + ADD CONSTRAINT muse_voice_proposal_pkey PRIMARY KEY (proposal_id); + + +-- +-- Name: muse_voice_version muse_voice_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_version + ADD CONSTRAINT muse_voice_version_pkey PRIMARY KEY (version_id); + + +-- +-- Name: muse_voice_version muse_voice_version_proposal_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_version + ADD CONSTRAINT muse_voice_version_proposal_id_key UNIQUE (proposal_id); + + +-- +-- Name: muse_voice_version muse_voice_version_work_id_revision_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_version + ADD CONSTRAINT muse_voice_version_work_id_revision_key UNIQUE (work_id, revision); + + +-- +-- Name: muse_voice_version muse_voice_version_work_id_version_id_key; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_version + ADD CONSTRAINT muse_voice_version_work_id_version_id_key UNIQUE (work_id, version_id); + + +-- +-- Name: muse_work muse_work_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_work + ADD CONSTRAINT muse_work_pkey PRIMARY KEY (work_id); + + +-- +-- Name: muse_work_version muse_work_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_work_version + ADD CONSTRAINT muse_work_version_pkey PRIMARY KEY (work_id, revision); + + +-- +-- Name: muse_world_clock muse_world_clock_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_world_clock + ADD CONSTRAINT muse_world_clock_pkey PRIMARY KEY (work_id); + + +-- +-- Name: muse_world_object muse_world_object_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_world_object + ADD CONSTRAINT muse_world_object_pkey PRIMARY KEY (object_id); + + +-- +-- Name: muse_world_version muse_world_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_world_version + ADD CONSTRAINT muse_world_version_pkey PRIMARY KEY (object_id, revision); + + +-- +-- Name: muse_writing_candidate muse_writing_candidate_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_writing_candidate + ADD CONSTRAINT muse_writing_candidate_pkey PRIMARY KEY (candidate_id); + + +-- +-- Name: muse_writing_candidate_version muse_writing_candidate_version_pkey; Type: CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_writing_candidate_version + ADD CONSTRAINT muse_writing_candidate_version_pkey PRIMARY KEY (candidate_id, revision); + + +-- +-- Name: evaluation_reuse_source; Type: INDEX; Schema: evaluation; Owner: muse_maint +-- + +CREATE INDEX evaluation_reuse_source ON evaluation.muse_evaluation_reuse USING btree (source_experiment_id); + + +-- +-- Name: muse_attempt_task_id_state_lease_until_idx; Type: INDEX; Schema: evaluation; Owner: muse_maint +-- + +CREATE INDEX muse_attempt_task_id_state_lease_until_idx ON evaluation.muse_attempt USING btree (task_id, state, lease_until); + + +-- +-- Name: muse_budget_reservation_run_purpose_account_id_window_start_idx; Type: INDEX; Schema: evaluation; Owner: muse_maint +-- + +CREATE INDEX muse_budget_reservation_run_purpose_account_id_window_start_idx ON evaluation.muse_budget_reservation USING btree (run_purpose, account_id, window_start); + + +-- +-- Name: muse_budget_reservation_task_id_role_id_idx; Type: INDEX; Schema: evaluation; Owner: muse_maint +-- + +CREATE INDEX muse_budget_reservation_task_id_role_id_idx ON evaluation.muse_budget_reservation USING btree (task_id, role_id); + + +-- +-- Name: muse_context_snapshot_task_id_created_at_idx; Type: INDEX; Schema: evaluation; Owner: muse_maint +-- + +CREATE INDEX muse_context_snapshot_task_id_created_at_idx ON evaluation.muse_context_snapshot USING btree (task_id, created_at); + + +-- +-- Name: muse_step_state_task_id_idx; Type: INDEX; Schema: evaluation; Owner: muse_maint +-- + +CREATE INDEX muse_step_state_task_id_idx ON evaluation.muse_step USING btree (state, task_id); + + +-- +-- Name: muse_task_run_purpose_state_created_at_idx; Type: INDEX; Schema: evaluation; Owner: muse_maint +-- + +CREATE INDEX muse_task_run_purpose_state_created_at_idx ON evaluation.muse_task USING btree (run_purpose, state, created_at); + + +-- +-- Name: method_usage_legacy_key; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE UNIQUE INDEX method_usage_legacy_key ON public.muse_method_usage USING btree (method_version_id, kind, context_ref, fragment_hash) WHERE ((task_id IS NULL) OR (result_ref IS NULL)); + + +-- +-- Name: muse_attempt_task_id_state_lease_until_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_attempt_task_id_state_lease_until_idx ON public.muse_attempt USING btree (task_id, state, lease_until); + + +-- +-- Name: muse_budget_reservation_run_purpose_account_id_window_start_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_budget_reservation_run_purpose_account_id_window_start_idx ON public.muse_budget_reservation USING btree (run_purpose, account_id, window_start); + + +-- +-- Name: muse_budget_reservation_task_id_role_id_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_budget_reservation_task_id_role_id_idx ON public.muse_budget_reservation USING btree (task_id, role_id); + + +-- +-- Name: muse_context_snapshot_task_id_created_at_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_context_snapshot_task_id_created_at_idx ON public.muse_context_snapshot USING btree (task_id, created_at); + + +-- +-- Name: muse_method_binding_active; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE UNIQUE INDEX muse_method_binding_active ON public.muse_method_binding USING btree (work_id, target_ref, method_id) WHERE (released_at IS NULL); + + +-- +-- Name: muse_method_evidence_method_id_kind_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_method_evidence_method_id_kind_idx ON public.muse_method_evidence USING btree (method_id, kind); + + +-- +-- Name: muse_method_index_active; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE UNIQUE INDEX muse_method_index_active ON public.muse_method_index_version USING btree (active) WHERE active; + + +-- +-- Name: muse_method_type_id_state_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_method_type_id_state_idx ON public.muse_method USING btree (type_id, state); + + +-- +-- Name: muse_method_usage_method_version_id_created_at_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_method_usage_method_version_id_created_at_idx ON public.muse_method_usage USING btree (method_version_id, created_at); + + +-- +-- Name: muse_ranking_snapshot_ranking_id_captured_at_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_ranking_snapshot_ranking_id_captured_at_idx ON public.muse_ranking_snapshot USING btree (ranking_id, captured_at DESC); + + +-- +-- Name: muse_review_report_candidate_id_created_at_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_review_report_candidate_id_created_at_idx ON public.muse_review_report USING btree (candidate_id, created_at); + + +-- +-- Name: muse_run_observation_author_id_issue_key_created_at_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_run_observation_author_id_issue_key_created_at_idx ON public.muse_run_observation USING btree (author_id, issue_key, created_at); + + +-- +-- Name: muse_source_analysis_author_id_source_id_created_at_analysi_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_source_analysis_author_id_source_id_created_at_analysi_idx ON public.muse_source_analysis USING btree (author_id, source_id, created_at DESC, analysis_id); + + +-- +-- Name: muse_source_slice_by_source; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_source_slice_by_source ON public.muse_source_slice USING btree (source_id, revision); + + +-- +-- Name: muse_source_slice_index_active; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE UNIQUE INDEX muse_source_slice_index_active ON public.muse_source_slice_index_version USING btree (active) WHERE active; + + +-- +-- Name: muse_source_slice_window; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE UNIQUE INDEX muse_source_slice_window ON public.muse_source_slice USING btree (source_id, revision, "窗计划哈希", "起点"); + + +-- +-- Name: muse_source_version_source_id_imported_at_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_source_version_source_id_imported_at_idx ON public.muse_source_version USING btree (source_id, imported_at); + + +-- +-- Name: muse_step_state_task_id_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_step_state_task_id_idx ON public.muse_step USING btree (state, task_id); + + +-- +-- Name: muse_task_run_purpose_state_created_at_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX muse_task_run_purpose_state_created_at_idx ON public.muse_task USING btree (run_purpose, state, created_at); + + +-- +-- Name: world_version_system_idx; Type: INDEX; Schema: public; Owner: muse_maint +-- + +CREATE INDEX world_version_system_idx ON public.muse_world_version USING btree (object_id, system_revision DESC); + + +-- +-- Name: muse_calibration_receipt calibration_receipt_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER calibration_receipt_guard BEFORE DELETE OR UPDATE ON evaluation.muse_calibration_receipt FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_comparison_rejection comparison_rejection_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER comparison_rejection_guard BEFORE DELETE OR UPDATE ON evaluation.muse_comparison_rejection FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_dataset_version dataset_history_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER dataset_history_guard BEFORE DELETE OR UPDATE ON evaluation.muse_dataset_version FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_effect_assessment effect_assessment_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER effect_assessment_guard BEFORE DELETE OR UPDATE ON evaluation.muse_effect_assessment FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_evaluation_condition evaluation_condition_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER evaluation_condition_guard BEFORE DELETE OR UPDATE ON evaluation.muse_evaluation_condition FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_experiment_execution evaluation_execution_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER evaluation_execution_guard BEFORE DELETE OR UPDATE ON evaluation.muse_experiment_execution FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_evaluation_output evaluation_output_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER evaluation_output_guard BEFORE DELETE OR UPDATE ON evaluation.muse_evaluation_output FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_evaluation_reuse evaluation_reuse_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER evaluation_reuse_guard BEFORE DELETE OR UPDATE ON evaluation.muse_evaluation_reuse FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_evaluation_unit evaluation_unit_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER evaluation_unit_guard BEFORE DELETE OR UPDATE ON evaluation.muse_evaluation_unit FOR EACH ROW EXECUTE FUNCTION evaluation.muse_guard_unit_binding(); + + +-- +-- Name: muse_experiment experiment_history_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER experiment_history_guard BEFORE DELETE OR UPDATE ON evaluation.muse_experiment FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_experiment_stop experiment_stop_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER experiment_stop_guard BEFORE DELETE OR UPDATE ON evaluation.muse_experiment_stop FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_model_delivery model_delivery_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER model_delivery_guard BEFORE DELETE OR UPDATE ON evaluation.muse_model_delivery FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_call_reconciliation muse_call_reconciliation_immutable; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER muse_call_reconciliation_immutable BEFORE DELETE OR UPDATE ON evaluation.muse_call_reconciliation FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_call_settlement muse_call_settlement_immutable; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER muse_call_settlement_immutable BEFORE DELETE OR UPDATE ON evaluation.muse_call_settlement FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_config_probe_binding muse_config_probe_immutable; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER muse_config_probe_immutable BEFORE DELETE OR UPDATE ON evaluation.muse_config_probe_binding FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_rule_diagnostic_assessment rule_diagnostic_assessment_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER rule_diagnostic_assessment_guard BEFORE DELETE OR UPDATE ON evaluation.muse_rule_diagnostic_assessment FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_rule_diagnostic_result rule_diagnostic_result_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER rule_diagnostic_result_guard BEFORE DELETE OR UPDATE ON evaluation.muse_rule_diagnostic_result FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_rule_diagnostic_run rule_diagnostic_run_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER rule_diagnostic_run_guard BEFORE DELETE OR UPDATE ON evaluation.muse_rule_diagnostic_run FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_rule_diagnostic_stop rule_diagnostic_stop_guard; Type: TRIGGER; Schema: evaluation; Owner: muse_maint +-- + +CREATE TRIGGER rule_diagnostic_stop_guard BEFORE DELETE OR UPDATE ON evaluation.muse_rule_diagnostic_stop FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: work_extension extension_immutable; Type: TRIGGER; Schema: metadata; Owner: muse_maint +-- + +CREATE TRIGGER extension_immutable BEFORE DELETE OR UPDATE ON metadata.work_extension FOR EACH ROW EXECUTE FUNCTION metadata.immutable_definition(); + + +-- +-- Name: policy_version policy_immutable; Type: TRIGGER; Schema: metadata; Owner: muse_maint +-- + +CREATE TRIGGER policy_immutable BEFORE DELETE OR UPDATE ON metadata.policy_version FOR EACH ROW EXECUTE FUNCTION metadata.immutable_definition(); + + +-- +-- Name: schema_version schema_immutable; Type: TRIGGER; Schema: metadata; Owner: muse_maint +-- + +CREATE TRIGGER schema_immutable BEFORE DELETE OR UPDATE ON metadata.schema_version FOR EACH ROW EXECUTE FUNCTION metadata.immutable_definition(); + + +-- +-- Name: muse_dataset_answers answer_history_guard; Type: TRIGGER; Schema: oracle; Owner: muse_maint +-- + +CREATE TRIGGER answer_history_guard BEFORE DELETE OR UPDATE ON oracle.muse_dataset_answers FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_blind_assignment assignment_history_guard; Type: TRIGGER; Schema: oracle; Owner: muse_maint +-- + +CREATE TRIGGER assignment_history_guard BEFORE DELETE OR UPDATE ON oracle.muse_blind_assignment FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_calibration_gold calibration_gold_guard; Type: TRIGGER; Schema: oracle; Owner: muse_maint +-- + +CREATE TRIGGER calibration_gold_guard BEFORE DELETE OR UPDATE ON oracle.muse_calibration_gold FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_branch_merge_source branch_merge_source_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER branch_merge_source_immutable BEFORE DELETE OR UPDATE ON public.muse_branch_merge_source FOR EACH ROW EXECUTE FUNCTION public.muse_branch_source_immutable(); + + +-- +-- Name: muse_document_branch document_branch_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER document_branch_immutable BEFORE DELETE OR UPDATE ON public.muse_document_branch FOR EACH ROW EXECUTE FUNCTION public.muse_branch_source_immutable(); + + +-- +-- Name: muse_enablement_receipt enablement_receipt_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER enablement_receipt_guard BEFORE DELETE OR UPDATE ON public.muse_enablement_receipt FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_model_delivery model_delivery_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER model_delivery_guard BEFORE DELETE OR UPDATE ON public.muse_model_delivery FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_author_feedback muse_author_feedback_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_author_feedback_immutable BEFORE DELETE OR UPDATE ON public.muse_author_feedback FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_author_observation muse_author_observation_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_author_observation_immutable BEFORE DELETE OR UPDATE ON public.muse_author_observation FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_call_reconciliation muse_call_reconciliation_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_call_reconciliation_immutable BEFORE DELETE OR UPDATE ON public.muse_call_reconciliation FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_call_settlement muse_call_settlement_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_call_settlement_immutable BEFORE DELETE OR UPDATE ON public.muse_call_settlement FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_config_probe_binding muse_config_probe_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_config_probe_immutable BEFORE DELETE OR UPDATE ON public.muse_config_probe_binding FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_delivery_artifact muse_delivery_artifact_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_delivery_artifact_immutable BEFORE DELETE OR UPDATE ON public.muse_delivery_artifact FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_delivery_artifact_validation muse_delivery_artifact_validation_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_delivery_artifact_validation_immutable BEFORE DELETE OR UPDATE ON public.muse_delivery_artifact_validation FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_delivery muse_delivery_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_delivery_immutable BEFORE DELETE OR UPDATE ON public.muse_delivery FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_diagnosis muse_diagnosis_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_diagnosis_guard BEFORE DELETE OR UPDATE ON public.muse_diagnosis FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_improvement_action muse_improvement_action_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_improvement_action_immutable BEFORE DELETE OR UPDATE ON public.muse_improvement_action FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_improvement_result muse_improvement_result_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_improvement_result_immutable BEFORE DELETE OR UPDATE ON public.muse_improvement_result FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_improvement_version muse_improvement_version_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_improvement_version_immutable BEFORE DELETE OR UPDATE ON public.muse_improvement_version FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_legacy_import_record muse_legacy_import_record_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +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(); + + +-- +-- Name: muse_literary_report muse_literary_report_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_literary_report_guard BEFORE DELETE OR UPDATE ON public.muse_literary_report FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_literary_shard muse_literary_shard_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_literary_shard_guard BEFORE DELETE OR UPDATE ON public.muse_literary_shard FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_method_index muse_method_index_changed; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_method_index_changed AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON public.muse_method_index FOR EACH STATEMENT EXECUTE FUNCTION public.muse_method_index_changed(); + + +-- +-- Name: muse_method_index_version muse_method_index_head_changed; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_method_index_head_changed AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON public.muse_method_index_version FOR EACH STATEMENT EXECUTE FUNCTION public.muse_method_index_changed(); + + +-- +-- Name: muse_preference_version muse_preference_version_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_preference_version_immutable BEFORE DELETE OR UPDATE ON public.muse_preference_version FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_reader_feedback muse_reader_feedback_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_reader_feedback_immutable BEFORE DELETE OR UPDATE ON public.muse_reader_feedback FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_release muse_release_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_release_immutable BEFORE DELETE OR UPDATE ON public.muse_release FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_revision_comparison_receipt muse_revision_comparison_receipt_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_revision_comparison_receipt_immutable BEFORE DELETE OR UPDATE ON public.muse_revision_comparison_receipt FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_revision_result muse_revision_result_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_revision_result_guard BEFORE DELETE OR UPDATE ON public.muse_revision_result FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_revision_session_action muse_revision_session_action_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_revision_session_action_immutable BEFORE DELETE OR UPDATE ON public.muse_revision_session_action FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_rule_version muse_rule_version_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_rule_version_guard BEFORE DELETE OR UPDATE ON public.muse_rule_version FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_run_observation_command muse_run_observation_command_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_run_observation_command_immutable BEFORE DELETE OR UPDATE ON public.muse_run_observation_command FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_run_observation muse_run_observation_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_run_observation_immutable BEFORE DELETE OR UPDATE ON public.muse_run_observation FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_serial_plan_version muse_serial_history_immutable; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_serial_history_immutable BEFORE DELETE OR UPDATE ON public.muse_serial_plan_version FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_source_analysis muse_source_analysis_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_source_analysis_guard BEFORE DELETE OR UPDATE ON public.muse_source_analysis FOR EACH ROW EXECUTE FUNCTION public.muse_guard_source_analysis(); + + +-- +-- Name: muse_source_slice muse_source_slice_changed; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_source_slice_changed AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON public.muse_source_slice FOR EACH STATEMENT EXECUTE FUNCTION public.muse_source_slice_changed(); + + +-- +-- Name: muse_source_slice muse_source_slice_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_source_slice_guard BEFORE UPDATE ON public.muse_source_slice FOR EACH ROW EXECUTE FUNCTION public.muse_guard_source_slice(); + + +-- +-- Name: muse_source_slice_index_version muse_source_slice_head_changed; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_source_slice_head_changed AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON public.muse_source_slice_index_version FOR EACH STATEMENT EXECUTE FUNCTION public.muse_source_slice_changed(); + + +-- +-- Name: muse_source_slice_index muse_source_slice_index_changed; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_source_slice_index_changed AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON public.muse_source_slice_index FOR EACH STATEMENT EXECUTE FUNCTION public.muse_source_slice_changed(); + + +-- +-- Name: muse_voice_proposal muse_voice_proposal_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_voice_proposal_guard BEFORE DELETE OR UPDATE ON public.muse_voice_proposal FOR EACH ROW EXECUTE FUNCTION public.muse_guard_voice_history(); + + +-- +-- Name: muse_voice_version muse_voice_version_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER muse_voice_version_guard BEFORE DELETE OR UPDATE ON public.muse_voice_version FOR EACH ROW EXECUTE FUNCTION public.muse_guard_voice_history(); + + +-- +-- Name: muse_quality_case_version quality_case_history_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER quality_case_history_guard BEFORE DELETE OR UPDATE ON public.muse_quality_case_version FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_rule_activation_event rule_activation_event_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER rule_activation_event_guard BEFORE DELETE OR UPDATE ON public.muse_rule_activation_event FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_rule_diagnostic_receipt rule_diagnostic_receipt_guard; Type: TRIGGER; Schema: public; Owner: muse_maint +-- + +CREATE TRIGGER rule_diagnostic_receipt_guard BEFORE DELETE OR UPDATE ON public.muse_rule_diagnostic_receipt FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); + + +-- +-- Name: muse_attempt muse_attempt_task_id_step_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_attempt + ADD CONSTRAINT muse_attempt_task_id_step_id_fkey FOREIGN KEY (task_id, step_id) REFERENCES evaluation.muse_step(task_id, step_id); + + +-- +-- Name: muse_budget_reservation muse_budget_reservation_attempt_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_budget_reservation + ADD CONSTRAINT muse_budget_reservation_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES evaluation.muse_attempt(attempt_id); + + +-- +-- Name: muse_budget_reservation muse_budget_reservation_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_budget_reservation + ADD CONSTRAINT muse_budget_reservation_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_calibration_receipt muse_calibration_receipt_experiment_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_calibration_receipt + ADD CONSTRAINT muse_calibration_receipt_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment(experiment_id); + + +-- +-- Name: muse_call_reconciliation muse_call_reconciliation_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_call_reconciliation + ADD CONSTRAINT muse_call_reconciliation_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_call_settlement muse_call_settlement_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_call_settlement + ADD CONSTRAINT muse_call_settlement_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_comparison_rejection muse_comparison_rejection_attempt_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_comparison_rejection + ADD CONSTRAINT muse_comparison_rejection_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES evaluation.muse_attempt(attempt_id); + + +-- +-- Name: muse_comparison_rejection muse_comparison_rejection_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_comparison_rejection + ADD CONSTRAINT muse_comparison_rejection_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_comparison_rejection muse_comparison_rejection_unit_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_comparison_rejection + ADD CONSTRAINT muse_comparison_rejection_unit_id_fkey FOREIGN KEY (unit_id) REFERENCES evaluation.muse_evaluation_unit(unit_id); + + +-- +-- Name: muse_config_probe_binding muse_config_probe_binding_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_config_probe_binding + ADD CONSTRAINT muse_config_probe_binding_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_context_snapshot muse_context_snapshot_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_context_snapshot + ADD CONSTRAINT muse_context_snapshot_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_effect_assessment muse_effect_assessment_experiment_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_effect_assessment + ADD CONSTRAINT muse_effect_assessment_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment(experiment_id); + + +-- +-- Name: muse_evaluation_condition muse_evaluation_condition_unit_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_condition + ADD CONSTRAINT muse_evaluation_condition_unit_id_fkey FOREIGN KEY (unit_id) REFERENCES evaluation.muse_evaluation_unit(unit_id); + + +-- +-- Name: muse_evaluation_output muse_evaluation_output_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_output + ADD CONSTRAINT muse_evaluation_output_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_evaluation_output muse_evaluation_output_unit_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_output + ADD CONSTRAINT muse_evaluation_output_unit_id_fkey FOREIGN KEY (unit_id) REFERENCES evaluation.muse_evaluation_unit(unit_id); + + +-- +-- Name: muse_evaluation_reuse muse_evaluation_reuse_source_experiment_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_reuse + ADD CONSTRAINT muse_evaluation_reuse_source_experiment_id_fkey FOREIGN KEY (source_experiment_id) REFERENCES evaluation.muse_experiment(experiment_id); + + +-- +-- Name: muse_evaluation_reuse muse_evaluation_reuse_source_unit_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_reuse + ADD CONSTRAINT muse_evaluation_reuse_source_unit_id_fkey FOREIGN KEY (source_unit_id) REFERENCES evaluation.muse_evaluation_unit(unit_id); + + +-- +-- Name: muse_evaluation_reuse muse_evaluation_reuse_unit_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_reuse + ADD CONSTRAINT muse_evaluation_reuse_unit_id_fkey FOREIGN KEY (unit_id) REFERENCES evaluation.muse_evaluation_unit(unit_id); + + +-- +-- Name: muse_evaluation_unit muse_evaluation_unit_experiment_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_unit + ADD CONSTRAINT muse_evaluation_unit_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment_execution(experiment_id); + + +-- +-- Name: muse_evaluation_unit muse_evaluation_unit_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_evaluation_unit + ADD CONSTRAINT muse_evaluation_unit_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_experiment muse_experiment_dataset_version_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_experiment + ADD CONSTRAINT muse_experiment_dataset_version_id_fkey FOREIGN KEY (dataset_version_id) REFERENCES evaluation.muse_dataset_version(version_id); + + +-- +-- Name: muse_experiment_execution muse_experiment_execution_experiment_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_experiment_execution + ADD CONSTRAINT muse_experiment_execution_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment(experiment_id); + + +-- +-- Name: muse_experiment_stop muse_experiment_stop_experiment_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_experiment_stop + ADD CONSTRAINT muse_experiment_stop_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment_execution(experiment_id); + + +-- +-- Name: muse_model_delivery muse_model_delivery_attempt_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_model_delivery + ADD CONSTRAINT muse_model_delivery_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES evaluation.muse_attempt(attempt_id); + + +-- +-- Name: muse_model_delivery muse_model_delivery_response_evidence_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_model_delivery + ADD CONSTRAINT muse_model_delivery_response_evidence_id_fkey FOREIGN KEY (response_evidence_id) REFERENCES evaluation.muse_runtime_evidence(evidence_id); + + +-- +-- Name: muse_model_delivery muse_model_delivery_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_model_delivery + ADD CONSTRAINT muse_model_delivery_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_raw_archive muse_raw_archive_authorization_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_authorization_id_fkey FOREIGN KEY (authorization_id) REFERENCES evaluation.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_raw_archive_item muse_raw_archive_item_archive_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_archive_item + ADD CONSTRAINT muse_raw_archive_item_archive_id_fkey FOREIGN KEY (archive_id) REFERENCES evaluation.muse_raw_archive(archive_id); + + +-- +-- Name: muse_raw_archive muse_raw_archive_lease_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_lease_id_fkey FOREIGN KEY (lease_id) REFERENCES evaluation.muse_raw_lease(lease_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_attempt_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES evaluation.muse_attempt(attempt_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_parent_authorization_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_parent_authorization_id_fkey FOREIGN KEY (parent_authorization_id) REFERENCES evaluation.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_archive_authorization_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_archive_authorization_id_fkey FOREIGN KEY (archive_authorization_id) REFERENCES evaluation.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_authorization_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_authorization_id_fkey FOREIGN KEY (authorization_id) REFERENCES evaluation.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_role_session_authorization muse_role_session_authorization_authorization_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_role_session_authorization + ADD CONSTRAINT muse_role_session_authorization_authorization_id_fkey FOREIGN KEY (authorization_id) REFERENCES evaluation.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_rule_diagnostic_assessment muse_rule_diagnostic_assessment_run_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_assessment + ADD CONSTRAINT muse_rule_diagnostic_assessment_run_id_fkey FOREIGN KEY (run_id) REFERENCES evaluation.muse_rule_diagnostic_run(run_id); + + +-- +-- Name: muse_rule_diagnostic_result muse_rule_diagnostic_result_run_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_result + ADD CONSTRAINT muse_rule_diagnostic_result_run_id_fkey FOREIGN KEY (run_id) REFERENCES evaluation.muse_rule_diagnostic_run(run_id); + + +-- +-- Name: muse_rule_diagnostic_run muse_rule_diagnostic_run_dataset_version_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_run + ADD CONSTRAINT muse_rule_diagnostic_run_dataset_version_id_fkey FOREIGN KEY (dataset_version_id) REFERENCES evaluation.muse_dataset_version(version_id); + + +-- +-- Name: muse_rule_diagnostic_stop muse_rule_diagnostic_stop_run_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_rule_diagnostic_stop + ADD CONSTRAINT muse_rule_diagnostic_stop_run_id_fkey FOREIGN KEY (run_id) REFERENCES evaluation.muse_rule_diagnostic_run(run_id); + + +-- +-- Name: muse_runtime_config_active muse_runtime_config_active_validation_receipt_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_config_active + ADD CONSTRAINT muse_runtime_config_active_validation_receipt_fkey FOREIGN KEY (validation_receipt) REFERENCES evaluation.muse_runtime_config_validation(receipt_id); + + +-- +-- Name: muse_runtime_config_validation muse_runtime_config_validatio_run_purpose_config_id_versio_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_config_validation + ADD CONSTRAINT muse_runtime_config_validatio_run_purpose_config_id_versio_fkey FOREIGN KEY (run_purpose, config_id, version) REFERENCES evaluation.muse_runtime_config_version(run_purpose, config_id, version); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_attempt_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES evaluation.muse_attempt(attempt_id); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_authorization_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_authorization_id_fkey FOREIGN KEY (authorization_id) REFERENCES evaluation.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_step muse_step_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_step + ADD CONSTRAINT muse_step_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_task_budget muse_task_budget_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_budget + ADD CONSTRAINT muse_task_budget_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_task_config_binding muse_task_config_binding_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_config_binding + ADD CONSTRAINT muse_task_config_binding_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_task_config_binding muse_task_config_binding_validation_receipt_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_config_binding + ADD CONSTRAINT muse_task_config_binding_validation_receipt_fkey FOREIGN KEY (validation_receipt) REFERENCES evaluation.muse_runtime_config_validation(receipt_id); + + +-- +-- Name: muse_task_control muse_task_control_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_control + ADD CONSTRAINT muse_task_control_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: muse_task_event muse_task_event_task_id_fkey; Type: FK CONSTRAINT; Schema: evaluation; Owner: muse_maint +-- + +ALTER TABLE ONLY evaluation.muse_task_event + ADD CONSTRAINT muse_task_event_task_id_fkey FOREIGN KEY (task_id) REFERENCES evaluation.muse_task(task_id); + + +-- +-- Name: policy_version policy_version_type_id_fkey; Type: FK CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.policy_version + ADD CONSTRAINT policy_version_type_id_fkey FOREIGN KEY (type_id) REFERENCES metadata.type_registry(type_id); + + +-- +-- Name: schema_binding schema_binding_schema_id_base_version_fkey; Type: FK CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.schema_binding + ADD CONSTRAINT schema_binding_schema_id_base_version_fkey FOREIGN KEY (schema_id, base_version) REFERENCES metadata.schema_version(schema_id, schema_version); + + +-- +-- Name: schema_binding schema_binding_type_id_fkey; Type: FK CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.schema_binding + ADD CONSTRAINT schema_binding_type_id_fkey FOREIGN KEY (type_id) REFERENCES metadata.type_registry(type_id); + + +-- +-- Name: schema_binding schema_binding_work_id_schema_id_base_version_extension_ve_fkey; Type: FK CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.schema_binding + ADD CONSTRAINT schema_binding_work_id_schema_id_base_version_extension_ve_fkey FOREIGN KEY (work_id, schema_id, base_version, extension_version) REFERENCES metadata.work_extension(work_id, schema_id, base_version, extension_version); + + +-- +-- Name: schema_version schema_version_type_id_fkey; Type: FK CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.schema_version + ADD CONSTRAINT schema_version_type_id_fkey FOREIGN KEY (type_id) REFERENCES metadata.type_registry(type_id); + + +-- +-- Name: work_extension work_extension_schema_id_base_version_fkey; Type: FK CONSTRAINT; Schema: metadata; Owner: muse_maint +-- + +ALTER TABLE ONLY metadata.work_extension + ADD CONSTRAINT work_extension_schema_id_base_version_fkey FOREIGN KEY (schema_id, base_version) REFERENCES metadata.schema_version(schema_id, schema_version); + + +-- +-- Name: muse_blind_assignment muse_blind_assignment_experiment_id_fkey; Type: FK CONSTRAINT; Schema: oracle; Owner: muse_maint +-- + +ALTER TABLE ONLY oracle.muse_blind_assignment + ADD CONSTRAINT muse_blind_assignment_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment(experiment_id); + + +-- +-- Name: muse_calibration_gold muse_calibration_gold_experiment_id_fkey; Type: FK CONSTRAINT; Schema: oracle; Owner: muse_maint +-- + +ALTER TABLE ONLY oracle.muse_calibration_gold + ADD CONSTRAINT muse_calibration_gold_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment(experiment_id); + + +-- +-- Name: muse_dataset_answers muse_dataset_answers_version_id_fkey; Type: FK CONSTRAINT; Schema: oracle; Owner: muse_maint +-- + +ALTER TABLE ONLY oracle.muse_dataset_answers + ADD CONSTRAINT muse_dataset_answers_version_id_fkey FOREIGN KEY (version_id) REFERENCES evaluation.muse_dataset_version(version_id); + + +-- +-- Name: muse_document document_current_version_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document + ADD CONSTRAINT document_current_version_fk FOREIGN KEY (document_id, current_revision) REFERENCES public.muse_document_version(document_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_fact_proposal fact_proposal_current_version_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_fact_proposal + ADD CONSTRAINT fact_proposal_current_version_fk FOREIGN KEY (proposal_id, current_revision) REFERENCES public.muse_fact_proposal_version(proposal_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_attempt muse_attempt_task_id_step_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_attempt + ADD CONSTRAINT muse_attempt_task_id_step_id_fkey FOREIGN KEY (task_id, step_id) REFERENCES public.muse_step(task_id, step_id); + + +-- +-- Name: muse_author_observation muse_author_observation_improvement_id_improvement_revisio_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_author_observation + ADD CONSTRAINT muse_author_observation_improvement_id_improvement_revisio_fkey FOREIGN KEY (improvement_id, improvement_revision) REFERENCES public.muse_improvement_version(improvement_id, revision); + + +-- +-- Name: muse_branch_merge_source muse_branch_merge_source_candidate_id_candidate_revision_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_branch_merge_source + ADD CONSTRAINT muse_branch_merge_source_candidate_id_candidate_revision_fkey FOREIGN KEY (candidate_id, candidate_revision) REFERENCES public.muse_writing_candidate_version(candidate_id, revision); + + +-- +-- Name: muse_branch_merge_source muse_branch_merge_source_source_document_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_branch_merge_source + ADD CONSTRAINT muse_branch_merge_source_source_document_id_fkey FOREIGN KEY (source_document_id) REFERENCES public.muse_document_branch(document_id); + + +-- +-- Name: muse_branch_merge_source muse_branch_merge_source_source_document_id_source_revisio_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_branch_merge_source + ADD CONSTRAINT muse_branch_merge_source_source_document_id_source_revisio_fkey FOREIGN KEY (source_document_id, source_revision) REFERENCES public.muse_document_version(document_id, revision); + + +-- +-- Name: muse_budget_reservation muse_budget_reservation_attempt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_budget_reservation + ADD CONSTRAINT muse_budget_reservation_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES public.muse_attempt(attempt_id); + + +-- +-- Name: muse_budget_reservation muse_budget_reservation_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_budget_reservation + ADD CONSTRAINT muse_budget_reservation_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_call_reconciliation muse_call_reconciliation_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_call_reconciliation + ADD CONSTRAINT muse_call_reconciliation_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_call_settlement muse_call_settlement_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_call_settlement + ADD CONSTRAINT muse_call_settlement_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_candidate_decision muse_candidate_decision_review_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_candidate_decision + ADD CONSTRAINT muse_candidate_decision_review_id_fkey FOREIGN KEY (review_id) REFERENCES public.muse_author_review(review_id); + + +-- +-- Name: muse_chapter muse_chapter_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_chapter + ADD CONSTRAINT muse_chapter_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_clean_candidate muse_clean_candidate_source_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_clean_candidate + ADD CONSTRAINT muse_clean_candidate_source_id_fkey FOREIGN KEY (source_id) REFERENCES public.muse_source(source_id); + + +-- +-- Name: muse_clean_candidate muse_clean_candidate_source_id_revision_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_clean_candidate + ADD CONSTRAINT muse_clean_candidate_source_id_revision_fkey FOREIGN KEY (source_id, revision) REFERENCES public.muse_source_version(source_id, revision); + + +-- +-- Name: muse_config_probe_binding muse_config_probe_binding_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_config_probe_binding + ADD CONSTRAINT muse_config_probe_binding_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_context_snapshot muse_context_snapshot_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_context_snapshot + ADD CONSTRAINT muse_context_snapshot_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_delivery_artifact muse_delivery_artifact_delivery_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery_artifact + ADD CONSTRAINT muse_delivery_artifact_delivery_id_fkey FOREIGN KEY (delivery_id) REFERENCES public.muse_delivery(delivery_id); + + +-- +-- Name: muse_delivery_artifact_validation muse_delivery_artifact_validation_artifact_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery_artifact_validation + ADD CONSTRAINT muse_delivery_artifact_validation_artifact_id_fkey FOREIGN KEY (artifact_id) REFERENCES public.muse_delivery_artifact(artifact_id); + + +-- +-- Name: muse_delivery muse_delivery_work_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_delivery + ADD CONSTRAINT muse_delivery_work_fk FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_diagnosis muse_diagnosis_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_diagnosis + ADD CONSTRAINT muse_diagnosis_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_directory_version muse_directory_version_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_directory_version + ADD CONSTRAINT muse_directory_version_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_document_branch muse_document_branch_document_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document_branch + ADD CONSTRAINT muse_document_branch_document_id_fkey FOREIGN KEY (document_id) REFERENCES public.muse_document(document_id); + + +-- +-- Name: muse_document_branch muse_document_branch_source_document_id_source_revision_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document_branch + ADD CONSTRAINT muse_document_branch_source_document_id_source_revision_fkey FOREIGN KEY (source_document_id, source_revision) REFERENCES public.muse_document_version(document_id, revision); + + +-- +-- Name: muse_document muse_document_chapter_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document + ADD CONSTRAINT muse_document_chapter_id_fkey FOREIGN KEY (chapter_id) REFERENCES public.muse_chapter(chapter_id); + + +-- +-- Name: muse_document_version muse_document_version_document_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document_version + ADD CONSTRAINT muse_document_version_document_id_fkey FOREIGN KEY (document_id) REFERENCES public.muse_document(document_id); + + +-- +-- Name: muse_document_version muse_document_version_document_id_restored_from_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_document_version + ADD CONSTRAINT muse_document_version_document_id_restored_from_fkey FOREIGN KEY (document_id, restored_from) REFERENCES public.muse_document_version(document_id, revision); + + +-- +-- Name: muse_enablement_receipt muse_enablement_receipt_experiment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_enablement_receipt + ADD CONSTRAINT muse_enablement_receipt_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment(experiment_id); + + +-- +-- Name: muse_exploration_selection_version muse_exploration_selection_version_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_exploration_selection_version + ADD CONSTRAINT muse_exploration_selection_version_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_exploration_selection muse_exploration_selection_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_exploration_selection + ADD CONSTRAINT muse_exploration_selection_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_fact_proposal_version muse_fact_proposal_version_proposal_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_fact_proposal_version + ADD CONSTRAINT muse_fact_proposal_version_proposal_id_fkey FOREIGN KEY (proposal_id) REFERENCES public.muse_fact_proposal(proposal_id); + + +-- +-- Name: muse_fact_proposal muse_fact_proposal_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_fact_proposal + ADD CONSTRAINT muse_fact_proposal_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_reader_feedback muse_feedback_release_work_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_reader_feedback + ADD CONSTRAINT muse_feedback_release_work_fk FOREIGN KEY (release_id, work_id) REFERENCES public.muse_release(release_id, work_id); + + +-- +-- Name: muse_reader_feedback muse_feedback_work_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_reader_feedback + ADD CONSTRAINT muse_feedback_work_fk FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_improvement_action muse_improvement_action_improvement_id_revision_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_improvement_action + ADD CONSTRAINT muse_improvement_action_improvement_id_revision_fkey FOREIGN KEY (improvement_id, revision) REFERENCES public.muse_improvement_version(improvement_id, revision); + + +-- +-- Name: muse_improvement_result muse_improvement_result_action_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_improvement_result + ADD CONSTRAINT muse_improvement_result_action_id_fkey FOREIGN KEY (action_id) REFERENCES public.muse_improvement_action(action_id); + + +-- +-- Name: muse_improvement_version muse_improvement_version_improvement_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_improvement_version + ADD CONSTRAINT muse_improvement_version_improvement_id_fkey FOREIGN KEY (improvement_id) REFERENCES public.muse_improvement(improvement_id); + + +-- +-- Name: muse_literary_report muse_literary_report_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_literary_report + ADD CONSTRAINT muse_literary_report_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_literary_shard muse_literary_shard_attempt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_literary_shard + ADD CONSTRAINT muse_literary_shard_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES public.muse_attempt(attempt_id); + + +-- +-- Name: muse_literary_shard muse_literary_shard_snapshot_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_literary_shard + ADD CONSTRAINT muse_literary_shard_snapshot_id_fkey FOREIGN KEY (snapshot_id) REFERENCES public.muse_context_snapshot(snapshot_id); + + +-- +-- Name: muse_literary_shard muse_literary_shard_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_literary_shard + ADD CONSTRAINT muse_literary_shard_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_method_binding muse_method_binding_method_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_binding + ADD CONSTRAINT muse_method_binding_method_id_fkey FOREIGN KEY (method_id) REFERENCES public.muse_method(method_id); + + +-- +-- Name: muse_method_binding muse_method_binding_version_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_binding + ADD CONSTRAINT muse_method_binding_version_id_fkey FOREIGN KEY (version_id) REFERENCES public.muse_method_version(version_id); + + +-- +-- Name: muse_method_evidence muse_method_evidence_method_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_evidence + ADD CONSTRAINT muse_method_evidence_method_id_fkey FOREIGN KEY (method_id) REFERENCES public.muse_method(method_id); + + +-- +-- Name: muse_method_index muse_method_index_method_version_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_index + ADD CONSTRAINT muse_method_index_method_version_id_fkey FOREIGN KEY (method_version_id) REFERENCES public.muse_method_version(version_id); + + +-- +-- Name: muse_method_usage muse_method_usage_method_version_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_usage + ADD CONSTRAINT muse_method_usage_method_version_id_fkey FOREIGN KEY (method_version_id) REFERENCES public.muse_method_version(version_id); + + +-- +-- Name: muse_method_version muse_method_version_method_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_method_version + ADD CONSTRAINT muse_method_version_method_id_fkey FOREIGN KEY (method_id) REFERENCES public.muse_method(method_id); + + +-- +-- Name: muse_model_candidate muse_model_candidate_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_candidate + ADD CONSTRAINT muse_model_candidate_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_writing_candidate(candidate_id); + + +-- +-- Name: muse_model_candidate muse_model_candidate_snapshot_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_candidate + ADD CONSTRAINT muse_model_candidate_snapshot_id_fkey FOREIGN KEY (snapshot_id) REFERENCES public.muse_context_snapshot(snapshot_id); + + +-- +-- Name: muse_model_candidate muse_model_candidate_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_candidate + ADD CONSTRAINT muse_model_candidate_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_model_delivery muse_model_delivery_attempt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_delivery + ADD CONSTRAINT muse_model_delivery_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES public.muse_attempt(attempt_id); + + +-- +-- Name: muse_model_delivery muse_model_delivery_response_evidence_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_delivery + ADD CONSTRAINT muse_model_delivery_response_evidence_id_fkey FOREIGN KEY (response_evidence_id) REFERENCES public.muse_runtime_evidence(evidence_id); + + +-- +-- Name: muse_model_delivery muse_model_delivery_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_delivery + ADD CONSTRAINT muse_model_delivery_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_model_plan_candidate muse_model_plan_candidate_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_plan_candidate + ADD CONSTRAINT muse_model_plan_candidate_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_plan_candidate(candidate_id); + + +-- +-- Name: muse_model_plan_candidate muse_model_plan_candidate_snapshot_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_plan_candidate + ADD CONSTRAINT muse_model_plan_candidate_snapshot_id_fkey FOREIGN KEY (snapshot_id) REFERENCES public.muse_context_snapshot(snapshot_id); + + +-- +-- Name: muse_model_plan_candidate muse_model_plan_candidate_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_model_plan_candidate + ADD CONSTRAINT muse_model_plan_candidate_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_plan_candidate_version muse_plan_candidate_version_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan_candidate_version + ADD CONSTRAINT muse_plan_candidate_version_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_plan_candidate(candidate_id); + + +-- +-- Name: muse_plan_candidate muse_plan_candidate_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan_candidate + ADD CONSTRAINT muse_plan_candidate_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_plan muse_plan_chapter_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan + ADD CONSTRAINT muse_plan_chapter_id_fkey FOREIGN KEY (chapter_id) REFERENCES public.muse_chapter(chapter_id); + + +-- +-- Name: muse_plan_version muse_plan_version_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan_version + ADD CONSTRAINT muse_plan_version_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.muse_plan(plan_id); + + +-- +-- Name: muse_plan muse_plan_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan + ADD CONSTRAINT muse_plan_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_preference_version muse_preference_version_preference_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_preference_version + ADD CONSTRAINT muse_preference_version_preference_id_fkey FOREIGN KEY (preference_id) REFERENCES public.muse_preference(preference_id); + + +-- +-- Name: muse_quality_case_version muse_quality_case_version_case_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_quality_case_version + ADD CONSTRAINT muse_quality_case_version_case_id_fkey FOREIGN KEY (case_id) REFERENCES public.muse_quality_case(case_id); + + +-- +-- Name: muse_ranking_snapshot muse_ranking_snapshot_ranking_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_ranking_snapshot + ADD CONSTRAINT muse_ranking_snapshot_ranking_id_fkey FOREIGN KEY (ranking_id) REFERENCES public.muse_ranking_source(ranking_id); + + +-- +-- Name: muse_raw_archive muse_raw_archive_authorization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_authorization_id_fkey FOREIGN KEY (authorization_id) REFERENCES public.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_raw_archive_item muse_raw_archive_item_archive_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_archive_item + ADD CONSTRAINT muse_raw_archive_item_archive_id_fkey FOREIGN KEY (archive_id) REFERENCES public.muse_raw_archive(archive_id); + + +-- +-- Name: muse_raw_archive muse_raw_archive_lease_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_archive + ADD CONSTRAINT muse_raw_archive_lease_id_fkey FOREIGN KEY (lease_id) REFERENCES public.muse_raw_lease(lease_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_attempt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES public.muse_attempt(attempt_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_parent_authorization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_parent_authorization_id_fkey FOREIGN KEY (parent_authorization_id) REFERENCES public.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_raw_authorization muse_raw_authorization_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_authorization + ADD CONSTRAINT muse_raw_authorization_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_archive_authorization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_archive_authorization_id_fkey FOREIGN KEY (archive_authorization_id) REFERENCES public.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_authorization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_authorization_id_fkey FOREIGN KEY (authorization_id) REFERENCES public.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_raw_lease muse_raw_lease_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_raw_lease + ADD CONSTRAINT muse_raw_lease_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_reader_feedback muse_reader_feedback_release_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_reader_feedback + ADD CONSTRAINT muse_reader_feedback_release_id_fkey FOREIGN KEY (release_id) REFERENCES public.muse_release(release_id); + + +-- +-- Name: muse_release muse_release_delivery_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_release + ADD CONSTRAINT muse_release_delivery_id_fkey FOREIGN KEY (delivery_id) REFERENCES public.muse_delivery(delivery_id); + + +-- +-- Name: muse_release muse_release_delivery_work_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_release + ADD CONSTRAINT muse_release_delivery_work_fk FOREIGN KEY (delivery_id, work_id) REFERENCES public.muse_delivery(delivery_id, work_id); + + +-- +-- Name: muse_review_report muse_review_report_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_review_report + ADD CONSTRAINT muse_review_report_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_writing_candidate(candidate_id); + + +-- +-- Name: muse_review_report muse_review_report_snapshot_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_review_report + ADD CONSTRAINT muse_review_report_snapshot_id_fkey FOREIGN KEY (snapshot_id) REFERENCES public.muse_context_snapshot(snapshot_id); + + +-- +-- Name: muse_revision_comparison_receipt muse_revision_comparison_receipt_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_comparison_receipt + ADD CONSTRAINT muse_revision_comparison_receipt_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_writing_candidate(candidate_id); + + +-- +-- Name: muse_revision_comparison_receipt muse_revision_comparison_receipt_experiment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_comparison_receipt + ADD CONSTRAINT muse_revision_comparison_receipt_experiment_id_fkey FOREIGN KEY (experiment_id) REFERENCES evaluation.muse_experiment(experiment_id); + + +-- +-- Name: muse_revision_comparison_receipt muse_revision_comparison_receipt_session_id_author_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_comparison_receipt + ADD CONSTRAINT muse_revision_comparison_receipt_session_id_author_id_fkey FOREIGN KEY (session_id, author_id) REFERENCES public.muse_revision_session(session_id, author_id); + + +-- +-- Name: muse_revision_comparison_receipt muse_revision_comparison_receipt_session_id_round_number_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_comparison_receipt + ADD CONSTRAINT muse_revision_comparison_receipt_session_id_round_number_fkey FOREIGN KEY (session_id, round_number) REFERENCES public.muse_revision_round(session_id, round_number); + + +-- +-- Name: muse_revision_result muse_revision_result_attempt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_result + ADD CONSTRAINT muse_revision_result_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES public.muse_attempt(attempt_id); + + +-- +-- Name: muse_revision_result muse_revision_result_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_result + ADD CONSTRAINT muse_revision_result_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_writing_candidate(candidate_id); + + +-- +-- Name: muse_revision_result muse_revision_result_diagnosis_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_result + ADD CONSTRAINT muse_revision_result_diagnosis_id_fkey FOREIGN KEY (diagnosis_id) REFERENCES public.muse_diagnosis(diagnosis_id); + + +-- +-- Name: muse_revision_result muse_revision_result_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_result + ADD CONSTRAINT muse_revision_result_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_revision_round muse_revision_round_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_round + ADD CONSTRAINT muse_revision_round_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_writing_candidate(candidate_id); + + +-- +-- Name: muse_revision_round muse_revision_round_session_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_round + ADD CONSTRAINT muse_revision_round_session_id_fkey FOREIGN KEY (session_id) REFERENCES public.muse_revision_session(session_id); + + +-- +-- Name: muse_revision_round muse_revision_round_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_round + ADD CONSTRAINT muse_revision_round_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_revision_session_action muse_revision_session_action_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session_action + ADD CONSTRAINT muse_revision_session_action_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_writing_candidate(candidate_id); + + +-- +-- Name: muse_revision_session_action muse_revision_session_action_session_id_author_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session_action + ADD CONSTRAINT muse_revision_session_action_session_id_author_id_fkey FOREIGN KEY (session_id, author_id) REFERENCES public.muse_revision_session(session_id, author_id); + + +-- +-- Name: muse_revision_session_action muse_revision_session_action_session_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session_action + ADD CONSTRAINT muse_revision_session_action_session_id_fkey FOREIGN KEY (session_id) REFERENCES public.muse_revision_session(session_id); + + +-- +-- Name: muse_revision_session muse_revision_session_chapter_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session + ADD CONSTRAINT muse_revision_session_chapter_id_fkey FOREIGN KEY (chapter_id) REFERENCES public.muse_chapter(chapter_id); + + +-- +-- Name: muse_revision_session muse_revision_session_selected_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session + ADD CONSTRAINT muse_revision_session_selected_candidate_id_fkey FOREIGN KEY (selected_candidate_id) REFERENCES public.muse_writing_candidate(candidate_id); + + +-- +-- Name: muse_revision_session muse_revision_session_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_revision_session + ADD CONSTRAINT muse_revision_session_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_role_session_authorization muse_role_session_authorization_authorization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_role_session_authorization + ADD CONSTRAINT muse_role_session_authorization_authorization_id_fkey FOREIGN KEY (authorization_id) REFERENCES public.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_rule_activation_current muse_rule_activation_current_credential_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_current + ADD CONSTRAINT muse_rule_activation_current_credential_id_fkey FOREIGN KEY (credential_id) REFERENCES public.muse_rule_diagnostic_receipt(receipt_id); + + +-- +-- Name: muse_rule_activation_current muse_rule_activation_current_latest_event_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_current + ADD CONSTRAINT muse_rule_activation_current_latest_event_id_fkey FOREIGN KEY (latest_event_id) REFERENCES public.muse_rule_activation_event(event_id); + + +-- +-- Name: muse_rule_activation_current muse_rule_activation_current_version_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_current + ADD CONSTRAINT muse_rule_activation_current_version_id_fkey FOREIGN KEY (version_id) REFERENCES public.muse_rule_version(version_id); + + +-- +-- Name: muse_rule_activation_event muse_rule_activation_event_credential_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_event + ADD CONSTRAINT muse_rule_activation_event_credential_id_fkey FOREIGN KEY (credential_id) REFERENCES public.muse_rule_diagnostic_receipt(receipt_id); + + +-- +-- Name: muse_rule_activation_event muse_rule_activation_event_review_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_event + ADD CONSTRAINT muse_rule_activation_event_review_id_fkey FOREIGN KEY (review_id) REFERENCES public.muse_author_review(review_id); + + +-- +-- Name: muse_rule_activation_event muse_rule_activation_event_version_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation_event + ADD CONSTRAINT muse_rule_activation_event_version_id_fkey FOREIGN KEY (version_id) REFERENCES public.muse_rule_version(version_id); + + +-- +-- Name: muse_rule_activation muse_rule_activation_version_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_activation + ADD CONSTRAINT muse_rule_activation_version_id_fkey FOREIGN KEY (version_id) REFERENCES public.muse_rule_version(version_id); + + +-- +-- Name: muse_rule_diagnostic_receipt muse_rule_diagnostic_receipt_rule_version_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_diagnostic_receipt + ADD CONSTRAINT muse_rule_diagnostic_receipt_rule_version_id_fkey FOREIGN KEY (rule_version_id) REFERENCES public.muse_rule_version(version_id); + + +-- +-- Name: muse_rule_diagnostic_receipt muse_rule_diagnostic_receipt_run_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_rule_diagnostic_receipt + ADD CONSTRAINT muse_rule_diagnostic_receipt_run_id_fkey FOREIGN KEY (run_id) REFERENCES evaluation.muse_rule_diagnostic_run(run_id); + + +-- +-- Name: muse_run_observation_command muse_run_observation_command_observation_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_run_observation_command + ADD CONSTRAINT muse_run_observation_command_observation_id_fkey FOREIGN KEY (observation_id) REFERENCES public.muse_run_observation(observation_id); + + +-- +-- Name: muse_runtime_config_active muse_runtime_config_active_validation_receipt_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_config_active + ADD CONSTRAINT muse_runtime_config_active_validation_receipt_fkey FOREIGN KEY (validation_receipt) REFERENCES public.muse_runtime_config_validation(receipt_id); + + +-- +-- Name: muse_runtime_config_validation muse_runtime_config_validatio_run_purpose_config_id_versio_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_config_validation + ADD CONSTRAINT muse_runtime_config_validatio_run_purpose_config_id_versio_fkey FOREIGN KEY (run_purpose, config_id, version) REFERENCES public.muse_runtime_config_version(run_purpose, config_id, version); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_attempt_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_attempt_id_fkey FOREIGN KEY (attempt_id) REFERENCES public.muse_attempt(attempt_id); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_authorization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_authorization_id_fkey FOREIGN KEY (authorization_id) REFERENCES public.muse_raw_authorization(authorization_id); + + +-- +-- Name: muse_runtime_evidence muse_runtime_evidence_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_runtime_evidence + ADD CONSTRAINT muse_runtime_evidence_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_serial_plan_version muse_serial_plan_version_plan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_serial_plan_version + ADD CONSTRAINT muse_serial_plan_version_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES public.muse_serial_plan(plan_id); + + +-- +-- Name: muse_serial_plan muse_serial_work_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_serial_plan + ADD CONSTRAINT muse_serial_work_fk FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_source_analysis muse_source_analysis_source_id_source_revision_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_analysis + ADD CONSTRAINT muse_source_analysis_source_id_source_revision_fkey FOREIGN KEY (source_id, source_revision) REFERENCES public.muse_source_version(source_id, revision); + + +-- +-- Name: muse_source_slice_index muse_source_slice_index_slice_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_slice_index + ADD CONSTRAINT muse_source_slice_index_slice_id_fkey FOREIGN KEY (slice_id) REFERENCES public.muse_source_slice(slice_id) ON DELETE CASCADE; + + +-- +-- Name: muse_source_slice muse_source_slice_source_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_slice + ADD CONSTRAINT muse_source_slice_source_id_fkey FOREIGN KEY (source_id) REFERENCES public.muse_source(source_id); + + +-- +-- Name: muse_source_version muse_source_version_source_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_source_version + ADD CONSTRAINT muse_source_version_source_id_fkey FOREIGN KEY (source_id) REFERENCES public.muse_source(source_id); + + +-- +-- Name: muse_step muse_step_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_step + ADD CONSTRAINT muse_step_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_task_budget muse_task_budget_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_budget + ADD CONSTRAINT muse_task_budget_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_task_config_binding muse_task_config_binding_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_config_binding + ADD CONSTRAINT muse_task_config_binding_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_task_config_binding muse_task_config_binding_validation_receipt_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_config_binding + ADD CONSTRAINT muse_task_config_binding_validation_receipt_fkey FOREIGN KEY (validation_receipt) REFERENCES public.muse_runtime_config_validation(receipt_id); + + +-- +-- Name: muse_task_control muse_task_control_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_control + ADD CONSTRAINT muse_task_control_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_task_event muse_task_event_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_task_event + ADD CONSTRAINT muse_task_event_task_id_fkey FOREIGN KEY (task_id) REFERENCES public.muse_task(task_id); + + +-- +-- Name: muse_voice_current muse_voice_current_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_current + ADD CONSTRAINT muse_voice_current_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_voice_current muse_voice_current_work_id_version_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_current + ADD CONSTRAINT muse_voice_current_work_id_version_id_fkey FOREIGN KEY (work_id, version_id) REFERENCES public.muse_voice_version(work_id, version_id); + + +-- +-- Name: muse_voice_proposal muse_voice_proposal_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_proposal + ADD CONSTRAINT muse_voice_proposal_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_voice_version muse_voice_version_proposal_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_version + ADD CONSTRAINT muse_voice_version_proposal_id_fkey FOREIGN KEY (proposal_id) REFERENCES public.muse_voice_proposal(proposal_id); + + +-- +-- Name: muse_voice_version muse_voice_version_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_voice_version + ADD CONSTRAINT muse_voice_version_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_work_version muse_work_version_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_work_version + ADD CONSTRAINT muse_work_version_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_world_clock muse_world_clock_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_world_clock + ADD CONSTRAINT muse_world_clock_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_world_object muse_world_object_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_world_object + ADD CONSTRAINT muse_world_object_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.muse_work(work_id); + + +-- +-- Name: muse_world_version muse_world_version_effective_from_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_world_version + ADD CONSTRAINT muse_world_version_effective_from_fkey FOREIGN KEY (effective_from) REFERENCES public.muse_chapter(chapter_id); + + +-- +-- Name: muse_world_version muse_world_version_object_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_world_version + ADD CONSTRAINT muse_world_version_object_id_fkey FOREIGN KEY (object_id) REFERENCES public.muse_world_object(object_id); + + +-- +-- Name: muse_writing_candidate muse_writing_candidate_chapter_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_writing_candidate + ADD CONSTRAINT muse_writing_candidate_chapter_id_fkey FOREIGN KEY (chapter_id) REFERENCES public.muse_chapter(chapter_id); + + +-- +-- Name: muse_writing_candidate_version muse_writing_candidate_version_candidate_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_writing_candidate_version + ADD CONSTRAINT muse_writing_candidate_version_candidate_id_fkey FOREIGN KEY (candidate_id) REFERENCES public.muse_writing_candidate(candidate_id); + + +-- +-- Name: muse_plan_candidate plan_candidate_current_version_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan_candidate + ADD CONSTRAINT plan_candidate_current_version_fk FOREIGN KEY (candidate_id, current_revision) REFERENCES public.muse_plan_candidate_version(candidate_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_plan plan_current_version_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_plan + ADD CONSTRAINT plan_current_version_fk FOREIGN KEY (plan_id, current_revision) REFERENCES public.muse_plan_version(plan_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_quality_case quality_case_current_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_quality_case + ADD CONSTRAINT quality_case_current_fk FOREIGN KEY (case_id, current_revision) REFERENCES public.muse_quality_case_version(case_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_exploration_selection selection_current_version_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_exploration_selection + ADD CONSTRAINT selection_current_version_fk FOREIGN KEY (work_id, current_revision) REFERENCES public.muse_exploration_selection_version(work_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_work work_current_directory_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_work + ADD CONSTRAINT work_current_directory_fk FOREIGN KEY (work_id, directory_revision) REFERENCES public.muse_directory_version(work_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_work work_current_version_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_work + ADD CONSTRAINT work_current_version_fk FOREIGN KEY (work_id, current_revision) REFERENCES public.muse_work_version(work_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_world_object world_current_version_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_world_object + ADD CONSTRAINT world_current_version_fk FOREIGN KEY (object_id, current_revision) REFERENCES public.muse_world_version(object_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: muse_writing_candidate writing_candidate_version_fk; Type: FK CONSTRAINT; Schema: public; Owner: muse_maint +-- + +ALTER TABLE ONLY public.muse_writing_candidate + ADD CONSTRAINT writing_candidate_version_fk FOREIGN KEY (candidate_id, current_revision) REFERENCES public.muse_writing_candidate_version(candidate_id, revision) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: SCHEMA evaluation; Type: ACL; Schema: -; Owner: muse_maint +-- + +GRANT USAGE ON SCHEMA evaluation TO muse_eval; + + +-- +-- Name: SCHEMA metadata; Type: ACL; Schema: -; Owner: muse_maint +-- + +GRANT USAGE ON SCHEMA metadata TO muse_app; +GRANT USAGE ON SCHEMA metadata TO muse_eval; + + +-- +-- Name: SCHEMA oracle; Type: ACL; Schema: -; Owner: muse_maint +-- + +GRANT USAGE ON SCHEMA oracle TO muse_eval; + + +-- +-- Name: SCHEMA public; Type: ACL; Schema: -; Owner: qingse +-- + + + +-- +-- Name: FUNCTION muse_method_index_changed(); Type: ACL; Schema: public; Owner: muse_maint +-- + +REVOKE ALL ON FUNCTION public.muse_method_index_changed() FROM PUBLIC; + + +-- +-- Name: FUNCTION muse_source_slice_changed(); Type: ACL; Schema: public; Owner: muse_maint +-- + +REVOKE ALL ON FUNCTION public.muse_source_slice_changed() FROM PUBLIC; + + +-- +-- Name: TABLE muse_attempt; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_attempt TO muse_eval; + + +-- +-- Name: TABLE muse_budget_account; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_budget_account TO muse_eval; + + +-- +-- Name: TABLE muse_budget_reservation; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_budget_reservation TO muse_eval; + + +-- +-- Name: TABLE muse_calibration_receipt; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_calibration_receipt TO muse_eval; + + +-- +-- Name: TABLE muse_call_reconciliation; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_call_reconciliation TO muse_eval; + + +-- +-- Name: TABLE muse_call_settlement; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_call_settlement TO muse_eval; + + +-- +-- Name: TABLE muse_comparison_rejection; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_comparison_rejection TO muse_eval; + + +-- +-- Name: TABLE muse_config_probe_binding; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_config_probe_binding TO muse_eval; + + +-- +-- Name: TABLE muse_context_snapshot; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_context_snapshot TO muse_eval; + + +-- +-- Name: TABLE muse_dataset_version; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT ON TABLE evaluation.muse_dataset_version TO muse_eval; + + +-- +-- Name: TABLE muse_effect_assessment; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_effect_assessment TO muse_eval; + + +-- +-- Name: TABLE muse_evaluation_condition; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_evaluation_condition TO muse_eval; + + +-- +-- Name: TABLE muse_evaluation_output; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_evaluation_output TO muse_eval; + + +-- +-- Name: TABLE muse_evaluation_reuse; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_evaluation_reuse TO muse_eval; + + +-- +-- Name: TABLE muse_evaluation_unit; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_evaluation_unit TO muse_eval; + + +-- +-- Name: TABLE muse_experiment; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_experiment TO muse_eval; + + +-- +-- Name: TABLE muse_experiment_execution; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_experiment_execution TO muse_eval; + + +-- +-- Name: TABLE muse_experiment_stop; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_experiment_stop TO muse_eval; + + +-- +-- Name: TABLE muse_flow_version; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_flow_version TO muse_eval; + + +-- +-- Name: TABLE muse_model_delivery; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_model_delivery TO muse_eval; + + +-- +-- Name: TABLE muse_raw_archive; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_raw_archive TO muse_eval; + + +-- +-- Name: TABLE muse_raw_archive_item; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_raw_archive_item TO muse_eval; + + +-- +-- Name: TABLE muse_raw_authorization; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_raw_authorization TO muse_eval; + + +-- +-- Name: TABLE muse_raw_lease; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_raw_lease TO muse_eval; + + +-- +-- Name: TABLE muse_raw_namespace; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT ON TABLE evaluation.muse_raw_namespace TO muse_eval; + + +-- +-- Name: TABLE muse_raw_orphan_cleanup; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_raw_orphan_cleanup TO muse_eval; + + +-- +-- Name: TABLE muse_role_session_authorization; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_role_session_authorization TO muse_eval; + + +-- +-- Name: TABLE muse_rule_diagnostic_assessment; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_rule_diagnostic_assessment TO muse_eval; + + +-- +-- Name: TABLE muse_rule_diagnostic_result; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_rule_diagnostic_result TO muse_eval; + + +-- +-- Name: TABLE muse_rule_diagnostic_run; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_rule_diagnostic_run TO muse_eval; + + +-- +-- Name: TABLE muse_rule_diagnostic_stop; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_rule_diagnostic_stop TO muse_eval; + + +-- +-- Name: TABLE muse_runtime_config_active; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_runtime_config_active TO muse_eval; + + +-- +-- Name: TABLE muse_runtime_config_validation; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_runtime_config_validation TO muse_eval; + + +-- +-- Name: TABLE muse_runtime_config_version; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_runtime_config_version TO muse_eval; + + +-- +-- Name: TABLE muse_runtime_evidence; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_runtime_evidence TO muse_eval; + + +-- +-- Name: TABLE muse_step; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_step TO muse_eval; + + +-- +-- Name: TABLE muse_task; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_task TO muse_eval; + + +-- +-- Name: TABLE muse_task_budget; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_task_budget TO muse_eval; + + +-- +-- Name: TABLE muse_task_config_binding; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_task_config_binding TO muse_eval; + + +-- +-- Name: TABLE muse_task_control; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_task_control TO muse_eval; + + +-- +-- Name: TABLE muse_task_event; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_task_event TO muse_eval; + + +-- +-- Name: TABLE muse_task_inventory; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT ON TABLE evaluation.muse_task_inventory TO muse_eval; + + +-- +-- Name: TABLE muse_task_scope_lease; Type: ACL; Schema: evaluation; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE evaluation.muse_task_scope_lease TO muse_eval; + + +-- +-- Name: TABLE activation_receipt; Type: ACL; Schema: metadata; Owner: muse_maint +-- + +GRANT SELECT,INSERT,UPDATE ON TABLE metadata.activation_receipt TO muse_app; +GRANT SELECT ON TABLE metadata.activation_receipt TO muse_eval; + + +-- +-- Name: TABLE policy_version; Type: ACL; Schema: metadata; Owner: muse_maint +-- + +GRANT SELECT,INSERT,UPDATE ON TABLE metadata.policy_version TO muse_app; +GRANT SELECT ON TABLE metadata.policy_version TO muse_eval; + + +-- +-- Name: TABLE schema_binding; Type: ACL; Schema: metadata; Owner: muse_maint +-- + +GRANT SELECT,INSERT,UPDATE ON TABLE metadata.schema_binding TO muse_app; +GRANT SELECT ON TABLE metadata.schema_binding TO muse_eval; + + +-- +-- Name: TABLE schema_version; Type: ACL; Schema: metadata; Owner: muse_maint +-- + +GRANT SELECT,INSERT,UPDATE ON TABLE metadata.schema_version TO muse_app; +GRANT SELECT ON TABLE metadata.schema_version TO muse_eval; + + +-- +-- Name: TABLE type_registry; Type: ACL; Schema: metadata; Owner: muse_maint +-- + +GRANT SELECT,INSERT,UPDATE ON TABLE metadata.type_registry TO muse_app; +GRANT SELECT ON TABLE metadata.type_registry TO muse_eval; + + +-- +-- Name: TABLE work_extension; Type: ACL; Schema: metadata; Owner: muse_maint +-- + +GRANT SELECT,INSERT,UPDATE ON TABLE metadata.work_extension TO muse_app; +GRANT SELECT ON TABLE metadata.work_extension TO muse_eval; + + +-- +-- Name: TABLE muse_blind_assignment; Type: ACL; Schema: oracle; Owner: muse_maint +-- + +GRANT SELECT,INSERT ON TABLE oracle.muse_blind_assignment TO muse_eval; + + +-- +-- Name: TABLE muse_calibration_gold; Type: ACL; Schema: oracle; Owner: muse_maint +-- + +GRANT SELECT ON TABLE oracle.muse_calibration_gold TO muse_eval; + + +-- +-- Name: TABLE muse_dataset_answers; Type: ACL; Schema: oracle; Owner: muse_maint +-- + +GRANT SELECT ON TABLE oracle.muse_dataset_answers TO muse_eval; + + +-- +-- Name: TABLE muse_attempt; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_attempt TO muse_app; + + +-- +-- Name: TABLE muse_author_feedback; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_author_feedback TO muse_app; + + +-- +-- Name: TABLE muse_author_observation; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_author_observation TO muse_app; + + +-- +-- Name: TABLE muse_author_review; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_author_review TO muse_app; + + +-- +-- Name: TABLE muse_branch_merge_source; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_branch_merge_source TO muse_app; + + +-- +-- Name: TABLE muse_budget_account; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_budget_account TO muse_app; + + +-- +-- Name: TABLE muse_budget_reservation; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_budget_reservation TO muse_app; + + +-- +-- Name: TABLE muse_call_reconciliation; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_call_reconciliation TO muse_app; + + +-- +-- Name: TABLE muse_call_settlement; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_call_settlement TO muse_app; + + +-- +-- Name: TABLE muse_candidate_decision; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_candidate_decision TO muse_app; + + +-- +-- Name: TABLE muse_change_command; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_change_command TO muse_app; + + +-- +-- Name: TABLE muse_change_impact; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_change_impact TO muse_app; + + +-- +-- Name: TABLE muse_chapter; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_chapter TO muse_app; + + +-- +-- Name: TABLE muse_clean_candidate; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_clean_candidate TO muse_app; + + +-- +-- Name: TABLE muse_config_probe_binding; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_config_probe_binding TO muse_app; + + +-- +-- Name: TABLE muse_context_snapshot; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_context_snapshot TO muse_app; + + +-- +-- Name: TABLE muse_delivery; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_delivery TO muse_app; + + +-- +-- Name: TABLE muse_delivery_artifact; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_delivery_artifact TO muse_app; + + +-- +-- Name: TABLE muse_delivery_artifact_validation; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT ON TABLE public.muse_delivery_artifact_validation TO muse_app; + + +-- +-- Name: TABLE muse_diagnosis; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_diagnosis TO muse_app; + + +-- +-- Name: TABLE muse_directory_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_directory_version TO muse_app; + + +-- +-- Name: TABLE muse_document; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_document TO muse_app; + + +-- +-- Name: TABLE muse_document_branch; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_document_branch TO muse_app; + + +-- +-- Name: TABLE muse_document_index; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_document_index TO muse_app; + + +-- +-- Name: TABLE muse_document_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_document_version TO muse_app; + + +-- +-- Name: TABLE muse_enablement_status; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_enablement_status TO muse_app; +GRANT SELECT ON TABLE public.muse_enablement_status TO muse_eval; + + +-- +-- Name: TABLE muse_exploration_selection; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_exploration_selection TO muse_app; + + +-- +-- Name: TABLE muse_exploration_selection_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_exploration_selection_version TO muse_app; + + +-- +-- Name: TABLE muse_fact_proposal; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_fact_proposal TO muse_app; + + +-- +-- Name: TABLE muse_fact_proposal_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_fact_proposal_version TO muse_app; + + +-- +-- Name: TABLE muse_flow_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_flow_version TO muse_app; + + +-- +-- Name: TABLE muse_improvement; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_improvement TO muse_app; + + +-- +-- Name: TABLE muse_improvement_action; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_improvement_action TO muse_app; + + +-- +-- Name: TABLE muse_improvement_result; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_improvement_result TO muse_app; + + +-- +-- Name: TABLE muse_improvement_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_improvement_version TO muse_app; + + +-- +-- Name: TABLE muse_legacy_import_record; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,UPDATE ON TABLE public.muse_legacy_import_record TO muse_app; + + +-- +-- Name: TABLE muse_legacy_target; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_legacy_target TO muse_app; + + +-- +-- Name: TABLE muse_literary_report; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_literary_report TO muse_app; + + +-- +-- Name: TABLE muse_literary_shard; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_literary_shard TO muse_app; + + +-- +-- Name: TABLE muse_method; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_method TO muse_app; + + +-- +-- Name: TABLE muse_method_binding; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_method_binding TO muse_app; + + +-- +-- Name: TABLE muse_method_evidence; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_method_evidence TO muse_app; + + +-- +-- Name: TABLE muse_method_index; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_method_index TO muse_app; + + +-- +-- Name: TABLE muse_method_index_guard; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_method_index_guard TO muse_app; +GRANT SELECT ON TABLE public.muse_method_index_guard TO muse_eval; + + +-- +-- Name: TABLE muse_method_index_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_method_index_version TO muse_app; + + +-- +-- Name: SEQUENCE muse_method_index_version_ledger_id_seq; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,USAGE ON SEQUENCE public.muse_method_index_version_ledger_id_seq TO muse_app; + + +-- +-- Name: TABLE muse_method_proposal; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_method_proposal TO muse_app; + + +-- +-- Name: TABLE muse_method_usage; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_method_usage TO muse_app; + + +-- +-- Name: TABLE muse_method_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_method_version TO muse_app; + + +-- +-- Name: TABLE muse_migration; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_migration TO muse_app; +GRANT SELECT ON TABLE public.muse_migration TO muse_eval; + + +-- +-- Name: TABLE muse_model_candidate; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_model_candidate TO muse_app; + + +-- +-- Name: TABLE muse_model_delivery; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_model_delivery TO muse_app; + + +-- +-- Name: TABLE muse_model_plan_candidate; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_model_plan_candidate TO muse_app; + + +-- +-- Name: TABLE muse_plan; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_plan TO muse_app; + + +-- +-- Name: TABLE muse_plan_candidate; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_plan_candidate TO muse_app; + + +-- +-- Name: TABLE muse_plan_candidate_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_plan_candidate_version TO muse_app; + + +-- +-- Name: TABLE muse_plan_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_plan_version TO muse_app; + + +-- +-- Name: TABLE muse_preference; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_preference TO muse_app; + + +-- +-- Name: TABLE muse_preference_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_preference_version TO muse_app; + + +-- +-- Name: TABLE muse_quality_case; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_quality_case TO muse_app; + + +-- +-- Name: TABLE muse_quality_case_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_quality_case_version TO muse_app; + + +-- +-- Name: TABLE muse_ranking_snapshot; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_ranking_snapshot TO muse_app; + + +-- +-- Name: TABLE muse_ranking_source; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_ranking_source TO muse_app; + + +-- +-- Name: TABLE muse_raw_archive; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_raw_archive TO muse_app; + + +-- +-- Name: TABLE muse_raw_archive_item; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_raw_archive_item TO muse_app; + + +-- +-- Name: TABLE muse_raw_authorization; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_raw_authorization TO muse_app; + + +-- +-- Name: TABLE muse_raw_lease; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_raw_lease TO muse_app; + + +-- +-- Name: TABLE muse_raw_namespace; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_raw_namespace TO muse_app; + + +-- +-- Name: TABLE muse_raw_orphan_cleanup; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_raw_orphan_cleanup TO muse_app; + + +-- +-- Name: TABLE muse_reader_feedback; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_reader_feedback TO muse_app; + + +-- +-- Name: TABLE muse_release; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_release TO muse_app; + + +-- +-- Name: TABLE muse_review_report; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_review_report TO muse_app; + + +-- +-- Name: TABLE muse_revision_comparison_status; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_revision_comparison_status TO muse_app; +GRANT SELECT ON TABLE public.muse_revision_comparison_status TO muse_eval; + + +-- +-- Name: TABLE muse_revision_result; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_revision_result TO muse_app; + + +-- +-- Name: TABLE muse_revision_round; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT ON TABLE public.muse_revision_round TO muse_app; + + +-- +-- Name: COLUMN muse_revision_round.task_id; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(task_id) ON TABLE public.muse_revision_round TO muse_app; + + +-- +-- Name: COLUMN muse_revision_round.state; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(state) ON TABLE public.muse_revision_round TO muse_app; + + +-- +-- Name: COLUMN muse_revision_round.outcome; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(outcome) ON TABLE public.muse_revision_round TO muse_app; + + +-- +-- Name: COLUMN muse_revision_round.candidate_id; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(candidate_id) ON TABLE public.muse_revision_round TO muse_app; + + +-- +-- Name: COLUMN muse_revision_round.updated_at; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(updated_at) ON TABLE public.muse_revision_round TO muse_app; + + +-- +-- Name: TABLE muse_revision_session; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT ON TABLE public.muse_revision_session TO muse_app; + + +-- +-- Name: COLUMN muse_revision_session.current_round; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(current_round) ON TABLE public.muse_revision_session TO muse_app; + + +-- +-- Name: COLUMN muse_revision_session.state; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(state) ON TABLE public.muse_revision_session TO muse_app; + + +-- +-- Name: COLUMN muse_revision_session.stop_reason; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(stop_reason) ON TABLE public.muse_revision_session TO muse_app; + + +-- +-- Name: COLUMN muse_revision_session.stop_detail; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(stop_detail) ON TABLE public.muse_revision_session TO muse_app; + + +-- +-- Name: COLUMN muse_revision_session.author_choice; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(author_choice) ON TABLE public.muse_revision_session TO muse_app; + + +-- +-- Name: COLUMN muse_revision_session.selected_candidate_id; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(selected_candidate_id) ON TABLE public.muse_revision_session TO muse_app; + + +-- +-- Name: COLUMN muse_revision_session.updated_at; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(updated_at) ON TABLE public.muse_revision_session TO muse_app; + + +-- +-- Name: TABLE muse_revision_session_action; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT ON TABLE public.muse_revision_session_action TO muse_app; + + +-- +-- Name: TABLE muse_role_session_authorization; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_role_session_authorization TO muse_app; + + +-- +-- Name: TABLE muse_rule_activation; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_rule_activation TO muse_app; + + +-- +-- Name: TABLE muse_rule_activation_current; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_rule_activation_current TO muse_app; + + +-- +-- Name: TABLE muse_rule_activation_event; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_rule_activation_event TO muse_app; + + +-- +-- Name: TABLE muse_rule_diagnostic_status; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_rule_diagnostic_status TO muse_app; +GRANT SELECT ON TABLE public.muse_rule_diagnostic_status TO muse_eval; + + +-- +-- Name: TABLE muse_rule_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_rule_version TO muse_app; + + +-- +-- Name: TABLE muse_run_observation; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_run_observation TO muse_app; + + +-- +-- Name: TABLE muse_run_observation_command; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_run_observation_command TO muse_app; + + +-- +-- Name: TABLE muse_runtime_config_active; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_runtime_config_active TO muse_app; + + +-- +-- Name: TABLE muse_runtime_config_validation; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_runtime_config_validation TO muse_app; + + +-- +-- Name: TABLE muse_runtime_config_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_runtime_config_version TO muse_app; + + +-- +-- Name: TABLE muse_runtime_evidence; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_runtime_evidence TO muse_app; + + +-- +-- Name: TABLE muse_serial_plan; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_serial_plan TO muse_app; + + +-- +-- Name: COLUMN muse_serial_plan.revision; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT UPDATE(revision) ON TABLE public.muse_serial_plan TO muse_app; + + +-- +-- Name: TABLE muse_serial_plan_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_serial_plan_version TO muse_app; + + +-- +-- Name: TABLE muse_source; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_source TO muse_app; + + +-- +-- Name: TABLE muse_source_analysis; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_source_analysis TO muse_app; + + +-- +-- Name: TABLE muse_source_slice; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_source_slice TO muse_app; + + +-- +-- Name: TABLE muse_source_slice_guard; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_source_slice_guard TO muse_app; +GRANT SELECT ON TABLE public.muse_source_slice_guard TO muse_eval; + + +-- +-- Name: TABLE muse_source_slice_index; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_source_slice_index TO muse_app; + + +-- +-- Name: TABLE muse_source_slice_index_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_source_slice_index_version TO muse_app; + + +-- +-- Name: SEQUENCE muse_source_slice_index_version_ledger_id_seq; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,USAGE ON SEQUENCE public.muse_source_slice_index_version_ledger_id_seq TO muse_app; + + +-- +-- Name: TABLE muse_source_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_source_version TO muse_app; + + +-- +-- Name: TABLE muse_step; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_step TO muse_app; + + +-- +-- Name: TABLE muse_task; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_task TO muse_app; + + +-- +-- Name: TABLE muse_task_budget; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_task_budget TO muse_app; + + +-- +-- Name: TABLE muse_task_config_binding; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_task_config_binding TO muse_app; + + +-- +-- Name: TABLE muse_task_control; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_task_control TO muse_app; + + +-- +-- Name: TABLE muse_task_event; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_task_event TO muse_app; + + +-- +-- Name: TABLE muse_task_inventory; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT ON TABLE public.muse_task_inventory TO muse_app; + + +-- +-- Name: TABLE muse_task_scope_lease; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_task_scope_lease TO muse_app; + + +-- +-- Name: TABLE muse_voice_current; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_voice_current TO muse_app; + + +-- +-- Name: TABLE muse_voice_proposal; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_voice_proposal TO muse_app; + + +-- +-- Name: TABLE muse_voice_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_voice_version TO muse_app; + + +-- +-- Name: TABLE muse_work; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_work TO muse_app; + + +-- +-- Name: TABLE muse_work_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_work_version TO muse_app; + + +-- +-- Name: TABLE muse_world_clock; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_world_clock TO muse_app; + + +-- +-- Name: TABLE muse_world_object; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_world_object TO muse_app; + + +-- +-- Name: TABLE muse_world_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_world_version TO muse_app; + + +-- +-- Name: TABLE muse_writing_candidate; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_writing_candidate TO muse_app; + + +-- +-- Name: TABLE muse_writing_candidate_version; Type: ACL; Schema: public; Owner: muse_maint +-- + +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.muse_writing_candidate_version TO muse_app; + + +-- +-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: evaluation; Owner: muse_maint +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA evaluation GRANT SELECT,USAGE ON SEQUENCES TO muse_eval; + + +-- +-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: evaluation; Owner: muse_maint +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA evaluation GRANT SELECT,INSERT,DELETE,UPDATE ON TABLES TO muse_eval; + + +-- +-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: oracle; Owner: muse_maint +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA oracle GRANT SELECT ON TABLES TO muse_eval; + + +-- +-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: public; Owner: muse_maint +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA public GRANT SELECT,USAGE ON SEQUENCES TO muse_app; + + +-- +-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: public; Owner: muse_maint +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE muse_maint IN SCHEMA public GRANT SELECT,INSERT,DELETE,UPDATE ON TABLES TO muse_app; + + +-- +-- PostgreSQL database dump complete +-- + + diff --git a/数据库/迁移/V0002__元数据结构与策略.sql b/数据库/迁移/V0002__元数据结构与策略.sql deleted file mode 100644 index 4d98d7b..0000000 --- a/数据库/迁移/V0002__元数据结构与策略.sql +++ /dev/null @@ -1,84 +0,0 @@ --- 元数据只保存结构模具与绑定,不保存任何业务实例值。 -CREATE SCHEMA metadata AUTHORIZATION muse_maint; -GRANT USAGE ON SCHEMA metadata TO muse_app, muse_eval; - -CREATE TABLE metadata.type_registry ( - type_id text PRIMARY KEY, - definition jsonb NOT NULL, - content_hash text NOT NULL, - state text NOT NULL DEFAULT 'candidate' CHECK (state IN ('candidate', 'published')), - policy_revision bigint NOT NULL DEFAULT 0 CHECK (policy_revision >= 0) -); -CREATE TABLE metadata.schema_version ( - schema_id text NOT NULL, - schema_version bigint NOT NULL CHECK (schema_version > 0), - type_id text NOT NULL REFERENCES metadata.type_registry(type_id), - definition jsonb NOT NULL, - content_hash text NOT NULL, - state text NOT NULL CHECK (state IN ('candidate', 'published')), - PRIMARY KEY (schema_id, schema_version) -); -CREATE TABLE metadata.work_extension ( - work_id text NOT NULL, - schema_id text NOT NULL, - base_version bigint NOT NULL, - extension_version bigint NOT NULL CHECK (extension_version > 0), - definition jsonb NOT NULL, - content_hash text NOT NULL, - state text NOT NULL CHECK (state IN ('candidate', 'published')), - PRIMARY KEY (work_id, schema_id, base_version, extension_version), - FOREIGN KEY (schema_id, base_version) - REFERENCES metadata.schema_version(schema_id, schema_version) -); -CREATE TABLE metadata.policy_version ( - type_id text NOT NULL REFERENCES metadata.type_registry(type_id), - version bigint NOT NULL CHECK (version > 0), - definition jsonb NOT NULL, - content_hash text NOT NULL, - PRIMARY KEY (type_id, version) -); -CREATE TABLE metadata.schema_binding ( - target_ref text PRIMARY KEY, - work_id text NOT NULL, - type_id text NOT NULL REFERENCES metadata.type_registry(type_id), - schema_id text NOT NULL, - base_version bigint NOT NULL, - extension_version bigint, - effective_schema_hash text NOT NULL, - revision bigint NOT NULL CHECK (revision > 0), - FOREIGN KEY (schema_id, base_version) - REFERENCES metadata.schema_version(schema_id, schema_version), - FOREIGN KEY (work_id, schema_id, base_version, extension_version) - REFERENCES metadata.work_extension(work_id, schema_id, base_version, extension_version) -); -CREATE TABLE metadata.activation_receipt ( - command_id text PRIMARY KEY, - request_hash text NOT NULL, - result jsonb NOT NULL, - reviewed_by text NOT NULL, - change_scope text NOT NULL, - created_at timestamptz NOT NULL DEFAULT current_timestamp -); - --- 候选修改也必须产生新版本;发布只允许改变状态,正文定义永远不可原地覆盖。 -CREATE FUNCTION metadata.immutable_definition() RETURNS trigger LANGUAGE plpgsql AS $$ -BEGIN - IF TG_OP = 'DELETE' THEN - RAISE EXCEPTION '元数据历史版本不可删除'; - END IF; - IF NEW.definition IS DISTINCT FROM OLD.definition - OR NEW.content_hash IS DISTINCT FROM OLD.content_hash THEN - RAISE EXCEPTION '元数据定义不可修改,必须新增版本'; - END IF; - RETURN NEW; -END; -$$; -CREATE TRIGGER schema_immutable BEFORE UPDATE OR DELETE ON metadata.schema_version -FOR EACH ROW EXECUTE FUNCTION metadata.immutable_definition(); -CREATE TRIGGER extension_immutable BEFORE UPDATE OR DELETE ON metadata.work_extension -FOR EACH ROW EXECUTE FUNCTION metadata.immutable_definition(); -CREATE TRIGGER policy_immutable BEFORE UPDATE OR DELETE ON metadata.policy_version -FOR EACH ROW EXECUTE FUNCTION metadata.immutable_definition(); - -GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA metadata TO muse_app; -GRANT SELECT ON ALL TABLES IN SCHEMA metadata TO muse_eval; diff --git a/数据库/迁移/V0003__正式变更.sql b/数据库/迁移/V0003__正式变更.sql deleted file mode 100644 index cf90063..0000000 --- a/数据库/迁移/V0003__正式变更.sql +++ /dev/null @@ -1,38 +0,0 @@ --- S01只保存命令、审阅、决定与影响;业务实例表由各owner迁移定义。 -CREATE TABLE public.muse_change_command ( - author_id text NOT NULL, - run_purpose public.muse_purpose NOT NULL CHECK (run_purpose='production'), - command_id text NOT NULL, - request_hash text NOT NULL, - receipt jsonb, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(author_id,run_purpose,command_id) -); -CREATE TABLE public.muse_author_review ( - review_id uuid PRIMARY KEY, - author_id text NOT NULL, - entry_id text NOT NULL, - target_ref text NOT NULL, - content_hash text NOT NULL, - snapshot jsonb NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TABLE public.muse_candidate_decision ( - candidate_id text NOT NULL, - candidate_revision bigint NOT NULL, - decision text NOT NULL CHECK (decision IN ('adopt','reject','defer')), - author_id text NOT NULL, - review_id uuid NOT NULL REFERENCES public.muse_author_review(review_id), - command_id text NOT NULL, - PRIMARY KEY(candidate_id,candidate_revision) -); -CREATE TABLE public.muse_change_impact ( - impact_id uuid PRIMARY KEY, - receipt_id uuid NOT NULL, - target_ref text NOT NULL, - reason text NOT NULL, - before_version text NOT NULL, - after_version text NOT NULL, - state text NOT NULL DEFAULT 'pending' CHECK (state IN ('pending','handled')), - UNIQUE(receipt_id,target_ref,reason) -); diff --git a/数据库/迁移/V0004__任务运行与证据.sql b/数据库/迁移/V0004__任务运行与证据.sql deleted file mode 100644 index 162dde6..0000000 --- a/数据库/迁移/V0004__任务运行与证据.sql +++ /dev/null @@ -1,290 +0,0 @@ --- 持久任务、步骤、尝试、独立作用域租约和有序事件。 --- 模型预算与原文生命周期随所属实现接入;用于当前开发基线。 -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$; diff --git a/数据库/迁移/V0005__作品规划.sql b/数据库/迁移/V0005__作品规划.sql deleted file mode 100644 index 9ce82cc..0000000 --- a/数据库/迁移/V0005__作品规划.sql +++ /dev/null @@ -1,94 +0,0 @@ --- B01拥有作品身份、动态档案版本及稳定章节目录。 -CREATE TABLE public.muse_work ( - work_id text PRIMARY KEY, - author_id text NOT NULL, - current_revision bigint NOT NULL CHECK(current_revision>0), - directory_revision bigint NOT NULL DEFAULT 0 CHECK(directory_revision>=0) -); -CREATE TABLE public.muse_work_version ( - work_id text NOT NULL REFERENCES public.muse_work(work_id), - revision bigint NOT NULL CHECK(revision>0), - content jsonb NOT NULL, - schema_binding jsonb NOT NULL, - content_hash text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(work_id,revision) -); -CREATE TABLE public.muse_chapter ( - chapter_id text PRIMARY KEY, - work_id text NOT NULL REFERENCES public.muse_work(work_id), - title text NOT NULL, - position integer NOT NULL CHECK(position>0), - UNIQUE(work_id,position) DEFERRABLE INITIALLY DEFERRED -); -CREATE TABLE public.muse_directory_version ( - work_id text NOT NULL REFERENCES public.muse_work(work_id), - revision bigint NOT NULL CHECK(revision>=0), - chapters jsonb NOT NULL, - nodes jsonb NOT NULL DEFAULT '[]', - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(work_id,revision) -); -ALTER TABLE public.muse_work ADD CONSTRAINT work_current_version_fk - FOREIGN KEY(work_id,current_revision) REFERENCES public.muse_work_version(work_id,revision) - DEFERRABLE INITIALLY DEFERRED; -ALTER TABLE public.muse_work ADD CONSTRAINT work_current_directory_fk - FOREIGN KEY(work_id,directory_revision) REFERENCES public.muse_directory_version(work_id,revision) - DEFERRABLE INITIALLY DEFERRED; --- 明确选定的探索来源属于B01;保留不可变快照,不将方向选择当作规划确认。 -CREATE TABLE public.muse_exploration_selection ( - work_id text PRIMARY KEY REFERENCES public.muse_work(work_id), - current_revision bigint NOT NULL CHECK(current_revision>0) -); -CREATE TABLE public.muse_exploration_selection_version ( - work_id text NOT NULL REFERENCES public.muse_work(work_id), - revision bigint NOT NULL CHECK(revision>0), - snapshot jsonb NOT NULL, - selected_by text NOT NULL, - selected_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(work_id,revision) -); -ALTER TABLE public.muse_exploration_selection ADD CONSTRAINT selection_current_version_fk - FOREIGN KEY(work_id,current_revision) REFERENCES public.muse_exploration_selection_version(work_id,revision) - DEFERRABLE INITIALLY DEFERRED; -CREATE TABLE public.muse_plan ( - plan_id text PRIMARY KEY, - work_id text NOT NULL REFERENCES public.muse_work(work_id), - type_id text NOT NULL, - chapter_id text REFERENCES public.muse_chapter(chapter_id), - node_id text, - current_revision bigint NOT NULL CHECK(current_revision>0) -); -CREATE TABLE public.muse_plan_version ( - plan_id text NOT NULL REFERENCES public.muse_plan(plan_id), - revision bigint NOT NULL CHECK(revision>0), - request jsonb NOT NULL, - content jsonb NOT NULL, - content_hash text NOT NULL, - schema_binding jsonb NOT NULL, - source_dependencies jsonb NOT NULL, - author_id text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(plan_id,revision) -); -ALTER TABLE public.muse_plan ADD CONSTRAINT plan_current_version_fk - FOREIGN KEY(plan_id,current_revision) REFERENCES public.muse_plan_version(plan_id,revision) - DEFERRABLE INITIALLY DEFERRED; -CREATE TABLE public.muse_plan_candidate ( - candidate_id uuid PRIMARY KEY, - work_id text NOT NULL REFERENCES public.muse_work(work_id), - plan_id text NOT NULL, - current_revision bigint NOT NULL CHECK(current_revision>0) -); -CREATE TABLE public.muse_plan_candidate_version ( - candidate_id uuid NOT NULL REFERENCES public.muse_plan_candidate(candidate_id), - revision bigint NOT NULL CHECK(revision>0), - request jsonb NOT NULL, - content jsonb NOT NULL, - source_dependencies jsonb NOT NULL, - candidate_hash text NOT NULL, - PRIMARY KEY(candidate_id,revision) -); -ALTER TABLE public.muse_plan_candidate ADD CONSTRAINT plan_candidate_current_version_fk - FOREIGN KEY(candidate_id,current_revision) REFERENCES public.muse_plan_candidate_version(candidate_id,revision) - DEFERRABLE INITIALLY DEFERRED; diff --git a/数据库/迁移/V0006__故事世界.sql b/数据库/迁移/V0006__故事世界.sql deleted file mode 100644 index 359a26a..0000000 --- a/数据库/迁移/V0006__故事世界.sql +++ /dev/null @@ -1,52 +0,0 @@ --- B02本书实例、不可变事实版本与提案;作者决定仍由S01保存。 -CREATE TABLE public.muse_world_clock ( - work_id text PRIMARY KEY REFERENCES public.muse_work(work_id), - system_revision bigint NOT NULL CHECK(system_revision>=0) -); -CREATE TABLE public.muse_world_object ( - object_id text PRIMARY KEY, - work_id text NOT NULL REFERENCES public.muse_work(work_id), - type_id text NOT NULL, - instance_family text NOT NULL CHECK(instance_family IN ('entity','relation')), - current_revision bigint NOT NULL CHECK(current_revision>0) -); -CREATE TABLE public.muse_world_version ( - object_id text NOT NULL REFERENCES public.muse_world_object(object_id), - revision bigint NOT NULL CHECK(revision>0), - system_revision bigint NOT NULL CHECK(system_revision>0), - content jsonb NOT NULL, - content_hash text NOT NULL, - schema_binding jsonb NOT NULL, - sources jsonb NOT NULL, - independent boolean NOT NULL, - effective_from text REFERENCES public.muse_chapter(chapter_id), - knowledge_mode text NOT NULL CHECK(knowledge_mode IN ('fact','belief','plan','setting')), - known_to jsonb NOT NULL, - reader_visible boolean NOT NULL, - planned_window jsonb, - author_id text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(object_id,revision) -); -ALTER TABLE public.muse_world_object ADD CONSTRAINT world_current_version_fk - FOREIGN KEY(object_id,current_revision) REFERENCES public.muse_world_version(object_id,revision) - DEFERRABLE INITIALLY DEFERRED; -CREATE TABLE public.muse_fact_proposal ( - proposal_id uuid PRIMARY KEY, - work_id text NOT NULL REFERENCES public.muse_work(work_id), - object_id text NOT NULL, - current_revision bigint NOT NULL CHECK(current_revision>0) -); -CREATE TABLE public.muse_fact_proposal_version ( - proposal_id uuid NOT NULL REFERENCES public.muse_fact_proposal(proposal_id), - revision bigint NOT NULL CHECK(revision>0), - request jsonb NOT NULL, - proposed_content jsonb NOT NULL, - proposal_hash text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(proposal_id,revision) -); -ALTER TABLE public.muse_fact_proposal ADD CONSTRAINT fact_proposal_current_version_fk - FOREIGN KEY(proposal_id,current_revision) REFERENCES public.muse_fact_proposal_version(proposal_id,revision) - DEFERRABLE INITIALLY DEFERRED; -CREATE INDEX world_version_system_idx ON public.muse_world_version(object_id,system_revision DESC); diff --git a/数据库/迁移/V0007__资料研究.sql b/数据库/迁移/V0007__资料研究.sql deleted file mode 100644 index d05a9fb..0000000 --- a/数据库/迁移/V0007__资料研究.sql +++ /dev/null @@ -1,67 +0,0 @@ --- B03:外部与私人资料、原文版本、清理候选与榜单快照。 --- 原文只追加不可改写;清理是对照产物;榜单快照把时点观察与效果推断分开(无 run 归因字段)。 -DO $migration$ -BEGIN - -- 来源:同源再导入落到版本链;kind 区分作者稿、参考书、网页、笔记与灵感。 - CREATE TABLE public.muse_source ( - source_id uuid PRIMARY KEY, - kind text NOT NULL CHECK (kind IN ('author_draft','reference','web','note','inspiration')), - title text NOT NULL, - origin text NOT NULL, - authorized_uses jsonb NOT NULL DEFAULT '[]'::jsonb, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (origin, kind), - CHECK (jsonb_typeof(authorized_uses) = 'array') - ); - - -- 原文版本:只追加;内容哈希用于证据校验与重复辨认。 - CREATE TABLE public.muse_source_version ( - source_id uuid NOT NULL REFERENCES public.muse_source(source_id), - revision bigint NOT NULL CHECK (revision > 0), - content_hash text NOT NULL, - content text NOT NULL, - import_result jsonb NOT NULL, - imported_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY (source_id, revision), - CHECK (jsonb_typeof(import_result) = 'object') - ); - CREATE INDEX ON public.muse_source_version (source_id, imported_at); - - -- 清理候选:对照产物,原文不受影响;删除项可定位、可回退。 - CREATE TABLE public.muse_clean_candidate ( - candidate_id uuid PRIMARY KEY, - source_id uuid NOT NULL REFERENCES public.muse_source(source_id), - revision bigint NOT NULL, - removals jsonb NOT NULL, - status text NOT NULL CHECK (status IN ('proposed','applied','rejected')), - cleaned_hash text, - cleaned_text text, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (source_id, revision, candidate_id), - CHECK (jsonb_typeof(removals) = 'array'), - CHECK ((status = 'applied') = (cleaned_hash IS NOT NULL AND cleaned_text IS NOT NULL)), - FOREIGN KEY (source_id, revision) REFERENCES public.muse_source_version(source_id, revision) - ); - - -- 榜单来源登记:具名榜种与采集方式。 - CREATE TABLE public.muse_ranking_source ( - ranking_id text PRIMARY KEY, - name text NOT NULL, - url text NOT NULL, - 采集方式 text NOT NULL - ); - - -- 榜单快照:时刻观察;失败保留失败态;不携带任何 run 归因。 - CREATE TABLE public.muse_ranking_snapshot ( - snapshot_id uuid PRIMARY KEY, - ranking_id text NOT NULL REFERENCES public.muse_ranking_source(ranking_id), - captured_at timestamptz NOT NULL DEFAULT clock_timestamp(), - status text NOT NULL CHECK (status IN ('ok','failed')), - failure_reason text, - items jsonb, - CHECK ((status = 'ok') = (items IS NOT NULL)), - CHECK (items IS NULL OR jsonb_typeof(items) = 'array') - ); - CREATE INDEX ON public.muse_ranking_snapshot (ranking_id, captured_at DESC); -END -$migration$; diff --git a/数据库/迁移/V0009__正文写作.sql b/数据库/迁移/V0009__正文写作.sql deleted file mode 100644 index ebcefee..0000000 --- a/数据库/迁移/V0009__正文写作.sql +++ /dev/null @@ -1,50 +0,0 @@ --- B05正文版本只追加;段落身份与显式换行保留在受限文档树中。 -CREATE TABLE public.muse_document ( - document_id uuid PRIMARY KEY, - chapter_id text NOT NULL REFERENCES public.muse_chapter(chapter_id), - branch_id text NOT NULL, - current_revision bigint NOT NULL CHECK(current_revision>0), - UNIQUE(chapter_id,branch_id) -); -CREATE TABLE public.muse_document_version ( - document_id uuid NOT NULL REFERENCES public.muse_document(document_id), - revision bigint NOT NULL CHECK(revision>0), - document jsonb NOT NULL, - document_hash text NOT NULL, - visible_text_hash text NOT NULL, - author_id text NOT NULL, - restored_from bigint, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(document_id,revision), - FOREIGN KEY(document_id,restored_from) REFERENCES public.muse_document_version(document_id,revision) -); -ALTER TABLE public.muse_document ADD CONSTRAINT document_current_version_fk - FOREIGN KEY(document_id,current_revision) REFERENCES public.muse_document_version(document_id,revision) - DEFERRABLE INITIALLY DEFERRED; - --- 作者改稿先存候选,决定记录由S01拥有;生成候选的证据绑定由后续写作任务扩展。 -CREATE TABLE public.muse_writing_candidate ( - candidate_id uuid PRIMARY KEY, - chapter_id text NOT NULL REFERENCES public.muse_chapter(chapter_id), - branch_id text NOT NULL, - origin text NOT NULL CHECK(origin='author'), - current_revision bigint NOT NULL CHECK(current_revision>0) -); -CREATE TABLE public.muse_writing_candidate_version ( - candidate_id uuid NOT NULL REFERENCES public.muse_writing_candidate(candidate_id), - revision bigint NOT NULL CHECK(revision>0), - base_revision bigint NOT NULL CHECK(base_revision>=0), - base_hash text NOT NULL, - document jsonb NOT NULL, - document_hash text NOT NULL, - visible_text_hash text NOT NULL, - candidate_hash text NOT NULL, - checks jsonb NOT NULL, - author_id text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(candidate_id,revision) -); -ALTER TABLE public.muse_writing_candidate ADD CONSTRAINT writing_candidate_version_fk - FOREIGN KEY(candidate_id,current_revision) - REFERENCES public.muse_writing_candidate_version(candidate_id,revision) - DEFERRABLE INITIALLY DEFERRED; diff --git a/数据库/迁移/V0016__流程定义与版本.sql b/数据库/迁移/V0016__流程定义与版本.sql deleted file mode 100644 index b2e51e9..0000000 --- a/数据库/迁移/V0016__流程定义与版本.sql +++ /dev/null @@ -1,20 +0,0 @@ --- 已校验流程的不可变执行计划;同版本不能覆盖历史任务定义。 -DO $migration$ -DECLARE - namespace text; -BEGIN - FOREACH namespace IN ARRAY ARRAY['public', 'evaluation'] LOOP - EXECUTE format($ddl$ - CREATE TABLE %I.muse_flow_version ( - run_purpose public.muse_purpose NOT NULL, - flow_id text NOT NULL, - version text NOT NULL, - definition jsonb NOT NULL, - definition_hash text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY (run_purpose, flow_id, version) - ) - $ddl$, namespace); - END LOOP; -END -$migration$; diff --git a/数据库/迁移/V0020__上下文快照与消费.sql b/数据库/迁移/V0020__上下文快照与消费.sql deleted file mode 100644 index 27b99e0..0000000 --- a/数据库/迁移/V0020__上下文快照与消费.sql +++ /dev/null @@ -1,28 +0,0 @@ --- B09:任务范围与实际消费的不可变上下文快照。 --- 快照身份由载荷确定性派生,同一输入重复冻结幂等为一行;历史快照只读不改写。 -DO $migration$ -DECLARE - namespace text; -BEGIN - FOREACH namespace IN ARRAY ARRAY['public', 'evaluation'] LOOP - EXECUTE format($ddl$ - CREATE TABLE %1$I.muse_context_snapshot ( - snapshot_id uuid PRIMARY KEY, - run_purpose public.muse_purpose NOT NULL, - task_id uuid NOT NULL REFERENCES %1$I.muse_task(task_id), - work_id text NOT NULL, - input_hash text NOT NULL, - frozen_scope jsonb NOT NULL, - assembly jsonb NOT NULL, - source_bindings jsonb NOT NULL, - created_by text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (run_purpose, task_id, input_hash), - CHECK (assembly ? ALL (ARRAY['入选','省略','字节数','文本哈希','文本'])), - CHECK (jsonb_typeof(source_bindings) = 'array') - ); - CREATE INDEX ON %1$I.muse_context_snapshot (task_id, created_at); - $ddl$, namespace); - END LOOP; -END -$migration$; diff --git a/数据库/迁移/V0021__模型候选与审校报告.sql b/数据库/迁移/V0021__模型候选与审校报告.sql deleted file mode 100644 index 3ac4cd1..0000000 --- a/数据库/迁移/V0021__模型候选与审校报告.sql +++ /dev/null @@ -1,59 +0,0 @@ --- B05/B06:模型候选来源证据与审校报告;候选来源在作者改稿之外扩展模型生成。 --- 模型候选不走 S01 作者决定命令,由写作任务在任务运行事务内写入;作者决定仍归 S01。 --- B05/B06 正式内容表只在 public 命名空间(与 V0009 一致)。 -DO $migration$ -DECLARE - origin_constraint text; -BEGIN - SELECT conname INTO origin_constraint - FROM pg_constraint - WHERE conrelid = 'public.muse_writing_candidate'::regclass - AND contype = 'c' - AND pg_get_constraintdef(oid) ILIKE '%origin%'; - IF origin_constraint IS NULL THEN - RAISE EXCEPTION '候选来源约束缺失,不能盲目扩展'; - END IF; - EXECUTE format($ddl$ - ALTER TABLE public.muse_writing_candidate DROP CONSTRAINT %I; - ALTER TABLE public.muse_writing_candidate - ADD CONSTRAINT writing_candidate_origin_check - CHECK (origin IN ('author', 'model')); - - -- 模型候选的证据绑定:来源任务、冻结快照与处理器/模型回执哈希;一行绑定一个候选,不可改写。 - CREATE TABLE public.muse_model_candidate ( - candidate_id uuid PRIMARY KEY - REFERENCES public.muse_writing_candidate(candidate_id), - task_id uuid NOT NULL REFERENCES public.muse_task(task_id), - snapshot_id uuid NOT NULL REFERENCES public.muse_context_snapshot(snapshot_id), - flow_version text NOT NULL, - processor_versions jsonb NOT NULL, - model_evidence jsonb NOT NULL, - prompt_hashes jsonb NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - CHECK (jsonb_typeof(processor_versions) = 'object'), - CHECK (jsonb_typeof(model_evidence) = 'array'), - CHECK (jsonb_typeof(prompt_hashes) = 'object') - ); - - -- 审校报告:绑定候选版本与所依据快照;问题与覆盖只追加,不修改候选本身。 - CREATE TABLE public.muse_review_report ( - report_id uuid PRIMARY KEY, - candidate_id uuid NOT NULL - REFERENCES public.muse_writing_candidate(candidate_id), - candidate_revision bigint NOT NULL CHECK (candidate_revision > 0), - snapshot_id uuid NOT NULL - REFERENCES public.muse_context_snapshot(snapshot_id), - basic jsonb NOT NULL, - continuity jsonb NOT NULL, - verdict text NOT NULL CHECK (verdict IN ('passed', 'failed')), - coverage jsonb NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (candidate_id, candidate_revision), - CHECK (basic ? ALL (ARRAY['checks', 'verdict'])), - CHECK (continuity ? ALL (ARRAY['findings', 'coverage'])), - CHECK (jsonb_typeof(coverage) = 'object') - ); - CREATE INDEX ON public.muse_review_report (candidate_id, created_at); - $ddl$, origin_constraint); -END -$migration$; diff --git a/数据库/迁移/V0022__知识方法.sql b/数据库/迁移/V0022__知识方法.sql deleted file mode 100644 index eac34a1..0000000 --- a/数据库/迁移/V0022__知识方法.sql +++ /dev/null @@ -1,129 +0,0 @@ --- B04:方法候选与版本、证据反例、固定绑定、不可变消费与检索索引。 --- 方法是跨作品正式内容:版本只追加;绑定记具体版本不追随;消费不可变;索引可重建不动正式内容。 --- 裁决 A:向量不依赖 pgvector,存 double precision[],相似度在应用层计算。 -DO $migration$ -BEGIN - -- 方法:跨作品范式卡;内容哈希按 owner 去重,同哈希不同 owner 由服务层拒绝。 - CREATE TABLE public.muse_method ( - method_id uuid PRIMARY KEY, - owner text NOT NULL, - type_id text NOT NULL, - title text NOT NULL, - state text NOT NULL CHECK (state IN ('proposed','confirmed','enabled','disabled','withdrawn')), - content_hash text NOT NULL, - current_version bigint NOT NULL DEFAULT 0 CHECK (current_version >= 0), - created_by text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - updated_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (owner, content_hash), - CHECK (title <> '') - ); - CREATE INDEX ON public.muse_method (type_id, state); - - -- 方法版本:append-only;绑定与消费都指向具体版本。 - CREATE TABLE public.muse_method_version ( - version_id uuid PRIMARY KEY, - method_id uuid NOT NULL REFERENCES public.muse_method(method_id), - version bigint NOT NULL CHECK (version > 0), - content jsonb NOT NULL CHECK (jsonb_typeof(content) = 'object'), - content_hash text NOT NULL, - 参数上限 jsonb NOT NULL CHECK (jsonb_typeof(参数上限) = 'object'), - schema_id text NOT NULL, - schema_version int NOT NULL, - effective_schema_hash text NOT NULL, - proposal_id uuid, - confirmed_by text NOT NULL, - confirmed_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (method_id, version), - UNIQUE (method_id, content_hash) - ); - - -- 方法提案:审阅对象;确认后版本入 append-only 表,提案保留可追溯。 - CREATE TABLE public.muse_method_proposal ( - proposal_id uuid PRIMARY KEY, - method_id uuid NOT NULL, - revision bigint NOT NULL CHECK (revision >= 1), - request jsonb NOT NULL CHECK (jsonb_typeof(request) = 'object'), - proposal_hash text NOT NULL, - created_by text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (method_id, revision) - ); - - -- 证据与反例:来源(B03 版本钉住)、样例、反例、例外与静态方法资源引用(不复制正文)。 - CREATE TABLE public.muse_method_evidence ( - evidence_id uuid PRIMARY KEY, - method_id uuid NOT NULL REFERENCES public.muse_method(method_id), - kind text NOT NULL CHECK (kind IN ('source','sample','counter','exception','static_ref')), - ref jsonb NOT NULL CHECK (jsonb_typeof(ref) = 'object'), - note text NOT NULL DEFAULT '', - created_at timestamptz NOT NULL DEFAULT clock_timestamp() - ); - CREATE INDEX ON public.muse_method_evidence (method_id, kind); - - -- 方法绑定:作品或规划目标固定到具体版本;active 唯一;重绑留痕可回查。 - CREATE TABLE public.muse_method_binding ( - binding_id uuid PRIMARY KEY, - work_id text NOT NULL, - target_kind text NOT NULL CHECK (target_kind IN ('work','planning')), - target_ref text NOT NULL, - method_id uuid NOT NULL REFERENCES public.muse_method(method_id), - version_id uuid NOT NULL REFERENCES public.muse_method_version(version_id), - bound_by text NOT NULL, - bound_at timestamptz NOT NULL DEFAULT clock_timestamp(), - released_at timestamptz, - CHECK (target_ref <> '') - ); - CREATE UNIQUE INDEX muse_method_binding_active - ON public.muse_method_binding (work_id, target_ref, method_id) - WHERE released_at IS NULL; - - -- 方法消费:不可变;kind 区分生成/审阅/规划/启用验证;上下文与结果都可定位。 - CREATE TABLE public.muse_method_usage ( - usage_id uuid PRIMARY KEY, - method_version_id uuid NOT NULL REFERENCES public.muse_method_version(version_id), - kind text NOT NULL CHECK (kind IN ('generation','review','planning','enablement')), - context_ref text NOT NULL, - fragment_hash text NOT NULL, - result_ref text, - task_id uuid, - created_by text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (method_version_id, kind, context_ref, fragment_hash) - ); - CREATE INDEX ON public.muse_method_usage (method_version_id, created_at); - - -- 方法检索索引:每版本一向量;embedder 版本随行;重建整表重写,不动方法本体。 - CREATE TABLE public.muse_method_index ( - method_version_id uuid PRIMARY KEY REFERENCES public.muse_method_version(version_id), - 检索文本 text NOT NULL, - 检索文本哈希 text NOT NULL, - vector double precision[] NOT NULL CHECK (array_length(vector, 1) > 0), - embedder text NOT NULL, - built_at timestamptz NOT NULL DEFAULT clock_timestamp() - ); - - -- 索引版本台账:当前有效索引身份;检索时对不上即拒绝为陈旧。 - CREATE TABLE public.muse_method_index_version ( - ledger_id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY, - 索引身份 text NOT NULL, - embedder text NOT NULL, - method_count int NOT NULL CHECK (method_count >= 0), - built_at timestamptz NOT NULL DEFAULT clock_timestamp(), - active boolean NOT NULL DEFAULT false - ); - CREATE UNIQUE INDEX muse_method_index_active ON public.muse_method_index_version (active) - WHERE active; - - -- 文档派生索引:承接章后流程登记的摘要绑定,关键词可查。 - CREATE TABLE public.muse_document_index ( - document_id text NOT NULL, - revision bigint NOT NULL CHECK (revision >= 0), - document_hash text NOT NULL, - 结构哈希 text NOT NULL, - summary text NOT NULL DEFAULT '', - registered_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY (document_id, revision) - ); -END -$migration$; diff --git a/数据库/迁移/V0023__模型规划与调用级消费.sql b/数据库/迁移/V0023__模型规划与调用级消费.sql deleted file mode 100644 index dc85dfe..0000000 --- a/数据库/迁移/V0023__模型规划与调用级消费.sql +++ /dev/null @@ -1,32 +0,0 @@ --- 模型规划只落候选,来源绑定独立保存;正式规划仍由作者决定。 -CREATE TABLE public.muse_model_plan_candidate ( - candidate_id uuid PRIMARY KEY REFERENCES public.muse_plan_candidate(candidate_id), - task_id uuid NOT NULL REFERENCES public.muse_task(task_id), - snapshot_id uuid NOT NULL REFERENCES public.muse_context_snapshot(snapshot_id), - call_id text NOT NULL, - model_evidence jsonb NOT NULL CHECK (jsonb_typeof(model_evidence)='object'), - prompt_hash text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (task_id, call_id) -); - --- 同一快照可能由不同真实调用消费;不能将后一次调用冒充前一次的幂等回执。 -DO $migration$ -DECLARE - old_constraint text; -BEGIN - SELECT conname INTO old_constraint FROM pg_constraint - WHERE conrelid='public.muse_method_usage'::regclass AND contype='u' - AND pg_get_constraintdef(oid)='UNIQUE (method_version_id, kind, context_ref, fragment_hash)'; - IF old_constraint IS NULL THEN - RAISE EXCEPTION '消费键约束缺失,不能盲目替换'; - END IF; - EXECUTE format('ALTER TABLE public.muse_method_usage DROP CONSTRAINT %I', old_constraint); -END -$migration$; -ALTER TABLE public.muse_method_usage ADD CONSTRAINT method_usage_call_key - UNIQUE (method_version_id, kind, context_ref, fragment_hash, task_id, result_ref); --- 历史无任务/调用回执维持原来的单键约束,不将其升级为真实模型消费。 -CREATE UNIQUE INDEX method_usage_legacy_key ON public.muse_method_usage - (method_version_id, kind, context_ref, fragment_hash) - WHERE task_id IS NULL OR result_ref IS NULL; diff --git a/数据库/迁移/V0024__模型派发授权依据.sql b/数据库/迁移/V0024__模型派发授权依据.sql deleted file mode 100644 index 303eecc..0000000 --- a/数据库/迁移/V0024__模型派发授权依据.sql +++ /dev/null @@ -1,19 +0,0 @@ --- 派发授权与发送状态同事务;技术回执不保存原文,不补造历史调用的授权。 -DO $迁移$ -DECLARE - 目标 text; -BEGIN - FOREACH 目标 IN ARRAY ARRAY['public', 'evaluation'] - LOOP - EXECUTE format( - 'ALTER TABLE %I.muse_runtime_evidence DROP CONSTRAINT muse_runtime_evidence_kind_check', - 目标 - ); - EXECUTE format( - 'ALTER TABLE %I.muse_runtime_evidence ADD CONSTRAINT muse_runtime_evidence_kind_check ' - 'CHECK (kind IN (''model_input'',''model_response'',''model_dispatch'',''tool_result'',''failure''))', - 目标 - ); - END LOOP; -END -$迁移$; diff --git a/数据库/迁移/V0025__旧库迁移来源与映射.sql b/数据库/迁移/V0025__旧库迁移来源与映射.sql deleted file mode 100644 index 24d78ad..0000000 --- a/数据库/迁移/V0025__旧库迁移来源与映射.sql +++ /dev/null @@ -1,70 +0,0 @@ --- 数据演进:隔离目标身份与迁移来源/回执;不代替任何业务域的实体或候选表。 -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(); diff --git a/数据库/迁移/V0026__参考分析版本.sql b/数据库/迁移/V0026__参考分析版本.sql deleted file mode 100644 index 56e87c5..0000000 --- a/数据库/迁移/V0026__参考分析版本.sql +++ /dev/null @@ -1,23 +0,0 @@ --- B03拥有完整分析;S02检查点只保留运行证据与结果引用。 -CREATE TABLE public.muse_source_analysis ( - author_id text NOT NULL, - analysis_id text NOT NULL, - revision bigint NOT NULL DEFAULT 1 CHECK (revision = 1), - source_id uuid NOT NULL, - source_revision bigint NOT NULL CHECK (source_revision > 0), - source_content_hash text NOT NULL CHECK (source_content_hash ~ '^[0-9a-f]{64}$'), - origin text NOT NULL CHECK (origin IN ('model','checkpoint_history','legacy_import')), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload) = 'object'), - content_hash text NOT NULL CHECK (content_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY (analysis_id), - FOREIGN KEY (source_id, source_revision) REFERENCES public.muse_source_version(source_id, revision) -); -CREATE INDEX ON public.muse_source_analysis (author_id, source_id, created_at DESC, analysis_id); -CREATE FUNCTION public.muse_guard_source_analysis() RETURNS trigger LANGUAGE plpgsql AS $$ -BEGIN - RAISE EXCEPTION '分析版本只追加,不改写或删除历史'; -END; -$$; -CREATE TRIGGER muse_source_analysis_guard BEFORE UPDATE OR DELETE ON public.muse_source_analysis -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_source_analysis(); diff --git a/数据库/迁移/V0027__作品声音版本.sql b/数据库/迁移/V0027__作品声音版本.sql deleted file mode 100644 index 3de5b77..0000000 --- a/数据库/迁移/V0027__作品声音版本.sql +++ /dev/null @@ -1,37 +0,0 @@ --- 全书声音候选与确认版本;人物语言指纹仍归B02。 -CREATE TABLE public.muse_voice_proposal ( - proposal_id uuid PRIMARY KEY, - author_id text NOT NULL, - work_id text NOT NULL REFERENCES public.muse_work(work_id), - revision bigint NOT NULL DEFAULT 1 CHECK (revision = 1), - base_revision bigint NOT NULL CHECK (base_revision >= 0), - request jsonb NOT NULL CHECK (jsonb_typeof(request) = 'object'), - proposal_hash text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TABLE public.muse_voice_version ( - version_id uuid PRIMARY KEY, - work_id text NOT NULL REFERENCES public.muse_work(work_id), - revision bigint NOT NULL CHECK (revision > 0), - proposal_id uuid NOT NULL UNIQUE REFERENCES public.muse_voice_proposal(proposal_id), - content_hash text NOT NULL, - effective_schema_hash text NOT NULL, - projection_version text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (work_id, revision), - UNIQUE (work_id, version_id) -); -CREATE TABLE public.muse_voice_current ( - work_id text PRIMARY KEY REFERENCES public.muse_work(work_id), - version_id uuid NOT NULL, - FOREIGN KEY (work_id, version_id) REFERENCES public.muse_voice_version(work_id, version_id) -); -CREATE FUNCTION public.muse_guard_voice_history() RETURNS trigger LANGUAGE plpgsql AS $$ -BEGIN - RAISE EXCEPTION '声音提案与历史版本只追加,不改写或删除'; -END; -$$; -CREATE TRIGGER muse_voice_proposal_guard BEFORE UPDATE OR DELETE ON public.muse_voice_proposal -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_voice_history(); -CREATE TRIGGER muse_voice_version_guard BEFORE UPDATE OR DELETE ON public.muse_voice_version -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_voice_history(); diff --git a/数据库/迁移/V0028__文学审校报告.sql b/数据库/迁移/V0028__文学审校报告.sql deleted file mode 100644 index 2aed3d2..0000000 --- a/数据库/迁移/V0028__文学审校报告.sql +++ /dev/null @@ -1,34 +0,0 @@ --- 文学片结果和完整报告由B06持有,任务运行只记录引用和执行证据。 -CREATE TABLE public.muse_literary_shard ( - task_id uuid NOT NULL REFERENCES public.muse_task(task_id), - shard_id text NOT NULL CHECK (shard_id ~ '^[0-9a-f]{64}$'), - attempt_id uuid NOT NULL REFERENCES public.muse_attempt(attempt_id), - call_id text NOT NULL, - author_id text NOT NULL, - snapshot_id uuid NOT NULL REFERENCES public.muse_context_snapshot(snapshot_id), - basis_hash text NOT NULL CHECK (basis_hash ~ '^[0-9a-f]{64}$'), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload) = 'object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - evidence jsonb NOT NULL CHECK (jsonb_typeof(evidence) = 'object'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY (task_id, shard_id), - UNIQUE (task_id, call_id) -); -CREATE TABLE public.muse_literary_report ( - report_id uuid PRIMARY KEY, - task_id uuid NOT NULL UNIQUE REFERENCES public.muse_task(task_id), - author_id text NOT NULL, - revision bigint NOT NULL DEFAULT 1 CHECK (revision = 1), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload) = 'object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE FUNCTION public.muse_guard_literary_history() RETURNS trigger LANGUAGE plpgsql AS $$ -BEGIN - RAISE EXCEPTION '文学片结果与报告只追加,不改写或删除历史'; -END; -$$; -CREATE TRIGGER muse_literary_shard_guard BEFORE UPDATE OR DELETE ON public.muse_literary_shard -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_literary_report_guard BEFORE UPDATE OR DELETE ON public.muse_literary_report -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0029__规则候选与诊断.sql b/数据库/迁移/V0029__规则候选与诊断.sql deleted file mode 100644 index 03c7ea2..0000000 --- a/数据库/迁移/V0029__规则候选与诊断.sql +++ /dev/null @@ -1,31 +0,0 @@ --- 规则种子只生成候选;启用记录由后续B10评测及S01批准产生。 -CREATE TABLE public.muse_rule_version ( - version_id uuid PRIMARY KEY, - author_id text NOT NULL, - rule_id text NOT NULL, - revision bigint NOT NULL CHECK (revision > 0), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload) = 'object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id, rule_id, revision) -); -CREATE TABLE public.muse_rule_activation ( - author_id text NOT NULL, - rule_id text NOT NULL, - version_id uuid NOT NULL REFERENCES public.muse_rule_version(version_id), - evaluation_ref text NOT NULL, - approval_ref text NOT NULL, - PRIMARY KEY(author_id, rule_id) -); -CREATE TABLE public.muse_diagnosis ( - diagnosis_id uuid PRIMARY KEY, - author_id text NOT NULL, - work_id text NOT NULL REFERENCES public.muse_work(work_id), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload) = 'object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TRIGGER muse_rule_version_guard BEFORE UPDATE OR DELETE ON public.muse_rule_version -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_diagnosis_guard BEFORE UPDATE OR DELETE ON public.muse_diagnosis -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0030__模型修订结果.sql b/数据库/迁移/V0030__模型修订结果.sql deleted file mode 100644 index b1abb04..0000000 --- a/数据库/迁移/V0030__模型修订结果.sql +++ /dev/null @@ -1,16 +0,0 @@ --- 模型修订只追加结果与来源;正文候选仍由B05拥有。 -CREATE TABLE public.muse_revision_result ( - task_id uuid PRIMARY KEY REFERENCES public.muse_task(task_id), - author_id text NOT NULL, - attempt_id uuid NOT NULL REFERENCES public.muse_attempt(attempt_id), - call_id text NOT NULL, - diagnosis_id uuid NOT NULL REFERENCES public.muse_diagnosis(diagnosis_id), - candidate_id uuid REFERENCES public.muse_writing_candidate(candidate_id), - outcome text NOT NULL CHECK (outcome IN ('candidate','original','rejected')), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload) = 'object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - CHECK ((outcome='candidate') = (candidate_id IS NOT NULL)) -); -CREATE TRIGGER muse_revision_result_guard BEFORE UPDATE OR DELETE ON public.muse_revision_result -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0031__正文分支来源.sql b/数据库/迁移/V0031__正文分支来源.sql deleted file mode 100644 index 5be6714..0000000 --- a/数据库/迁移/V0031__正文分支来源.sql +++ /dev/null @@ -1,34 +0,0 @@ --- B05分支只保存起点;正文内容仍归既有document/version表。 -CREATE TABLE public.muse_document_branch ( - document_id uuid PRIMARY KEY REFERENCES public.muse_document(document_id), - source_document_id uuid NOT NULL, - source_revision bigint NOT NULL, - source_hash text NOT NULL, - author_id text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - CHECK(document_id <> source_document_id), - FOREIGN KEY(source_document_id,source_revision) - REFERENCES public.muse_document_version(document_id,revision) -); -CREATE TABLE public.muse_branch_merge_source ( - candidate_id uuid NOT NULL, - candidate_revision bigint NOT NULL, - source_document_id uuid NOT NULL REFERENCES public.muse_document_branch(document_id), - source_revision bigint NOT NULL, - source_hash text NOT NULL, - merge_basis jsonb NOT NULL, - PRIMARY KEY(candidate_id,candidate_revision), - FOREIGN KEY(candidate_id,candidate_revision) - REFERENCES public.muse_writing_candidate_version(candidate_id,revision), - FOREIGN KEY(source_document_id,source_revision) - REFERENCES public.muse_document_version(document_id,revision) -); -CREATE FUNCTION public.muse_branch_source_immutable() RETURNS trigger LANGUAGE plpgsql AS $$ -BEGIN - RAISE EXCEPTION 'branch and merge origins are immutable'; -END; -$$; -CREATE TRIGGER document_branch_immutable BEFORE UPDATE OR DELETE ON public.muse_document_branch - FOR EACH ROW EXECUTE FUNCTION public.muse_branch_source_immutable(); -CREATE TRIGGER branch_merge_source_immutable BEFORE UPDATE OR DELETE ON public.muse_branch_merge_source - FOR EACH ROW EXECUTE FUNCTION public.muse_branch_source_immutable(); diff --git a/数据库/迁移/V0032__选段修订依据.sql b/数据库/迁移/V0032__选段修订依据.sql deleted file mode 100644 index 0624e6f..0000000 --- a/数据库/迁移/V0032__选段修订依据.sql +++ /dev/null @@ -1,6 +0,0 @@ --- 通用作者圈选复用修订交付与恢复;没有诊断时不伪造诊断身份。 -ALTER TABLE public.muse_revision_result ALTER COLUMN diagnosis_id DROP NOT NULL; -ALTER TABLE public.muse_revision_result ADD COLUMN source_kind text NOT NULL DEFAULT 'diagnosis' - CHECK(source_kind IN ('diagnosis','selection')); -ALTER TABLE public.muse_revision_result ADD CONSTRAINT revision_source_kind_check - CHECK ((source_kind='diagnosis')=(diagnosis_id IS NOT NULL)); diff --git a/数据库/迁移/V0033__质量案例.sql b/数据库/迁移/V0033__质量案例.sql deleted file mode 100644 index 741c731..0000000 --- a/数据库/迁移/V0033__质量案例.sql +++ /dev/null @@ -1,20 +0,0 @@ --- B06案例版本只追加,当前指针由S01作者操作推进。 -CREATE TABLE public.muse_quality_case ( - case_id uuid PRIMARY KEY, - author_id text NOT NULL, - current_revision bigint NOT NULL CHECK(current_revision>0) -); -CREATE TABLE public.muse_quality_case_version ( - case_id uuid NOT NULL REFERENCES public.muse_quality_case(case_id), - revision bigint NOT NULL CHECK(revision>0), - state text NOT NULL CHECK(state IN ('shadow','confirmed','withdrawn')), - payload jsonb NOT NULL CHECK(jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK(payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(case_id,revision) -); -ALTER TABLE public.muse_quality_case ADD CONSTRAINT quality_case_current_fk - FOREIGN KEY(case_id,current_revision) REFERENCES public.muse_quality_case_version(case_id,revision) - DEFERRABLE INITIALLY DEFERRED; -CREATE TRIGGER quality_case_history_guard BEFORE UPDATE OR DELETE ON public.muse_quality_case_version - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0034__隔离数据集与实验.sql b/数据库/迁移/V0034__隔离数据集与实验.sql deleted file mode 100644 index c8e3e2e..0000000 --- a/数据库/迁移/V0034__隔离数据集与实验.sql +++ /dev/null @@ -1,46 +0,0 @@ --- B10公开输入与答案分区封存;muse_app不能访问evaluation/oracle。 -CREATE TABLE evaluation.muse_dataset_version ( - version_id uuid PRIMARY KEY, - dataset_id text NOT NULL, - revision bigint NOT NULL CHECK(revision>0), - public_manifest jsonb NOT NULL CHECK(jsonb_typeof(public_manifest)='object'), - public_hash text NOT NULL CHECK(public_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(dataset_id,revision) -); -CREATE TABLE oracle.muse_dataset_answers ( - version_id uuid PRIMARY KEY REFERENCES evaluation.muse_dataset_version(version_id), - answers jsonb NOT NULL CHECK(jsonb_typeof(answers)='array'), - answer_hash text NOT NULL CHECK(answer_hash ~ '^[0-9a-f]{64}$') -); --- 发布资料由维护入口写;评测角色只能读取封存输入,不修改样本与分割。 -REVOKE INSERT,UPDATE,DELETE,TRUNCATE ON evaluation.muse_dataset_version FROM muse_eval; -CREATE TABLE evaluation.muse_experiment ( - experiment_id uuid PRIMARY KEY, - author_id text NOT NULL, - command_id text NOT NULL, - request_hash text NOT NULL CHECK(request_hash ~ '^[0-9a-f]{64}$'), - dataset_version_id uuid NOT NULL REFERENCES evaluation.muse_dataset_version(version_id), - conditions jsonb NOT NULL CHECK(jsonb_typeof(conditions)='object'), - conditions_hash text NOT NULL CHECK(conditions_hash ~ '^[0-9a-f]{64}$'), - sample_ids jsonb NOT NULL CHECK(jsonb_typeof(sample_ids)='array' AND jsonb_array_length(sample_ids)>0), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,command_id) -); -CREATE TABLE oracle.muse_blind_assignment ( - assignment_id uuid PRIMARY KEY, - experiment_id uuid NOT NULL REFERENCES evaluation.muse_experiment(experiment_id), - sample_id text NOT NULL, - arm_order jsonb NOT NULL CHECK(jsonb_typeof(arm_order)='array'), - UNIQUE(experiment_id,sample_id) -); --- 编排可追加匿名映射,不增加答案写权限或映射更新权限。 -GRANT INSERT ON oracle.muse_blind_assignment TO muse_eval; -CREATE TRIGGER dataset_history_guard BEFORE UPDATE OR DELETE ON evaluation.muse_dataset_version -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER answer_history_guard BEFORE UPDATE OR DELETE ON oracle.muse_dataset_answers -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER experiment_history_guard BEFORE UPDATE OR DELETE ON evaluation.muse_experiment -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER assignment_history_guard BEFORE UPDATE OR DELETE ON oracle.muse_blind_assignment -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0035__评测逐例执行.sql b/数据库/迁移/V0035__评测逐例执行.sql deleted file mode 100644 index 78316c1..0000000 --- a/数据库/迁移/V0035__评测逐例执行.sql +++ /dev/null @@ -1,43 +0,0 @@ --- B10执行计划、单元归属和原始交付;任务/尝试/费用继续由S02拥有。 -CREATE TABLE evaluation.muse_experiment_execution ( - experiment_id uuid PRIMARY KEY REFERENCES evaluation.muse_experiment(experiment_id), - request_hash text NOT NULL, - plan jsonb NOT NULL, - plan_hash text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TABLE evaluation.muse_evaluation_unit ( - unit_id uuid PRIMARY KEY, - experiment_id uuid NOT NULL REFERENCES evaluation.muse_experiment_execution(experiment_id), - sample_id text NOT NULL, - kind text NOT NULL CHECK(kind IN ('generation','comparison')), - specification jsonb NOT NULL, - specification_hash text NOT NULL, - task_id uuid UNIQUE REFERENCES evaluation.muse_task(task_id) -); -CREATE TABLE evaluation.muse_evaluation_output ( - unit_id uuid PRIMARY KEY REFERENCES evaluation.muse_evaluation_unit(unit_id), - task_id uuid NOT NULL REFERENCES evaluation.muse_task(task_id), - attempt_id uuid NOT NULL, - call_id text NOT NULL UNIQUE, - user_input_hash text NOT NULL, - output jsonb NOT NULL, - output_hash text NOT NULL, - evidence jsonb NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TRIGGER evaluation_execution_guard BEFORE UPDATE OR DELETE ON evaluation.muse_experiment_execution -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER evaluation_output_guard BEFORE UPDATE OR DELETE ON evaluation.muse_evaluation_output -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE FUNCTION evaluation.muse_guard_unit_binding() RETURNS trigger LANGUAGE plpgsql AS $$ -BEGIN - IF TG_OP='DELETE' THEN RAISE EXCEPTION 'evaluation unit is immutable'; END IF; - IF OLD.task_id IS NOT NULL OR NEW.task_id IS NULL OR - (to_jsonb(OLD)-'task_id') <> (to_jsonb(NEW)-'task_id') THEN - RAISE EXCEPTION 'only first task binding is allowed'; - END IF; - RETURN NEW; -END $$; -CREATE TRIGGER evaluation_unit_guard BEFORE UPDATE OR DELETE ON evaluation.muse_evaluation_unit -FOR EACH ROW EXECUTE FUNCTION evaluation.muse_guard_unit_binding(); diff --git a/数据库/迁移/V0036__评测停止决定.sql b/数据库/迁移/V0036__评测停止决定.sql deleted file mode 100644 index 0f8978c..0000000 --- a/数据库/迁移/V0036__评测停止决定.sql +++ /dev/null @@ -1,9 +0,0 @@ --- 停止决定独立追加,执行计划与已发生交付保持不变。 -CREATE TABLE evaluation.muse_experiment_stop ( - experiment_id uuid PRIMARY KEY REFERENCES evaluation.muse_experiment_execution(experiment_id), - author_id text NOT NULL, - command_id text NOT NULL, - stopped_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TRIGGER experiment_stop_guard BEFORE UPDATE OR DELETE ON evaluation.muse_experiment_stop -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0037__逐调用交付确认.sql b/数据库/迁移/V0037__逐调用交付确认.sql deleted file mode 100644 index afc9541..0000000 --- a/数据库/迁移/V0037__逐调用交付确认.sql +++ /dev/null @@ -1,20 +0,0 @@ --- S02逐调用的保存确认;尝试上的最后调用指针不再充当全部回合的历史。 -DO $$ -DECLARE - scope_name text; -BEGIN - FOREACH scope_name IN ARRAY ARRAY['public', 'evaluation'] LOOP - EXECUTE format($ddl$ - CREATE TABLE %1$I.muse_model_delivery ( - call_id text 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), - response_evidence_id uuid NOT NULL REFERENCES %1$I.muse_runtime_evidence(evidence_id), - response_hash text NOT NULL CHECK(response_hash ~ '^[0-9a-f]{64}$'), - confirmed_at timestamptz NOT NULL DEFAULT clock_timestamp() - ); - CREATE TRIGGER model_delivery_guard BEFORE UPDATE OR DELETE ON %1$I.muse_model_delivery - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); - $ddl$, scope_name); - END LOOP; -END $$; diff --git a/数据库/迁移/V0038__评测引文拒绝.sql b/数据库/迁移/V0038__评测引文拒绝.sql deleted file mode 100644 index 159da7e..0000000 --- a/数据库/迁移/V0038__评测引文拒绝.sql +++ /dev/null @@ -1,17 +0,0 @@ --- B10保存已由S02确认的引文拒绝;不覆盖原回合,也不重置纠正次数。 -CREATE TABLE evaluation.muse_comparison_rejection ( - unit_id uuid NOT NULL REFERENCES evaluation.muse_evaluation_unit(unit_id), - sequence smallint NOT NULL CHECK(sequence BETWEEN 1 AND 3), - task_id uuid NOT NULL REFERENCES evaluation.muse_task(task_id), - attempt_id uuid NOT NULL REFERENCES evaluation.muse_attempt(attempt_id), - call_id text NOT NULL UNIQUE, - user_input_hash text NOT NULL CHECK(user_input_hash ~ '^[0-9a-f]{64}$'), - output jsonb NOT NULL, - failure_code text NOT NULL CHECK(failure_code IN ('PAIRWISE_QUOTE_NOT_FOUND','PAIRWISE_NOT_EXECUTED')), - previous_hash text CHECK(previous_hash ~ '^[0-9a-f]{64}$'), - record_hash text NOT NULL CHECK(record_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(unit_id, sequence) -); -CREATE TRIGGER comparison_rejection_guard BEFORE UPDATE OR DELETE ON evaluation.muse_comparison_rejection -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0039__评测条件第三.sql b/数据库/迁移/V0039__评测条件第三.sql deleted file mode 100644 index 7d5ea88..0000000 --- a/数据库/迁移/V0039__评测条件第三.sql +++ /dev/null @@ -1,10 +0,0 @@ --- 条件第三决议只追加,保存初评实际交付依据;不以缺少任务推断无需第三评。 -CREATE TABLE evaluation.muse_evaluation_condition ( - unit_id uuid PRIMARY KEY REFERENCES evaluation.muse_evaluation_unit(unit_id), - decision jsonb NOT NULL, - decision_hash text NOT NULL CHECK(decision_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TRIGGER evaluation_condition_guard -BEFORE UPDATE OR DELETE ON evaluation.muse_evaluation_condition -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0040__标定金标准与凭据.sql b/数据库/迁移/V0040__标定金标准与凭据.sql deleted file mode 100644 index bd0ded4..0000000 --- a/数据库/迁移/V0040__标定金标准与凭据.sql +++ /dev/null @@ -1,18 +0,0 @@ --- 金标准由维护者先于评委任务封存;标定结果不具有生产写入权。 -CREATE TABLE oracle.muse_calibration_gold ( - experiment_id uuid PRIMARY KEY REFERENCES evaluation.muse_experiment(experiment_id), - payload jsonb NOT NULL CHECK(jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK(payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TRIGGER calibration_gold_guard BEFORE UPDATE OR DELETE ON oracle.muse_calibration_gold -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TABLE evaluation.muse_calibration_receipt ( - experiment_id uuid PRIMARY KEY REFERENCES evaluation.muse_experiment(experiment_id), - receipt_id uuid NOT NULL UNIQUE, - payload jsonb NOT NULL CHECK(jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK(payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TRIGGER calibration_receipt_guard BEFORE UPDATE OR DELETE ON evaluation.muse_calibration_receipt -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0041__评测语义检测单元.sql b/数据库/迁移/V0041__评测语义检测单元.sql deleted file mode 100644 index a7c826c..0000000 --- a/数据库/迁移/V0041__评测语义检测单元.sql +++ /dev/null @@ -1,4 +0,0 @@ --- B10沿用既有单元、交付及S02任务;只扩充检测种类,不修改旧记录。 -ALTER TABLE evaluation.muse_evaluation_unit DROP CONSTRAINT muse_evaluation_unit_kind_check; -ALTER TABLE evaluation.muse_evaluation_unit ADD CONSTRAINT muse_evaluation_unit_kind_check -CHECK(kind IN ('generation','comparison','detection')); diff --git a/数据库/迁移/V0042__效果判据凭据.sql b/数据库/迁移/V0042__效果判据凭据.sql deleted file mode 100644 index 856bf2e..0000000 --- a/数据库/迁移/V0042__效果判据凭据.sql +++ /dev/null @@ -1,10 +0,0 @@ --- 阈值判断记录只属于隔离评测;不能直接当作生产目标的启用回执。 -CREATE TABLE evaluation.muse_effect_assessment ( - experiment_id uuid PRIMARY KEY REFERENCES evaluation.muse_experiment(experiment_id), - receipt_id uuid NOT NULL UNIQUE, - payload jsonb NOT NULL, - payload_hash text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TRIGGER effect_assessment_guard BEFORE UPDATE OR DELETE ON evaluation.muse_effect_assessment -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0043__目标启用凭据.sql b/数据库/迁移/V0043__目标启用凭据.sql deleted file mode 100644 index 0913f2a..0000000 --- a/数据库/迁移/V0043__目标启用凭据.sql +++ /dev/null @@ -1,28 +0,0 @@ --- B10导出的最小启用证明;模型与生产角色都不能自行写入验证结论。 -CREATE TABLE public.muse_enablement_receipt ( - receipt_id uuid PRIMARY KEY, - author_id text NOT NULL, - experiment_id uuid NOT NULL REFERENCES evaluation.muse_experiment(experiment_id), - basis_experiment_ids uuid[] NOT NULL CHECK (cardinality(basis_experiment_ids)>0), - effect_receipt_id uuid NOT NULL, - payload jsonb NOT NULL CHECK (jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - valid_until timestamptz NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,experiment_id,payload_hash) -); -REVOKE ALL ON public.muse_enablement_receipt FROM muse_app, muse_eval; -CREATE TRIGGER enablement_receipt_guard BEFORE UPDATE OR DELETE ON public.muse_enablement_receipt -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); - --- 只暴露已导出的证明与停止布尔值;不暴露答案、匿名映射或评测候选。 -CREATE VIEW public.muse_enablement_status WITH (security_barrier=true) AS -SELECT r.receipt_id,r.author_id,r.experiment_id,r.basis_experiment_ids, - r.effect_receipt_id,r.payload,r.payload_hash,r.valid_until, - EXISTS ( - SELECT 1 FROM evaluation.muse_experiment_stop s - WHERE s.experiment_id=ANY(r.basis_experiment_ids) - ) AS stopped -FROM public.muse_enablement_receipt r; -REVOKE ALL ON public.muse_enablement_status FROM muse_app, muse_eval; -GRANT SELECT ON public.muse_enablement_status TO muse_app, muse_eval; diff --git a/数据库/迁移/V0044__作者偏好与反馈.sql b/数据库/迁移/V0044__作者偏好与反馈.sql deleted file mode 100644 index d0a1f20..0000000 --- a/数据库/迁移/V0044__作者偏好与反馈.sql +++ /dev/null @@ -1,34 +0,0 @@ --- B07作者偏好及反馈:当前指针和只追加历史分开,评测角色无生产内容权限。 -CREATE TABLE public.muse_preference ( - preference_id uuid PRIMARY KEY, - author_id text NOT NULL, - current_revision integer NOT NULL CHECK (current_revision > 0) -); -CREATE TABLE public.muse_preference_version ( - preference_id uuid NOT NULL REFERENCES public.muse_preference, - revision integer NOT NULL CHECK (revision > 0), - payload jsonb NOT NULL, - content_hash text NOT NULL CHECK (content_hash ~ '^[0-9a-f]{64}$'), - state text NOT NULL CHECK (state IN ('pending','active','withdrawn')), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY (preference_id,revision) -); -CREATE TABLE public.muse_author_feedback ( - feedback_id uuid PRIMARY KEY, - author_id text NOT NULL, - command_id text NOT NULL, - payload jsonb NOT NULL, - content_hash text NOT NULL CHECK (content_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE (author_id,command_id) -); -CREATE TRIGGER muse_preference_version_immutable BEFORE UPDATE OR DELETE - ON public.muse_preference_version FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_author_feedback_immutable BEFORE UPDATE OR DELETE - ON public.muse_author_feedback FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -REVOKE ALL ON public.muse_preference, public.muse_preference_version, - public.muse_author_feedback FROM muse_eval; -GRANT SELECT,INSERT,UPDATE ON public.muse_preference TO muse_app; -GRANT SELECT,INSERT ON public.muse_preference_version,public.muse_author_feedback TO muse_app; diff --git a/数据库/迁移/V0045__具体改进与目标回执.sql b/数据库/迁移/V0045__具体改进与目标回执.sql deleted file mode 100644 index 7a3a466..0000000 --- a/数据库/迁移/V0045__具体改进与目标回执.sql +++ /dev/null @@ -1,48 +0,0 @@ --- B07保存具体提案、意向和外部owner原回执;不复制目标生效状态。 -CREATE TABLE public.muse_improvement ( - improvement_id uuid PRIMARY KEY, - author_id text NOT NULL, - current_revision integer NOT NULL CHECK(current_revision > 0) -); -CREATE TABLE public.muse_improvement_version ( - improvement_id uuid NOT NULL REFERENCES public.muse_improvement, - revision integer NOT NULL CHECK(revision > 0), - payload jsonb NOT NULL, - content_hash text NOT NULL CHECK(content_hash ~ '^[0-9a-f]{64}$'), - feedback_ids uuid[] NOT NULL CHECK(cardinality(feedback_ids) > 0), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(improvement_id,revision) -); -CREATE TABLE public.muse_improvement_action ( - action_id uuid PRIMARY KEY, - author_id text NOT NULL, - command_id text NOT NULL, - improvement_id uuid NOT NULL, - revision integer NOT NULL, - kind text NOT NULL CHECK(kind IN ('validation','enable','disable')), - payload jsonb NOT NULL, - content_hash text NOT NULL CHECK(content_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,command_id), - FOREIGN KEY(improvement_id,revision) REFERENCES public.muse_improvement_version -); -CREATE TABLE public.muse_improvement_result ( - action_id uuid PRIMARY KEY REFERENCES public.muse_improvement_action, - receipt jsonb NOT NULL, - receipt_hash text NOT NULL CHECK(receipt_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TRIGGER muse_improvement_version_immutable BEFORE UPDATE OR DELETE - ON public.muse_improvement_version FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_improvement_action_immutable BEFORE UPDATE OR DELETE - ON public.muse_improvement_action FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_improvement_result_immutable BEFORE UPDATE OR DELETE - ON public.muse_improvement_result FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -REVOKE ALL ON public.muse_improvement,public.muse_improvement_version, - public.muse_improvement_action,public.muse_improvement_result FROM muse_eval; -GRANT SELECT,INSERT,UPDATE ON public.muse_improvement TO muse_app; -GRANT SELECT,INSERT ON public.muse_improvement_version,public.muse_improvement_action, - public.muse_improvement_result TO muse_app; diff --git a/数据库/迁移/V0046__作者长期观察.sql b/数据库/迁移/V0046__作者长期观察.sql deleted file mode 100644 index 8e880ba..0000000 --- a/数据库/迁移/V0046__作者长期观察.sql +++ /dev/null @@ -1,21 +0,0 @@ --- B07作者自报观察与实际反馈绑定;未知指标保留NULL,不自动建立因果或启用目标。 -CREATE TABLE public.muse_author_observation ( - observation_id uuid PRIMARY KEY, - author_id text NOT NULL, - command_id text NOT NULL, - feedback_ids uuid[] NOT NULL CHECK(cardinality(feedback_ids) > 0), - improvement_id uuid, - improvement_revision integer, - payload jsonb NOT NULL, - content_hash text NOT NULL CHECK(content_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,command_id), - CHECK ((improvement_id IS NULL) = (improvement_revision IS NULL)), - FOREIGN KEY(improvement_id,improvement_revision) - REFERENCES public.muse_improvement_version(improvement_id,revision) -); -CREATE TRIGGER muse_author_observation_immutable BEFORE UPDATE OR DELETE - ON public.muse_author_observation FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -REVOKE ALL ON public.muse_author_observation FROM muse_eval; -GRANT SELECT,INSERT ON public.muse_author_observation TO muse_app; diff --git a/数据库/迁移/V0047__定稿与导出产物.sql b/数据库/迁移/V0047__定稿与导出产物.sql deleted file mode 100644 index 391e465..0000000 --- a/数据库/迁移/V0047__定稿与导出产物.sql +++ /dev/null @@ -1,32 +0,0 @@ --- B08固定交付清单与导出字节;正文仍以B05版本为唯一权威。 -CREATE TABLE public.muse_delivery ( - delivery_id uuid PRIMARY KEY, - author_id text NOT NULL, - work_id text NOT NULL, - revision integer NOT NULL CHECK(revision > 0), - manifest jsonb NOT NULL, - manifest_hash text NOT NULL CHECK(manifest_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(work_id,revision), - CHECK(jsonb_array_length(manifest->'chapters') > 0) -); -CREATE TABLE public.muse_delivery_artifact ( - artifact_id uuid PRIMARY KEY, - delivery_id uuid NOT NULL REFERENCES public.muse_delivery, - format text NOT NULL CHECK(format IN ('txt','md','docx','epub')), - formatter_version text NOT NULL, - data bytea NOT NULL, - content_hash text NOT NULL CHECK(content_hash ~ '^[0-9a-f]{64}$'), - verification jsonb NOT NULL, - task_id uuid, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(delivery_id,format,formatter_version), - CHECK(octet_length(data) > 0) -); -CREATE TRIGGER muse_delivery_immutable BEFORE UPDATE OR DELETE - ON public.muse_delivery FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_delivery_artifact_immutable BEFORE UPDATE OR DELETE - ON public.muse_delivery_artifact FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -REVOKE ALL ON public.muse_delivery,public.muse_delivery_artifact FROM muse_eval; -GRANT SELECT,INSERT ON public.muse_delivery,public.muse_delivery_artifact TO muse_app; diff --git a/数据库/迁移/V0048__连载发布与读者反馈.sql b/数据库/迁移/V0048__连载发布与读者反馈.sql deleted file mode 100644 index 7495f69..0000000 --- a/数据库/迁移/V0048__连载发布与读者反馈.sql +++ /dev/null @@ -1,42 +0,0 @@ --- B08计划与真实发布分开;读者反馈没有run归因字段。 -CREATE TABLE public.muse_serial_plan ( - plan_id uuid PRIMARY KEY, - author_id text NOT NULL, - work_id text NOT NULL, - revision integer NOT NULL CHECK(revision > 0) -); -CREATE TABLE public.muse_serial_plan_version ( - plan_id uuid NOT NULL REFERENCES public.muse_serial_plan, - revision integer NOT NULL CHECK(revision > 0), - payload jsonb NOT NULL, - content_hash text NOT NULL, - PRIMARY KEY(plan_id, revision) -); -CREATE TABLE public.muse_release ( - release_id uuid PRIMARY KEY, - author_id text NOT NULL, - work_id text NOT NULL, - delivery_id uuid NOT NULL REFERENCES public.muse_delivery, - payload jsonb NOT NULL, - content_hash text NOT NULL -); -CREATE TABLE public.muse_reader_feedback ( - feedback_id uuid PRIMARY KEY, - author_id text NOT NULL, - work_id text NOT NULL, - release_id uuid REFERENCES public.muse_release, - payload jsonb NOT NULL, - content_hash text NOT NULL -); -CREATE TRIGGER muse_serial_history_immutable BEFORE UPDATE OR DELETE - ON public.muse_serial_plan_version FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_release_immutable BEFORE UPDATE OR DELETE - ON public.muse_release FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_reader_feedback_immutable BEFORE UPDATE OR DELETE - ON public.muse_reader_feedback FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -REVOKE ALL ON public.muse_serial_plan,public.muse_serial_plan_version, - public.muse_release,public.muse_reader_feedback FROM muse_eval; -GRANT SELECT,INSERT ON public.muse_serial_plan,public.muse_serial_plan_version, - public.muse_release,public.muse_reader_feedback TO muse_app; -GRANT UPDATE(revision) ON public.muse_serial_plan TO muse_app; diff --git a/数据库/迁移/V0049__运行版本只读核对.sql b/数据库/迁移/V0049__运行版本只读核对.sql deleted file mode 100644 index 12a69a1..0000000 --- a/数据库/迁移/V0049__运行版本只读核对.sql +++ /dev/null @@ -1,2 +0,0 @@ --- 运行角色只读数据版本,不获得迁移账本写权限;用于拒绝不兼容程序继续写入。 -GRANT SELECT ON public.muse_migration TO muse_app, muse_eval; diff --git a/数据库/迁移/V0050__跨模块交付引用约束.sql b/数据库/迁移/V0050__跨模块交付引用约束.sql deleted file mode 100644 index 47b1962..0000000 --- a/数据库/迁移/V0050__跨模块交付引用约束.sql +++ /dev/null @@ -1,15 +0,0 @@ --- 新版交付引用必须指向真实作品,同一发布和反馈不能跨作品错接;不改写历史行。 -ALTER TABLE public.muse_delivery ADD CONSTRAINT muse_delivery_work_fk - FOREIGN KEY(work_id) REFERENCES public.muse_work(work_id); -ALTER TABLE public.muse_serial_plan ADD CONSTRAINT muse_serial_work_fk - FOREIGN KEY(work_id) REFERENCES public.muse_work(work_id); -ALTER TABLE public.muse_delivery ADD CONSTRAINT muse_delivery_work_identity - UNIQUE(delivery_id,work_id); -ALTER TABLE public.muse_release ADD CONSTRAINT muse_release_delivery_work_fk - FOREIGN KEY(delivery_id,work_id) REFERENCES public.muse_delivery(delivery_id,work_id); -ALTER TABLE public.muse_release ADD CONSTRAINT muse_release_work_identity - UNIQUE(release_id,work_id); -ALTER TABLE public.muse_reader_feedback ADD CONSTRAINT muse_feedback_work_fk - FOREIGN KEY(work_id) REFERENCES public.muse_work(work_id); -ALTER TABLE public.muse_reader_feedback ADD CONSTRAINT muse_feedback_release_work_fk - FOREIGN KEY(release_id,work_id) REFERENCES public.muse_release(release_id,work_id); diff --git a/数据库/迁移/V0051__工作台任务盘点视图.sql b/数据库/迁移/V0051__工作台任务盘点视图.sql deleted file mode 100644 index 08656f3..0000000 --- a/数据库/迁移/V0051__工作台任务盘点视图.sql +++ /dev/null @@ -1,10 +0,0 @@ --- 仅聚合本用途的任务,不包含冻结输入、原文或模型凭据;按作者过滤由S02公开入口执行。 -CREATE VIEW public.muse_task_inventory WITH (security_barrier=true) AS - SELECT author_id,run_purpose,state,count(*) AS task_count - FROM public.muse_task GROUP BY author_id,run_purpose,state; -CREATE VIEW evaluation.muse_task_inventory WITH (security_barrier=true) AS - SELECT author_id,run_purpose,state,count(*) AS task_count - FROM evaluation.muse_task GROUP BY author_id,run_purpose,state; -REVOKE ALL ON public.muse_task_inventory,evaluation.muse_task_inventory FROM PUBLIC,muse_app,muse_eval; -GRANT SELECT ON public.muse_task_inventory TO muse_app; -GRANT SELECT ON evaluation.muse_task_inventory TO muse_eval; diff --git a/数据库/迁移/V0052__持久返修会话.sql b/数据库/迁移/V0052__持久返修会话.sql deleted file mode 100644 index 06b054a..0000000 --- a/数据库/迁移/V0052__持久返修会话.sql +++ /dev/null @@ -1,81 +0,0 @@ --- B06 只登记作者控制的有限返修会话、轮任务引用和选择;实际模型任务与候选仍归 S02/B05。 -CREATE TABLE public.muse_revision_session ( - session_id uuid PRIMARY KEY, - author_id text NOT NULL, - create_command_id text NOT NULL, - request_hash text NOT NULL CHECK(request_hash ~ '^[0-9a-f]{64}$'), - work_id text NOT NULL REFERENCES public.muse_work(work_id), - chapter_id text NOT NULL REFERENCES public.muse_chapter(chapter_id), - branch_id text NOT NULL, - original_revision bigint NOT NULL CHECK(original_revision > 0), - original_document_hash text NOT NULL CHECK(original_document_hash ~ '^[0-9a-f]{64}$'), - source_kind text NOT NULL CHECK(source_kind IN ('diagnosis','selection')), - basis_hash text NOT NULL CHECK(basis_hash ~ '^[0-9a-f]{64}$'), - "authorization" jsonb NOT NULL CHECK(jsonb_typeof("authorization") = 'object'), - authorization_hash text NOT NULL CHECK(authorization_hash ~ '^[0-9a-f]{64}$'), - config_id text NOT NULL, - max_rounds integer NOT NULL CHECK(max_rounds BETWEEN 1 AND 5), - current_round integer NOT NULL DEFAULT 1 CHECK(current_round BETWEEN 1 AND 5), - state text NOT NULL CHECK(state IN ('preparing','running','awaiting_author','closed')), - stop_reason text, - stop_detail text, - author_choice text CHECK(author_choice IN ('original','candidate')), - selected_candidate_id uuid REFERENCES public.muse_writing_candidate(candidate_id), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - updated_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,create_command_id), - UNIQUE(session_id,author_id), - CHECK(current_round <= max_rounds), - CHECK((state = 'closed') = (stop_reason IS NOT NULL)), - CHECK( - (author_choice IS NULL AND selected_candidate_id IS NULL) - OR (author_choice = 'original' AND selected_candidate_id IS NULL) - OR (author_choice = 'candidate' AND selected_candidate_id IS NOT NULL) - ) -); - -CREATE TABLE public.muse_revision_round ( - session_id uuid NOT NULL REFERENCES public.muse_revision_session(session_id), - round_number integer NOT NULL CHECK(round_number BETWEEN 1 AND 5), - task_command_id text NOT NULL UNIQUE, - task_request_hash text NOT NULL CHECK(task_request_hash ~ '^[0-9a-f]{64}$'), - task_id uuid UNIQUE REFERENCES public.muse_task(task_id), - state text NOT NULL CHECK(state IN ('preparing','running','candidate','original','rejected')), - outcome text CHECK(outcome IN ('candidate','original','rejected')), - candidate_id uuid REFERENCES public.muse_writing_candidate(candidate_id), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - updated_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(session_id,round_number), - CHECK((task_id IS NULL) = (state = 'preparing')), - CHECK((outcome IS NULL) = (state IN ('preparing','running'))), - CHECK((outcome = 'candidate') = (candidate_id IS NOT NULL)) -); - -CREATE TABLE public.muse_revision_session_action ( - action_id uuid PRIMARY KEY, - session_id uuid NOT NULL REFERENCES public.muse_revision_session(session_id), - author_id text NOT NULL, - command_id text NOT NULL, - expected_round integer NOT NULL CHECK(expected_round BETWEEN 1 AND 5), - candidate_id uuid NOT NULL REFERENCES public.muse_writing_candidate(candidate_id), - choice text NOT NULL CHECK(choice IN ('original','candidate','retry')), - request_hash text NOT NULL CHECK(request_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,command_id), - FOREIGN KEY(session_id,author_id) - REFERENCES public.muse_revision_session(session_id,author_id) -); - -CREATE TRIGGER muse_revision_session_action_immutable BEFORE UPDATE OR DELETE - ON public.muse_revision_session_action FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); - -REVOKE ALL ON public.muse_revision_session,public.muse_revision_round, - public.muse_revision_session_action FROM PUBLIC,muse_app,muse_eval; -GRANT SELECT,INSERT ON public.muse_revision_session,public.muse_revision_round TO muse_app; -GRANT UPDATE(current_round,state,stop_reason,stop_detail,author_choice, - selected_candidate_id,updated_at) - ON public.muse_revision_session TO muse_app; -GRANT UPDATE(task_id,state,outcome,candidate_id,updated_at) - ON public.muse_revision_round TO muse_app; -GRANT SELECT,INSERT ON public.muse_revision_session_action TO muse_app; diff --git a/数据库/迁移/V0053__返修独立比较证明.sql b/数据库/迁移/V0053__返修独立比较证明.sql deleted file mode 100644 index 5ddda9d..0000000 --- a/数据库/迁移/V0053__返修独立比较证明.sql +++ /dev/null @@ -1,35 +0,0 @@ --- B10只导出无正文的返修比较证明;B06只读,不据此自动采纳候选或修改正文。 -CREATE TABLE public.muse_revision_comparison_receipt ( - receipt_id uuid PRIMARY KEY, - author_id text NOT NULL, - experiment_id uuid NOT NULL REFERENCES evaluation.muse_experiment(experiment_id), - session_id uuid NOT NULL, - round_number integer NOT NULL CHECK(round_number BETWEEN 1 AND 5), - candidate_id uuid NOT NULL REFERENCES public.muse_writing_candidate(candidate_id), - payload jsonb NOT NULL CHECK(jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK(payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - FOREIGN KEY(session_id,author_id) - REFERENCES public.muse_revision_session(session_id,author_id), - FOREIGN KEY(session_id,round_number) - REFERENCES public.muse_revision_round(session_id,round_number), - UNIQUE(author_id,experiment_id,payload_hash) -); - -REVOKE ALL ON public.muse_revision_comparison_receipt FROM PUBLIC,muse_app,muse_eval; -CREATE TRIGGER muse_revision_comparison_receipt_immutable BEFORE UPDATE OR DELETE - ON public.muse_revision_comparison_receipt FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); - --- 生产侧只能看到已导出的最小证明及实验是否停止,看不到oracle中的固定文本对或匿名映射。 -CREATE VIEW public.muse_revision_comparison_status WITH (security_barrier=true) AS -SELECT r.receipt_id,r.author_id,r.experiment_id,r.session_id,r.round_number, - r.candidate_id,r.payload,r.payload_hash, - EXISTS ( - SELECT 1 FROM evaluation.muse_experiment_stop s - WHERE s.experiment_id=r.experiment_id - ) AS stopped -FROM public.muse_revision_comparison_receipt r; - -REVOKE ALL ON public.muse_revision_comparison_status FROM PUBLIC,muse_app,muse_eval; -GRANT SELECT ON public.muse_revision_comparison_status TO muse_app,muse_eval; diff --git a/数据库/迁移/V0054__规则诊断资格与启停.sql b/数据库/迁移/V0054__规则诊断资格与启停.sql deleted file mode 100644 index 528c2bd..0000000 --- a/数据库/迁移/V0054__规则诊断资格与启停.sql +++ /dev/null @@ -1,110 +0,0 @@ --- B10确定性规则诊断的逐例证据与最小公开凭据;B06拥有启停与消费历史。 -CREATE TABLE evaluation.muse_rule_diagnostic_run ( - run_id uuid PRIMARY KEY, - author_id text NOT NULL, - dataset_version_id uuid NOT NULL REFERENCES evaluation.muse_dataset_version(version_id), - target jsonb NOT NULL CHECK (jsonb_typeof(target)='object'), - policy jsonb NOT NULL CHECK (jsonb_typeof(policy)='object'), - policy_hash text NOT NULL CHECK (policy_hash ~ '^[0-9a-f]{64}$'), - plan_hash text NOT NULL CHECK (plan_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,dataset_version_id,policy_hash) -); - -CREATE TABLE evaluation.muse_rule_diagnostic_result ( - run_id uuid NOT NULL REFERENCES evaluation.muse_rule_diagnostic_run(run_id), - sample_id text NOT NULL, - payload jsonb NOT NULL CHECK (jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(run_id,sample_id) -); - -CREATE TABLE evaluation.muse_rule_diagnostic_assessment ( - run_id uuid PRIMARY KEY REFERENCES evaluation.muse_rule_diagnostic_run(run_id), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); - -CREATE TABLE evaluation.muse_rule_diagnostic_stop ( - run_id uuid PRIMARY KEY REFERENCES evaluation.muse_rule_diagnostic_run(run_id), - author_id text NOT NULL, - command_id text NOT NULL, - stopped_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,command_id) -); - -CREATE TRIGGER rule_diagnostic_run_guard BEFORE UPDATE OR DELETE -ON evaluation.muse_rule_diagnostic_run FOR EACH ROW -EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER rule_diagnostic_result_guard BEFORE UPDATE OR DELETE -ON evaluation.muse_rule_diagnostic_result FOR EACH ROW -EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER rule_diagnostic_assessment_guard BEFORE UPDATE OR DELETE -ON evaluation.muse_rule_diagnostic_assessment FOR EACH ROW -EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER rule_diagnostic_stop_guard BEFORE UPDATE OR DELETE -ON evaluation.muse_rule_diagnostic_stop FOR EACH ROW -EXECUTE FUNCTION public.muse_guard_literary_history(); - --- 只有maintenance可导出;production和evaluation只读不含oracle的最小投影。 -CREATE TABLE public.muse_rule_diagnostic_receipt ( - receipt_id uuid PRIMARY KEY, - author_id text NOT NULL, - run_id uuid NOT NULL REFERENCES evaluation.muse_rule_diagnostic_run(run_id), - rule_version_id uuid NOT NULL REFERENCES public.muse_rule_version(version_id), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - valid_until timestamptz NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,run_id,payload_hash) -); -REVOKE ALL ON public.muse_rule_diagnostic_receipt FROM muse_app,muse_eval; -CREATE TRIGGER rule_diagnostic_receipt_guard BEFORE UPDATE OR DELETE -ON public.muse_rule_diagnostic_receipt FOR EACH ROW -EXECUTE FUNCTION public.muse_guard_literary_history(); - -CREATE VIEW public.muse_rule_diagnostic_status WITH (security_barrier=true) AS -SELECT r.receipt_id,r.author_id,r.run_id,r.rule_version_id,r.payload,r.payload_hash, - r.valid_until, - EXISTS ( - SELECT 1 FROM evaluation.muse_rule_diagnostic_stop s WHERE s.run_id=r.run_id - ) AS stopped -FROM public.muse_rule_diagnostic_receipt r; -REVOKE ALL ON public.muse_rule_diagnostic_status FROM muse_app,muse_eval; -GRANT SELECT ON public.muse_rule_diagnostic_status TO muse_app,muse_eval; - --- 当前投影可变,但每次变更都先追加不可变事件。 -CREATE TABLE public.muse_rule_activation_event ( - event_id uuid PRIMARY KEY, - author_id text NOT NULL, - rule_id text NOT NULL, - activation_revision bigint NOT NULL CHECK (activation_revision > 0), - version_id uuid NOT NULL REFERENCES public.muse_rule_version(version_id), - action text NOT NULL CHECK (action IN ('enable','disable')), - credential_id uuid REFERENCES public.muse_rule_diagnostic_receipt(receipt_id), - candidate_id text NOT NULL, - candidate_hash text NOT NULL CHECK (candidate_hash ~ '^[0-9a-f]{64}$'), - review_id uuid NOT NULL REFERENCES public.muse_author_review(review_id), - command_id text NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,rule_id,activation_revision), - UNIQUE(author_id,command_id) -); - -CREATE TABLE public.muse_rule_activation_current ( - author_id text NOT NULL, - rule_id text NOT NULL, - activation_revision bigint NOT NULL CHECK (activation_revision > 0), - version_id uuid NOT NULL REFERENCES public.muse_rule_version(version_id), - state text NOT NULL CHECK (state IN ('active','disabled')), - credential_id uuid REFERENCES public.muse_rule_diagnostic_receipt(receipt_id), - latest_event_id uuid NOT NULL REFERENCES public.muse_rule_activation_event(event_id), - updated_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(author_id,rule_id) -); - -CREATE TRIGGER rule_activation_event_guard BEFORE UPDATE OR DELETE -ON public.muse_rule_activation_event FOR EACH ROW -EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0055__运行观察来源.sql b/数据库/迁移/V0055__运行观察来源.sql deleted file mode 100644 index 17fa541..0000000 --- a/数据库/迁移/V0055__运行观察来源.sql +++ /dev/null @@ -1,39 +0,0 @@ --- B07只追加带真实来源的运行观察;与V0046作者自报指标分开。 -CREATE TABLE public.muse_run_observation ( - observation_id uuid PRIMARY KEY, - author_id text NOT NULL CHECK (btrim(author_id) <> ''), - source_ids uuid[] NOT NULL CONSTRAINT muse_run_observation_source_ids_nonempty - CHECK (cardinality(source_ids) > 0 AND array_position(source_ids,NULL) IS NULL), - source_set_hash text NOT NULL CHECK (source_set_hash ~ '^[0-9a-f]{64}$'), - phenomenon text NOT NULL CHECK (length(btrim(phenomenon)) BETWEEN 1 AND 200), - issue_key text NOT NULL DEFAULT '', - state text NOT NULL DEFAULT 'observation' CHECK (state = 'observation'), - request_hash text NOT NULL CHECK (request_hash ~ '^[0-9a-f]{64}$'), - payload jsonb NOT NULL CONSTRAINT muse_run_observation_sources_present CHECK ( - CASE WHEN jsonb_typeof(payload->'sources') = 'array' THEN - jsonb_array_length(payload->'sources') > 0 AND NOT jsonb_path_exists(payload, - '$.sources[*] ? (!exists(@.runtime.task_id) || !exists(@.runtime.attempt_id) - || !exists(@.locator.content_hash) || @.runtime.task_id.type() != "string" - || @.runtime.attempt_id.type() != "string" || @.locator.content_hash.type() != "string" - || @.runtime.task_id == "" || @.runtime.attempt_id == "" || @.locator.content_hash == "")') - ELSE false END), - content_hash text NOT NULL CHECK (content_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - UNIQUE(author_id,source_set_hash,phenomenon) -); -CREATE INDEX ON public.muse_run_observation(author_id,issue_key,created_at); -CREATE TABLE public.muse_run_observation_command ( - author_id text NOT NULL, - command_id text NOT NULL CHECK (btrim(command_id) <> ''), - observation_id uuid NOT NULL REFERENCES public.muse_run_observation(observation_id), - request_hash text NOT NULL CHECK (request_hash ~ '^[0-9a-f]{64}$'), - PRIMARY KEY(author_id,command_id) -); -CREATE TRIGGER muse_run_observation_immutable BEFORE UPDATE OR DELETE - ON public.muse_run_observation FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_run_observation_command_immutable BEFORE UPDATE OR DELETE - ON public.muse_run_observation_command FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -REVOKE ALL ON public.muse_run_observation,public.muse_run_observation_command FROM muse_eval; -GRANT SELECT,INSERT ON public.muse_run_observation,public.muse_run_observation_command TO muse_app; diff --git a/数据库/迁移/V0056__调用结算与配置验证.sql b/数据库/迁移/V0056__调用结算与配置验证.sql deleted file mode 100644 index ff2e364..0000000 --- a/数据库/迁移/V0056__调用结算与配置验证.sql +++ /dev/null @@ -1,55 +0,0 @@ --- 结算不产生执行事件;账目变化由独立版本及只追加命令回执表达。 -ALTER TABLE public.muse_task ADD COLUMN accounting_revision bigint NOT NULL DEFAULT 0; -ALTER TABLE evaluation.muse_task ADD COLUMN accounting_revision bigint NOT NULL DEFAULT 0; -CREATE TABLE public.muse_call_settlement ( - task_id uuid NOT NULL REFERENCES public.muse_task(task_id), - command_id text NOT NULL CHECK (btrim(command_id) <> ''), - receipt_id uuid NOT NULL UNIQUE, - request_hash text NOT NULL CHECK (request_hash ~ '^[0-9a-f]{64}$'), - receipt jsonb NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(task_id,command_id) -); -CREATE TABLE evaluation.muse_call_settlement (LIKE public.muse_call_settlement INCLUDING ALL); -ALTER TABLE evaluation.muse_call_settlement ADD FOREIGN KEY(task_id) REFERENCES evaluation.muse_task(task_id); -CREATE TRIGGER muse_call_settlement_immutable BEFORE UPDATE OR DELETE ON public.muse_call_settlement - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_call_settlement_immutable BEFORE UPDATE OR DELETE ON evaluation.muse_call_settlement - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -GRANT SELECT,INSERT ON public.muse_call_settlement TO muse_app; -GRANT SELECT,INSERT ON evaluation.muse_call_settlement TO muse_eval; -REVOKE ALL ON public.muse_call_settlement FROM muse_eval; --- 验证专用绑定不能被业务配置读取入口消费,不需要草案先启用。 -CREATE TABLE public.muse_config_probe_binding ( - task_id uuid PRIMARY KEY REFERENCES public.muse_task(task_id), - config_id text NOT NULL, - version text NOT NULL, - content_hash text NOT NULL CHECK (content_hash ~ '^[0-9a-f]{64}$'), - content jsonb NOT NULL, - created_at timestamptz NOT NULL DEFAULT clock_timestamp() -); -CREATE TABLE evaluation.muse_config_probe_binding (LIKE public.muse_config_probe_binding INCLUDING ALL); -ALTER TABLE evaluation.muse_config_probe_binding ADD FOREIGN KEY(task_id) REFERENCES evaluation.muse_task(task_id); -CREATE TRIGGER muse_config_probe_immutable BEFORE UPDATE OR DELETE ON public.muse_config_probe_binding - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_config_probe_immutable BEFORE UPDATE OR DELETE ON evaluation.muse_config_probe_binding - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -GRANT SELECT,INSERT ON public.muse_config_probe_binding TO muse_app; -GRANT SELECT,INSERT ON evaluation.muse_config_probe_binding TO muse_eval; -REVOKE ALL ON public.muse_config_probe_binding FROM muse_eval; -CREATE TABLE public.muse_call_reconciliation ( - task_id uuid NOT NULL REFERENCES public.muse_task(task_id), - command_id text NOT NULL CHECK (btrim(command_id) <> ''), - request_hash text NOT NULL CHECK (request_hash ~ '^[0-9a-f]{64}$'), - receipt jsonb NOT NULL, - PRIMARY KEY(task_id,command_id) -); -CREATE TABLE evaluation.muse_call_reconciliation (LIKE public.muse_call_reconciliation INCLUDING ALL); -ALTER TABLE evaluation.muse_call_reconciliation ADD FOREIGN KEY(task_id) REFERENCES evaluation.muse_task(task_id); -CREATE TRIGGER muse_call_reconciliation_immutable BEFORE UPDATE OR DELETE ON public.muse_call_reconciliation - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -CREATE TRIGGER muse_call_reconciliation_immutable BEFORE UPDATE OR DELETE ON evaluation.muse_call_reconciliation - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); -GRANT SELECT,INSERT ON public.muse_call_reconciliation TO muse_app; -GRANT SELECT,INSERT ON evaluation.muse_call_reconciliation TO muse_eval; -REVOKE ALL ON public.muse_call_reconciliation FROM muse_eval; diff --git a/数据库/迁移/V0057__来源当前授权.sql b/数据库/迁移/V0057__来源当前授权.sql deleted file mode 100644 index 7c39fe7..0000000 --- a/数据库/迁移/V0057__来源当前授权.sql +++ /dev/null @@ -1,3 +0,0 @@ --- 当前消费授权与不可变内容版本独立;旧授权集合保持原值。 -ALTER TABLE muse_source ADD COLUMN authorization_revision bigint NOT NULL DEFAULT 1 - CHECK (authorization_revision >= 1); diff --git a/数据库/迁移/V0058__成品补充验证回执.sql b/数据库/迁移/V0058__成品补充验证回执.sql deleted file mode 100644 index b4f9c85..0000000 --- a/数据库/迁移/V0058__成品补充验证回执.sql +++ /dev/null @@ -1,17 +0,0 @@ --- B08显式完整审计的追加证明;既有成品字节及原始验证记录保持不可变。 -CREATE TABLE public.muse_delivery_artifact_validation ( - artifact_id uuid NOT NULL REFERENCES public.muse_delivery_artifact, - validation_version text NOT NULL CHECK(validation_version = 'delivery-validation-v2'), - author_id text NOT NULL, - verification jsonb NOT NULL, - audited_at timestamptz NOT NULL DEFAULT clock_timestamp(), - PRIMARY KEY(artifact_id,validation_version), - CHECK((verification->>'validation_version' = validation_version) IS TRUE), - CHECK((verification->'verified' = 'true'::jsonb) IS TRUE), - CHECK((jsonb_typeof(verification->'binding') = 'object') IS TRUE) -); -CREATE TRIGGER muse_delivery_artifact_validation_immutable BEFORE UPDATE OR DELETE - ON public.muse_delivery_artifact_validation FOR EACH ROW - EXECUTE FUNCTION public.muse_guard_literary_history(); -REVOKE ALL ON public.muse_delivery_artifact_validation FROM PUBLIC,muse_app,muse_eval; -GRANT SELECT,INSERT ON public.muse_delivery_artifact_validation TO muse_app; diff --git a/数据库/迁移/V0059__检索索引代次.sql b/数据库/迁移/V0059__检索索引代次.sql deleted file mode 100644 index 409b449..0000000 --- a/数据库/迁移/V0059__检索索引代次.sql +++ /dev/null @@ -1,31 +0,0 @@ --- B09:索引现有条目和头的事务变更守卫;不产生第二套索引或业务权威。 -CREATE TABLE public.muse_method_index_guard ( - singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton), - generation bigint NOT NULL DEFAULT 0 CHECK (generation >= 0) -); -INSERT INTO public.muse_method_index_guard (singleton, generation) VALUES (true, 0); - -CREATE FUNCTION public.muse_method_index_changed() RETURNS trigger -LANGUAGE plpgsql SECURITY DEFINER SET search_path = pg_catalog AS $guard$ -BEGIN - UPDATE public.muse_method_index_guard - SET generation = generation + 1 - WHERE singleton; - IF NOT FOUND THEN - RAISE EXCEPTION 'method index mutation guard is missing'; - END IF; - RETURN NULL; -END -$guard$; - --- statement 级别也覆盖批量改写和 TRUNCATE;事务失败时代次一并回滚。 -CREATE TRIGGER muse_method_index_changed -AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON public.muse_method_index -FOR EACH STATEMENT EXECUTE FUNCTION public.muse_method_index_changed(); -CREATE TRIGGER muse_method_index_head_changed -AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON public.muse_method_index_version -FOR EACH STATEMENT EXECUTE FUNCTION public.muse_method_index_changed(); - -REVOKE ALL ON public.muse_method_index_guard FROM PUBLIC, muse_app, muse_eval; -GRANT SELECT ON public.muse_method_index_guard TO muse_app, muse_eval; -REVOKE ALL ON FUNCTION public.muse_method_index_changed() FROM PUBLIC; diff --git a/数据库/迁移/V0060__评测单元复用来源.sql b/数据库/迁移/V0060__评测单元复用来源.sql deleted file mode 100644 index b369d22..0000000 --- a/数据库/迁移/V0060__评测单元复用来源.sql +++ /dev/null @@ -1,14 +0,0 @@ --- B10逐例复用只追加原来源,不复制任务、响应或费用账。 -CREATE TABLE evaluation.muse_evaluation_reuse ( - unit_id uuid PRIMARY KEY REFERENCES evaluation.muse_evaluation_unit(unit_id), - source_unit_id uuid NOT NULL REFERENCES evaluation.muse_evaluation_unit(unit_id), - source_experiment_id uuid NOT NULL REFERENCES evaluation.muse_experiment(experiment_id), - payload jsonb NOT NULL CHECK (jsonb_typeof(payload)='object'), - payload_hash text NOT NULL CHECK (payload_hash ~ '^[0-9a-f]{64}$'), - created_at timestamptz NOT NULL DEFAULT clock_timestamp(), - CHECK (unit_id <> source_unit_id) -); -CREATE INDEX evaluation_reuse_source ON evaluation.muse_evaluation_reuse(source_experiment_id); -CREATE TRIGGER evaluation_reuse_guard -BEFORE UPDATE OR DELETE ON evaluation.muse_evaluation_reuse -FOR EACH ROW EXECUTE FUNCTION public.muse_guard_literary_history(); diff --git a/数据库/迁移/V0061__场景切片索引.sql b/数据库/迁移/V0061__场景切片索引.sql deleted file mode 100644 index 6675edb..0000000 --- a/数据库/迁移/V0061__场景切片索引.sql +++ /dev/null @@ -1,87 +0,0 @@ --- B03:场景切片派生缓存与向量代次索引——参考书原文的确定性切窗。 --- 原文以 muse_source_version 为权威;切片与索引是可全量重建的派生数据,禁原地改写。 -DO $migration$ -BEGIN - -- 切片台账:来源版本的定位窗;窗计划哈希锁定切窗方案,同版本只认一个窗计划。 - CREATE TABLE public.muse_source_slice ( - slice_id uuid PRIMARY KEY, - source_id uuid NOT NULL REFERENCES public.muse_source(source_id), - revision bigint NOT NULL CHECK (revision > 0), - 起点 int NOT NULL CHECK (起点 >= 0), - 终点 int NOT NULL CHECK (终点 > 起点), - 窗计划哈希 text NOT NULL, - 检索文本 text NOT NULL, - 检索文本哈希 text NOT NULL CHECK (检索文本哈希 ~ '^[0-9a-f]{64}$'), - built_at timestamptz NOT NULL DEFAULT clock_timestamp() - ); - -- 同版本同窗计划内起点唯一;不同窗计划可并存,重建时整计划替换。 - CREATE UNIQUE INDEX muse_source_slice_window - ON public.muse_source_slice (source_id, revision, 窗计划哈希, 起点); - CREATE INDEX muse_source_slice_by_source ON public.muse_source_slice (source_id, revision); - - -- 派生数据禁原地改写;删除仅允许全量重建事务成批进行。 - CREATE FUNCTION public.muse_guard_source_slice() RETURNS trigger LANGUAGE plpgsql AS $guard$ - BEGIN - RAISE EXCEPTION '场景切片是派生数据,禁止原地改写;重建请整批删除后重算'; - END; - $guard$; - CREATE TRIGGER muse_source_slice_guard BEFORE UPDATE ON public.muse_source_slice - FOR EACH ROW EXECUTE FUNCTION public.muse_guard_source_slice(); - - -- 切片向量索引:与 muse_method_index 同构(哈希 bigram,内存余弦)。 - CREATE TABLE public.muse_source_slice_index ( - slice_id uuid PRIMARY KEY REFERENCES public.muse_source_slice(slice_id) ON DELETE CASCADE, - 检索文本 text NOT NULL, - 检索文本哈希 text NOT NULL, - vector double precision[] NOT NULL CHECK (array_length(vector, 1) > 0), - embedder text NOT NULL, - built_at timestamptz NOT NULL DEFAULT clock_timestamp() - ); - - -- 代次台账:当前有效索引身份;检索时对不上即拒绝为陈旧。 - CREATE TABLE public.muse_source_slice_index_version ( - ledger_id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY, - 索引身份 text NOT NULL, - embedder text NOT NULL, - slice_count int NOT NULL CHECK (slice_count >= 0), - built_at timestamptz NOT NULL DEFAULT clock_timestamp(), - active boolean NOT NULL DEFAULT false - ); - CREATE UNIQUE INDEX muse_source_slice_index_active - ON public.muse_source_slice_index_version (active) WHERE active; - - -- 代次守卫:切片与索引的事务变更递增代次,检索按代次判新鲜(仿 V0059)。 - CREATE TABLE public.muse_source_slice_guard ( - singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton), - generation bigint NOT NULL DEFAULT 0 CHECK (generation >= 0) - ); - INSERT INTO public.muse_source_slice_guard (singleton, generation) VALUES (true, 0); - - CREATE FUNCTION public.muse_source_slice_changed() RETURNS trigger - LANGUAGE plpgsql SECURITY DEFINER SET search_path = pg_catalog AS $guard$ - BEGIN - UPDATE public.muse_source_slice_guard - SET generation = generation + 1 - WHERE singleton; - IF NOT FOUND THEN - RAISE EXCEPTION 'source slice mutation guard is missing'; - END IF; - RETURN NULL; - END; - $guard$; - - CREATE TRIGGER muse_source_slice_changed - AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON public.muse_source_slice - FOR EACH STATEMENT EXECUTE FUNCTION public.muse_source_slice_changed(); - CREATE TRIGGER muse_source_slice_index_changed - AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON public.muse_source_slice_index - FOR EACH STATEMENT EXECUTE FUNCTION public.muse_source_slice_changed(); - CREATE TRIGGER muse_source_slice_head_changed - AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON public.muse_source_slice_index_version - FOR EACH STATEMENT EXECUTE FUNCTION public.muse_source_slice_changed(); - - REVOKE ALL ON public.muse_source_slice_guard FROM PUBLIC, muse_app, muse_eval; - GRANT SELECT ON public.muse_source_slice_guard TO muse_app, muse_eval; - REVOKE ALL ON FUNCTION public.muse_source_slice_changed() FROM PUBLIC; -END -$migration$;