# 落库与看板设计 v2(八张待落库表 + 只读看板) > 目标读者:创始人。状态:**设计待审(已吸收四路评审),未动代码**。 > 任务:把"一切输入产出必须落库可见"落成具体的表、写路径与只读看板。 > SoT 去向:本文件是**任务设计**,不是长期 SoT。实现后蒸馏进三处——表结构进 `muse/authority/db/ddl/`、表清单与约定进 `muse/authority/db/表映射.md`、"哪些输入产出进哪类表"进领域文档(08 §3/§7、01、05、04、06)——届时本文件删除。设计期间这三处不提前改,避免把还没建的表写成既成事实。 > v2 相对 v1:吸收四路评审(逻辑闭环 / 可实现性 / 合理性 / SoT 父仓一致性)。表从 6 张增至 8 张(新增运行注册 `example_run`、质量结果 `example_quality_result`);改正来源追溯方向与上下文哈希连接;raw 改靠访问控制;质量评判本期记录可见。 ## 1. 背景与口径 - 数据权威已翻成 PostgreSQL(`muse-example` 库)为正式内容权威,Git 退回代码与文档的家并可留痕。见 [08-数据权威与可视化领域](系统架构/新版设计/数据模型/存储与对象关系.md)。 - 落库原则唯一 owner 是 [领域索引 §3](系统架构/新版设计/阅读指南.md);看板合同唯一 owner 是 [可视化模块合同](系统架构/新版设计/工作台设计.md)。本设计不重复二者,只把它们落成具体表与写路径。 - **这套东西的两重定位**:记录留痕的验收面(空白处就是缺口,也是后续抽取优化要补的地方)+ 内容与复利原料的浏览面。 - **诚实的工作量判断**:建表不是主体,真正的成本在写路径改造。其中 raw 进库(§4)、正文 Canonical 写入层(§2.9)不是"改现有写点",是新建组件或重定义安全合同;planner 落库(§2.6)是从零建一条管线。第 2/3/4 步工作量按此估计,不当成顺手事。 **本设计覆盖 08 §3 落库合同表的哪些行、其余在哪挂起**(回应"一切落库是否全闭合"): | 08 §3 输入产出类 | 本设计承接 | |---|---| | 作品/章/正文(正式) | 现有 `muse_content_*`;写入层见 §2.9 | | 实体/关系/叙事状态/世界规则 | 现有 `muse_knowledge_*`(双轨) | | 范式 | 现有 `muse_knowledge_draft`(work_id=0) | | 用户意图、规划、细纲、冻结上下文、范式选择 | `example_planning_section` + `example_context_freeze`(§2.6);**用户意图全文本期不单列,随运行触发记入 `example_run.trigger_source`/`trigger_detail`,挂起更完整的意图档案于 05** | | AI 待审候选正文 | `example_candidate`(§2.4) | | 检测/评分/审核/实验结果 | `example_quality_result`(§2.3)+ 回执摘要 | | 用户的接受/合并/丢弃决策 | `example_user_decision`(§2.5) | | 每次运行的回执 | `example_run` + `example_run_receipt`(§2.2) | | 补证/重写记录 | 回执的修订类别列(§2.2) | | 模型调用提示词与执行配置 | `example_llm_call`(§2.1)+ raw | | Agent/Skill 元数据(角色画像 / 可配置项 / 技能读写合同) | `example_agent_role` + `example_skill`(§2.10 登记表;权威在 Git 侧,登记入库供看板智能体页只读) | | 完整原文/问答/标准答案/供应商响应 | `example_raw_lease` + `example_raw_content`(§2.7) | | 实体/范式观察草稿(05 §2 末步) | **挂起于 05 §6 待建,本期不建** | | 质量结果的结构化 reviews/experiments 量表全量 | 本期记 `example_quality_result`;跨运行聚合视图二期(06 §9) | | DB 备份与重建脚本 | 挂起于 08 §10,本设计不含 | 建表约定(照现有 `91/96` 风格): - 文件名 `muse/authority/db/ddl/<编号>-<中文主题>.sql`,编号从 **97** 起(90–96 已占)。`CREATE TABLE IF NOT EXISTS`;主键 `id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY`。 - **公共列分界**(统一口径,文件头各写理由):运行态设施表(`example_llm_call`)**不带**业务公共列(仿 `95`);业务溯源账本(候选/决策/规划/冻结/raw/质量结果)带归属列 `creator/create_time/tenant_id`;**append-only 表一律不带 `updater/update_time/deleted` 三死列**(禁改删时它们永不写入)。 - **append-only 表**(回执/决策/冻结/raw/质量结果)用 BEFORE UPDATE OR DELETE 触发器禁改写(仿 `96`);可变表(候选/规划)带 `trg_*_updated_at`。 - 唯一键含归属、命名 `uk_example_*`;CHECK `chk_example_*`;索引 `idx_example_*`。 - **哈希归一规则**:runtime/CAS 系用 `sha256:`(71 字符),snapshot 系用裸 64 hex。**入库一律剥 `sha256:` 前缀存裸 64 hex**,列统一 `CHAR(64)`;读取按列语义决定是否复原。所有 `*_sha256` 列同此。 - 一律 `.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py apply muse/authority/db/ddl/<文件>`,整文件单事务回滚。 ## 2. 表设计 外加:文件分组 97 调用 / 98 运行+回执+质量 / 99 候选+决策 / 100 规划+冻结 / 101 raw / 102 智能体·技能登记。**不启用 96 授权快照**:单用户本地,多租户授权机制是从父仓过度继承的(创始人 2026-07-30 拍板,见领域索引 §9);参考书出处信息已在 `example_reference_work`/`muse_knowledge_document`。 ### 2.1 模型调用明细 `example_llm_call`(97) - **用途**:逐次记录每笔模型调用。今天只在 stderr 留一行(易失),库里只有按窗聚合的额度水位 `example_llm_quota`(4 列,非 MiniMax 成本记 0)。 - **形态**:运行态设施表,**不带业务公共列**(仿 `95`,文件头写明:运行态、append-only、无业务归属);append-only。**不扩额度账本**(账本是按窗 `+=` 累加器,语义打架)。 - **列**:`id` PK;`window_key VARCHAR(16)`(→ 额度窗);`run_id VARCHAR(64)`(可空,清洗/拆书批处理无 run,靠 caller 区分);`caller VARCHAR(64)`;`requested_model_id`/`actual_model_id VARCHAR(64)`;`model_match BOOLEAN`;`in_tokens`/`cached_tokens`/`out_tokens INTEGER`;`cost_usd NUMERIC(14,8)`(本地估算,非网关权威,已知);`stop_reason VARCHAR(32)`;`duration_ms INTEGER`;`prompt_sha256 CHAR(64)`(全文落 raw);`raw_content_id BIGINT`(→ raw);`call_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP`(兼作创建时间);`creator VARCHAR(64)`(记写入方;设施表只留这两列)。 - **索引**:`idx(window_key)`、`idx(caller, call_time)`、`idx(run_id)`。 - **写路径(按可实现性修正)**:`duration/tokens/stop_reason/raw 响应体`都在 `chat()` 内部即弃,`chat_governed` 那层拿不到——所以写点是 **`chat()` 内置 hook**(不是贴在 `chat_governed` 的 `_bump_window` 后),由 `chat()` 在拿到响应处直接记;`caller`/`run_id` 由调用方传入(下游 6 处:parse_llm/parse_outline/parse_ingest/migrate_upgrade_windows/review_cards/clean_detect,加可选参数不破坏兼容)。`chat()` 只回 `(content, usage)`,raw 响应体要往上带(扩返回或回调)。 - **owner**:06-模型边界。 ### 2.2 运行注册 + 运行回执 + 质量结果(98,三表同文件,运行级账本) **`example_run`**(运行注册,可变表——回应"run_id 无主"):一次运行一行,所有子表挂它。 - 列:`run_id VARCHAR(64) PRIMARY KEY`(自然键);`work_id BIGINT`(→ 作品,回答"哪个作品",08 §3 硬要求);`target_chapter INTEGER`;`trigger_source VARCHAR(32)`(user/replay_eval/diagnostic,触发来源;**不用 trigger,那是 SQL 保留字**);`trigger_detail JSONB`(用户意图摘要等);`started_at`/`finished_at TIMESTAMP`;`terminal_state VARCHAR(20)`(running/completed/failed);公共列六件套(可变表,带软删)。 - 写路径:运行开始时写一行(生产由主会话发起、回放由 replay-eval 发起),结束时更新终态。 **`example_run_receipt`**(运行身份账本,append-only):字段平移自 `ExecutionReceipt.as_dict()` ⊕ CAS 身份 ⊕ 哈希链。 - 列:`id` PK;`run_id VARCHAR(64) NOT NULL`(→ `example_run`);`sample_id VARCHAR(64) NOT NULL`(**生产侧也造一个运行内标识,不得空**——CAS revision 按样本单调,sample_id 必须进唯一键);`revision INTEGER NOT NULL`(CAS 样本内单调号);`arm VARCHAR(32)`;`attempt INTEGER DEFAULT 1`;`adapter_role VARCHAR(32)`(writer/planner/detector/judge…);`stage_kind VARCHAR(20)`(**generation/detection/supplement/rewrite/accept**——补证/重写独立成类,配 `loop_seq INTEGER` 循环序号,回应"补证数不出次数";与 attempt=失败重试 分工);`candidate_version VARCHAR(32)`;`candidate_sha256 CHAR(64)`;`context_sha256 CHAR(64)`(**→ `example_context_freeze.context_sha256`,不是 manifest_sha256**);`previous_state_sha256 CHAR(64)`(哈希链);`requested_model_id`/`actual_model_id`;`model_match`;`effort`;`total_cost_usd NUMERIC(14,8)`;`usage JSONB`;`stop_reason`/`terminal_reason`;`is_error BOOLEAN`;`safe_summary JSONB`(结论 + 失败类别的安全摘要;完整 prompt/response 落 raw);`result_sha256 CHAR(64)`;`raw_content_id BIGINT`;归属列 `creator/create_time/tenant_id`(唯一键含 tenant_id)。 - **唯一键 `uk(run_id, sample_id, revision)`**(CAS 身份;revision 按样本单调,单 run_id 下不同样本各有 revision=1,故 sample_id 必入键)。 - **连接说明**:`candidate_version`/`candidate_sha256` 是数据列兼到候选表的连接键(05 §3 绑定键 `run_id+attempt+candidate_version+candidate_sha256`),**不是回执自身身份**。回执↔候选是**四列 1:N**(一个候选对应生成/检测/审核多条回执);筛"产生该候选的生成回执"用 `adapter_role='writer' AND stage_kind='generation'`。 - 写路径:评测 `ledger.complete()`(replay-eval/execute.py)、质量门 `issue_gate_report_and_receipt()`(quality-gate/writer_gate.py)、生产 `continuation/run_writer.py::run_writer_with_receipt`。 - **owner**:08 §7(字段合同)、05 §3(绑定键)。回执**不含**"用户决策"字段(偏离 08 §7 字面:回执是 append-only 身份账本,决策独立成表见 §2.5;蒸馏时回改 08)。 **`example_quality_result`**(质量评判账本,append-only——回应"有质量评判就记录、就可见"): - 列:`id` PK;`run_id VARCHAR(64)`(→ run);`receipt_id BIGINT`(→ 回执);`candidate_sha256 CHAR(64)`(绑候选,06 §5);`judge_kind VARCHAR(20)`(detection/scoring/review/experiment);`dimension VARCHAR(32)`(评分维度,评分类用);`scale_version VARCHAR(32)`(量表/质量政策版本,06 §3);`score NUMERIC`;`conclusion VARCHAR(20)`(pass/fail/revise…);`failure_class VARCHAR(32)`;`detail JSONB`(审核的问题/修复/复验;实验的基线/假设/干预/预期/结论);`raw_content_id BIGINT`;归属列 + `create_time`。 - **索引**:`idx(candidate_sha256)`、`idx(run_id)`、`idx(judge_kind)`。幂等唯一键用表达式索引 `uk(tenant_id, run_id, judge_kind, COALESCE(dimension,''), COALESCE(candidate_sha256,''))`(dimension/candidate_sha256 可空,朴素 UNIQUE 在 PG 里 NULL 互不相等会破坏幂等,故 COALESCE;重跑检测不重复记)。 - 写路径:detect / quality-gate / eval 在各自签发处落一条。**本期:每次评判都记录、看板运行详情逐条可见;跨运行评分趋势/复利聚合视图二期**(06 §9,那是视图聚合不是记录)。 - **owner**:06-质量与复利。 ### 2.3 (编号承接上文):98 文件含运行/回执/质量三表,见 2.2。 ### 2.4 待审候选 `example_candidate`(99) - **用途**:登记 AI 待审候选(Shadow)。今天候选是内存对象 `InMemoryCasStateStore`;关联字段全在 `CandidateEnvelope v2`。 - **形态**:可变表(状态流转),带归属列 + updated_at 触发器。 - **列**:`id` PK;`work_id BIGINT NOT NULL`(→ 作品);`target_chapter INTEGER NOT NULL`;`run_id VARCHAR(64)`(→ run;**merge 候选的 run_id = 复检重跑那次运行**,因为用户改后合并的版本没有生成 run,其"产出"是用户编辑 + 一次重跑检测,见 §2.9 来源说明);`attempt INTEGER`;`run_type VARCHAR(20) NOT NULL`(**production/eval/diagnostic——评测候选不得成正文,05 §8.4 四层机械隔离的第一层;`acceptance_eligible` 是由 run_type 派生的缓存位,以 run_type 为准**);`candidate_version VARCHAR(32) NOT NULL`;`candidate_sha256 CHAR(64) NOT NULL`;`candidate_body TEXT`(候选正文,看板待审视图直接读;候选表整体按 raw 级访问控制——见 §4,**不重复塞 raw 表**);`context_sha256 CHAR(64)`(→ freeze.context_sha256);`quality_policy_version VARCHAR(32)`;`mode VARCHAR(20)`(continuation/rewrite/expansion/polish);`source_role VARCHAR(20)`;`state VARCHAR(20) NOT NULL DEFAULT 'draft'`;`acceptance_eligible BOOLEAN`;归属列 + `update_time`/`deleted`。 - **状态机**(对齐 [05 §3](系统架构/新版设计/编排与能力资源.md),列名/值与 05 统一): ```text draft -> checking -> passed (机械门 + 语义检测 + 质量审核通过) -> rejected (不通过,修订后以新候选版本重跑,不就地改) draft/checking/passed -> discarded (用户在任一态都可丢弃,对齐 05) passed -> accepted (用户原样接受,confirm 写) accepted -> archived (归档,对齐 05 单条 ACCEPTED→ARCHIVED) ``` - 7 态全进库是 SoT 逼出来的(05 §3、§8 条目 6 要看板渲染候选当前命运),非冲突。列名 `state`、值小写(库惯例),与 05 §3 大写状态名语义对应(ACCEPTED↔accepted、DISCARDED↔discarded 等)。 - **唯一键** `uk(tenant_id, work_id, target_chapter, candidate_version)`;**索引** `idx(tenant_id, work_id, state)`、`idx(tenant_id, run_type)`(评测隔离查询)。 - 写路径:`continuation/run_writer_pipeline.py` PASSED 终态登记(替换内存 store);confirm 的 PG 版状态迁移。 - **owner**:01-作品领域(存储)、05 §3(状态机)。 ### 2.5 用户决策记录 `example_user_decision`(99,与候选同文件) - **用途**:记录用户每次接受/合并/丢弃 + **理据**(补现在缺的"为什么"——今天唯一留痕是 git commit message,翻库后不算数)。 - **命名锚定(拆父仓雷)**:本表是父仓 **Candidate Decision Archive**(后端-04 §7/§11,用户处理候选**之后**的审计归档)的单用户落地,**不是** ADR-018 删除的 Candidate Decision Envelope(接受**前**预封装的裁决闸门);不缓存来源/质量/合规裁决,接受时实时校验(05 §5 六道保护步)。 - **形态**:append-only(一条决策一行,改主意=插新行覆盖候选 state)。 - **列**:`id` PK;`candidate_id BIGINT`(→ 候选);`work_id BIGINT`/`target_chapter INTEGER`(决策当时的快照,append-only 故不会失步);`decision VARCHAR(20) NOT NULL`(accept/merge/discard);`rationale TEXT`(理据);`basis_ref VARCHAR(256)`(依据,如 大纲@日期/细纲版本);`decided_by VARCHAR(64)`(单用户=创始人);`expected_revision INTEGER`(接受时比对的**正文** revision,冲突报 REVISION_CONFLICT);`command_id VARCHAR(120)`(幂等键,**直连 `muse_content_command_log.command_id`**——它无 sha256 列,故不叫 command_sha256);`canonical_block_id BIGINT`(接受/合并后落成的正式正文 → `muse_content_block.id`;**冗余正向指针,不是来源权威——来源权威在正文块自带的归因,见 §2.9**);归属列 + `create_time`。 - **范围**:只记正文/规划候选的 accept/merge/discard。知识卡确认是另一个动词(confirm),走 `muse_knowledge_draft.status` 双轨 + `muse_knowledge_entity`,不进本表(避免多态关联;父仓后端-04 §11 亦分表分状态)。 - 写路径:confirm 新增写库层(该目录现零 DB 代码);决策写入后翻候选 state。 - **owner**:05-创作流程(接受语义)、01(存储)。 ### 2.6 规划与上下文冻结(100,两表同文件) 今天三类产物库里零存量零表:规划/细纲在文件与 gitignore 临时目录(planning 连脚本都没有,planner 智能体直接写文件),冻结 manifest 是仓外临时 JSON 算完即弃;主仓 `muse_content_planning_section` 暂缓未建。两表新建。 **`example_planning_section`**(可变表,带归属列 + updated_at): - 列:`id` PK;`work_id BIGINT NOT NULL`;`target_chapter INTEGER`(章级 section=细纲 填章号;书级=设定/大纲/状态/装配 为空);`section_type VARCHAR(32)`(setting/outline/state/assembly/fine_outline);`schema_type VARCHAR(32)`(对应 meta/schemas 型);`version INTEGER`;`payload JSONB NOT NULL`(结构化内容);`state VARCHAR(20) DEFAULT 'shadow'`(shadow/confirmed);`confirmed_at TIMESTAMP`;归属列 + `update_time`/`deleted`。 - **唯一键用两个部分唯一索引**(仿 V26 partial unique,因 target_chapter 可空):书级 `uk(tenant_id, work_id, section_type, version) WHERE target_chapter IS NULL`;章级 `uk(tenant_id, work_id, section_type, target_chapter, version) WHERE target_chapter IS NOT NULL`。 - **已确认细纲取用**(补今天的无持久化缺口):`SELECT payload FROM example_planning_section WHERE work_id=? AND section_type='fine_outline' AND target_chapter=? AND state='confirmed' ORDER BY version DESC LIMIT 1`。read-context 取数需改道读库(不再当内存参数)。 **`example_context_freeze`**(append-only,冻结一旦生成不可改): - 列:`id` PK;`work_id BIGINT`;`target_chapter INTEGER`;`as_of_chapter INTEGER NOT NULL`(冻结上界,严格 `<= asOf`);`manifest_sha256 CHAR(64) NOT NULL UNIQUE`(manifest 自身哈希);`context_sha256 CHAR(64)`(**WriterContext 回执哈希 = `retrieval_identity(context)`,回执表连的是这一列**;非唯一,接受一对多或加索引);`reference_work_id BIGINT`;`reference_version VARCHAR(64)`;`arm_config JSONB`;`sections JSONB`(每节 sourceId/sourceVersion/sha256/charCount);`token_budget INTEGER`;`omitted_fields`/`omitted_sources JSONB`;归属列 + `create_time`。 - **写路径(点名具体落点,不用含糊的"编排层")**:snapshot 纯函数(build/check/audit)**不动**,asOf/哈希校验原样当入库前失败关闭闸。落库挂在 **read-context 的 `assemble_writer_context.py::assemble_context()` 之后**——这是生产路径真实存在且被调用的函数(主会话调 read-context 组装上下文),算出 `context_sha256` 后即弃处改为经 db skill 落一行。回放路径由 replay-eval 在其编排里同样落。**不新建独立"生产编排器"**:本仓生产编排=主会话按 AGENTS §7 顺序调 skill,落库挂各 skill 现有调用点即可。 - **owner**:04-上下文领域、01(规划存储)。 ### 2.7 raw 元数据与全文(101,两表同文件) **raw 合同已改写**(创始人批准,详 §4):放弃时效语义,改靠**访问控制 + append-only**;密钥/token 绝不入表。 **`example_raw_lease`**(元数据,append-only,字段自 `_lease_record` 平移): - 列:`id` PK;`vault_id CHAR(32)`;`run_id VARCHAR(64)`;`source_version VARCHAR(128)`;`content_hashes JSONB`;`purpose VARCHAR(64)`;`status VARCHAR(20)`(open/migrated/closed,**保留作历史状态,不再是删期限闸门**);`retain_until TIMESTAMP`(**批准的留存期限,留作溯源;进库后不触发自动删除,将来若加清理策略以此为据**——诚实留档,非僵尸);`archive_id`/`archive_sha256`(仓外备份若仍做);`file_count`/`total_bytes`;`run_authorization_id VARCHAR(128)`(本次运行授权标识,来自执行授权——运行时对象,不查库、不指 96);`source_work_id BIGINT`(raw 来源参考书 → `example_reference_work.id`,出处溯源);归属列 + `create_time`。 **`example_raw_content`**(全文,append-only,受访问控制): - 列:`id` PK;`lease_id BIGINT`(→ lease);`kind VARCHAR(32)`(prompt/response/source_text/oracle/supplier——**删 `candidate`:候选正文单存候选表,不进 raw**);`run_id VARCHAR(64)`;`role VARCHAR(32)`;`content_sha256 CHAR(64) NOT NULL`;`content TEXT NOT NULL`;归属列 + `create_time`。 - **唯一键 `uk(lease_id, content_sha256)`**(同一次进库内重试幂等去重;**跨进库各留一行,授权归属不串**——不用全局 UNIQUE(content_sha256),否则同一本书两份授权共享一行、溯源指错)。 - **访问控制**:默认不进普通检索,看全文须显式指定;看板可看全文;密钥/token/凭据列级 + 写入前过滤双禁。 - 写路径:raw_vault 写点 + 各调用方 `_raw_json` 改走 db skill 参数化通道(§3)。 - **owner**:08 §5。 ### 2.8 增删改查形态(回答"能不能简洁 CRUD") | 类别 | 表 | 增 | 查 | 改 | 删 | |---|---|---|---|---|---| | 账本(不可变) | llm_call / run_receipt / quality_result / user_decision / context_freeze / raw_lease / raw_content | INSERT | SELECT | ✗ 触发器禁;"改"=插新行 | ✗ 触发器禁 | | 可变 | run / candidate / planning_section / agent_role / skill | INSERT | SELECT | UPDATE(终态/状态/配置) | 软删 `deleted=TRUE` | - **archived vs deleted 分界**:归档走候选 `state='archived'`(业务命运,看板历史照常可见);清垃圾行/测试行走 `deleted=TRUE`(行级行政隐藏,默认不显示)。 - 真实场景查询都是一两条带索引的等值/范围查询: - **看板看待审候选并接受**:`SELECT … FROM example_candidate WHERE work_id=? AND state IN ('draft','checking','passed') AND run_type='production'`(正文就在 `candidate_body`);接受=插一条决策 + `UPDATE candidate SET state='accepted'`。 - **一次运行全链路排查**(给 run_id):`example_run` 拿作品/触发/终态;回执/候选/质量结果/raw/模型调用各 `WHERE run_id=?`;冻结用回执 `context_sha256` 连 `freeze.context_sha256`。 - **这段正式正文从哪来**:见 §2.9——权威从**正文块自带归因**反查,不经决策表正向指针。 - **按章取已确认细纲**:见 §2.6 SQL。 - **某候选被判了什么**:`SELECT … FROM example_quality_result WHERE candidate_sha256=?`。 ### 2.9 正文来源归因(写正文入库的前置合同) 这是看板"沿来源下钻"立身之本,也是评审最集中的洞,单列前置合同: - **方向**:来源权威落在**正文块自身**,不是决策表的正向指针。依据父仓 架构-02 §3(原路径 ../../design-docs/架构-02-核心数据结构与双轨模型.md,已随旧实现退出,见固定基线):"正文来源归因是当前正文 revision 的一部分,不能只依赖历史候选 Archive"。父仓正文块来源归因表(`muse_content_block_source_attribution`,主仓 V1 已有、暂空置)存 `decision_id` **反向引用**决策归档。 - **用主仓现成表,不另起炉灶**:`muse_content_block_source_attribution`(`block_id + revision + source_type + source_object_id + source_version + lineage_payload JSONB + authorization_snapshot_id`,唯一键 `(tenant_id, block_id, revision)`)天生**按版本归因**——一章可 accept→merge→merge 出多个 revision,每个 revision 一行归因,`lineage_payload` 装候选身份(candidate_id/run_id/candidate_sha256)。这解决了"revision=2 是哪次决策造成的"。 - **`user_decision.canonical_block_id` 降级**为冗余正向指针(看板从决策跳正文用),**不当唯一溯源路径**。 - **写正文 Canonical 写入层**:本设计的前置依赖,不是顺手事,**提为独立子任务并估工**。写入序列(单事务,定死 crash-in-between 形态): ```text 校验(accept preflight,05 §5 六道保护步,含 revision CAS) -> 写 muse_content_block(content_text,revision + 1) [拿到 block_id] -> 写 muse_content_block_source_attribution(block_id, revision, lineage_payload=候选身份) -> 写 example_user_decision(canonical_block_id=block_id, command_id 幂等) -> UPDATE example_candidate SET state='accepted' (同事务提交;任一失败整体回滚,不留"无来源指针的正式正文") ``` - **merge 候选来源**:用户改后合并的版本无生成 run,其 run_id=复检重跑运行,归因 `lineage_payload` 标 `source_type='user_merge'` + 原候选 + 重跑检测回执。 - **本期缩小声明**:单用户暂不做多租户导出/来源撤权重验,但归因落块的方向按架构-02 §3 执行,不埋"只靠归档"的债。来源撤权时候选作废,本期不做撤权重验(不启用 96),接受时实时校验兜底(05 可补 invalidated 语义)。 ### 2.10 智能体与技能登记 `example_agent_role` + `example_skill`(102) 看板"智能体"空间的画像 / 可配置项 / 技能合同的数据源(**A 方案,2026-07-30 拍板**)。这些元数据的权威在 Git 侧(`.agent/agents/*.md`、`.agent/skills/*/SKILL.md`),但看板只读库——故登记入库,把智能体配置也纳入留痕。登记表是 Git 侧权威在库内的**影子**(类比 `muse_meta_function_chain` 是 meta/chains 的库内影子):**Git 仍是配置权威,登记表只供看板只读**。 **`example_agent_role`**(角色登记,可变表,带公共列 + updated_at): - 列:`id` PK;`role VARCHAR(32) NOT NULL`(writer/planner/extractor/detector/judge);`display_name VARCHAR(64)`;`model VARCHAR(64)`(模型归属,opus/其它);`effort VARCHAR(16)`;`budget_usd NUMERIC(14,8)`;`tools JSONB`(可用工具);`responsibility TEXT`(职责白话描述);`source_ref VARCHAR(256)`(Git 侧 .md 路径,出处可溯);`synced_at TIMESTAMP`(最近一次从 Git 同步时间);公共列六件套。 - 唯一键 `uk(tenant_id, role)`。 **`example_skill`**(技能登记,可变表,带公共列 + updated_at): - 列:`id` PK;`skill_name VARCHAR(64) NOT NULL`;`purpose TEXT`(一句话用途);`consumer VARCHAR(64)`(给谁用:主会话/某角色/其它 skill);`reads JSONB`(读哪些表);`writes JSONB`(写哪些表);`red_lines TEXT`(红线);`model_used VARCHAR(64)`(用模型则记,确定性工具为空);`source_ref VARCHAR(256)`(SKILL.md 路径);`synced_at TIMESTAMP`;公共列六件套。 - 唯一键 `uk(tenant_id, skill_name)`。 **登记机制**:新增确定性登记脚本(建议 `db/scripts/sync_agent_registry.py`,或挂到现有种子机制),从 Git 侧 md 抽取 frontmatter 与"数据库读写合同"段,**upsert 两表**(幂等可重跑,仿 `seed_schemas`);配置变更后重跑即同步。看板只读这两表、不读 Git(守住看板只读库的合同)。 ## 3. 写路径改造(落库挂各 skill 现有调用点;不新建独立生产编排器) 本仓生产编排=主会话按 AGENTS §7 顺序调 skill。落库挂在每个 skill 真实存在的调用点上,唯一新建组件是 §2.9 的正文写入层。 | skill | 改什么 | 落库点 | |---|---|---| | **db**(前置) | `db.py exec` 现收裸 SQL 字符串、无参数化;百 KB raw 全文过 CLI 参数不可行(shell 转义 + ARG_MAX)。**扩展 db.py 提供参数化/stdin 执行通道**(登记为新工作) | — | | **正文写入层**(新建,§2.9) | 写 block + source_attribution + decision + 翻 state 的单事务序列 | confirm 触发 | | **confirm**(动最重) | SKILL.md description(还是 git 那句)+ 采纳/丢弃/推送三段换写库语义;scripts/ 新增 PG 版候选状态存储 + 决策写入 + 调正文写入层。**注意 confirm 是 DB/git 混合体**:知识卡确认与"既有创作文件采纳"仍走 git,正文候选走 DB——SKILL.md 写清双通道分界,不是整体切换 | decision + candidate.state | | **continuation** | `run_writer_pipeline` PASSED 终态登记候选(替换内存 store / result_path 文件);`candidateArtifact` 进 raw | candidate + raw | | **llm** | `chat()` 内置 hook 落明细;响应体往上带;caller/run_id 由 6 个下游传入 | llm_call | | **detect / quality-gate / eval** | 签发处落质量评判 + 回执 | quality_result + receipt | | **read-context** | `assemble_context()` 算出 context_sha256 后落冻结;取已确认细纲改道读库 | context_freeze | | **planning / fine-outline**(从零建管线,单拆一步) | ① planner 智能体契约改写(opus 自由 Markdown→按 schema_type 产严格 JSON);② planning validator(从无到有,对等 writer_contract);③ Markdown/frontmatter→payload JSONB 规则;④ 主会话落库代码;⑤ read-context 细纲读取改道。先交付①②再落库;版本语义(version 谁递增、shadow→confirmed 是否走 confirm)拍定 | planning_section | | **runtime(raw_vault)** | raw 进库改写见 §4,是重定义安全终态,不是改一个写点 | raw_lease + raw_content | **写入通道口径(修正自相矛盾)**:所有写入经 **db skill 的 DSN 与约定**,在各 skill 的 `scripts/` 内以**参数化短连接**执行(仿 `_bump_window` 的即开即关,Tailscale 不持长事务);大对象(raw 全文)走 db.py 参数化/stdin 通道。不是"每笔起一次 db CLI 子进程",也不是裸连各写各的。 ## 4. raw 合同改写(创始人批准,单列拍死三件事) 旧合同(raw 留仓外 `/tmp` 租约保险库、24h 过期即删、评测后 migrate 归档、回执不带路径)作废。新合同:**raw 进库、靠访问控制 + append-only、可看全文**。实现前先把三件事拍死(否则第 4 步是重做半个 replay-eval): 1. **过期条款的 DB 形态**:**放弃时效语义**(单用户本地),改靠**访问控制 + append-only**;`retain_until` 只留档溯源,不触发自动删除。raw_vault 的 `RAW_LEASE_EXPIRED`/`min_remaining`/调前复检(`_assert_raw_call_window`)这三条可执行安全条款,在库模型下由"访问控制 + 禁删触发器"替代,不再做时效裁决。 2. **run 成功终态的新定义**:今天 `COMPLETED` 的必要条件是 `raw_disposition_ok`(migrate 成功),CAS 终态记 `cleanup_state=migrated/failed`。raw 常驻库后 migrate 降为**可选仓外备份**,`COMPLETED` 改以"raw 已落库(lease+content 写入成功)"为终态判据;`cleanup_state` 枚举与 manifest 的 `rawDisposition` 相应重定义。连带 `test_raw_vault.py / test_run_writer_replay.py / test_audit_leakage.py` 重写。 3. **授权门简化(不启用 96)**:单用户本地,授权人/使用者/机器是同一人,原"用途授权有效(关联 96 快照)"门改为轻量出处门——raw 须来自已导入参考书(`source_work_id` → `example_reference_work`,出处可溯)且仅本地用途即可;不做版权状态/用途数组/到期重验那套多租户合规仪式。`run_authorization_id` 仅记运行授权出处(运行时对象,不查库)。密钥/token 禁入表的门保留。 **对账父仓**:raw 全量留存是对 专题-05 §9.2(原路径 ../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md,已随旧实现退出,见固定基线)"provider 原始响应默认不长期保存"的**刻意覆盖**——单用户锻炉需全量 raw 可见以供走查;密钥/凭据禁入表仍从父仓(§9.1)。此覆盖写明于 08 §5。 **改写落点**(实现第 4 步动):08 §5、runtime `SKILL.md`、[可视化模块合同 §5](系统架构/新版设计/工作台设计.md)、`muse/authority/db/表映射.md`。§4 旧 raw 清单删"未接受候选正文"、`raw_content.kind` 删 `candidate`(候选正文单存候选表,整表 raw 级访问控制——对齐 08 §3 落库合同表)。 ## 5. 看板模块设计 合同在 [可视化模块合同](系统架构/新版设计/工作台设计.md),这里只补实现排序: - **只读硬约束**(机械门):独立只读连接(`SET TRANSACTION READ ONLY`);全代码 grep 无 `INSERT/UPDATE/DELETE`/DDL;不接写通道;挂了不牵连创作链。 - **技术形态**:纯标准库 HTTP 服务端渲染(仿 open-wenmo hub),无 SPA 框架;查库复用 `.venv` psycopg **只读连接**。 - **关键解耦**:合同 §4.1 各视图(作品/知识卡/参考书拆书/清洗/额度/结构本体/写命令审计;授权快照不启用)**全读现有表,可立即并行起步**;§4.2 视图随落库逐格点亮,未建显示"无数据/待落库"。 - **质量评判本期可见**:运行详情页逐条展示该 run 的 `example_quality_result`(检测/评分/审核/实验 + 量表版本 + 失败类别);**跨运行评分趋势/复利聚合视图二期**(依赖已有数据,是视图层)。 - **防误导**(合同 §7):型别看 `draft_payload` 中文/英文两套键不看 `draft_type`;公共/作品看 `work_id`;entity/binding 0 行如实显示"已确认为 0";数字实时查库不缓存。 - **门禁**:本机/局域网/Tailscale 免验证;公网走 TOTP;单用户信任。 ## 6. 实施顺序与验收 ```text 第 0 步(门) raw 旧合同作废落 08 §5;拍死 §4 三件事;定 §2.9 正文写入层归属(不启用 96,无需 apply) 第 1 步(打底,风险最小,可并行看板§4.1) db.py 参数化通道扩展;97 llm_call;98 run+receipt+quality(含 run_type/修订类别/唯一键修正); 102 智能体·技能登记表 + 登记脚本(读 Git→upsert,看板智能体页据此可建) 第 2 步(心脏) 99 候选+决策 + 正文 Canonical 写入层(§2.9 单事务序列)+ confirm 写库改造 第 3 步 planning 管线(planner 合同+validator 先行)+ 100 规划与冻结 + read-context 改道 第 4 步 101 raw(按 §4 新合同)+ runtime 安全终态重定义 + 测试重写,卡用途授权门 看板 与上并行:先发 §4.1;§4.2 随落库点亮;质量评判随 98 上线即在运行详情可见;复利聚合视图二期 ``` 每步验收(对照各领域 SoT): 1. DDL 先落 `muse/authority/db/ddl/` 再 apply;`muse/authority/db/表映射.md` 同步登记。 2. 写路径走 db skill 参数化短连接;离线自测覆盖关键路径与失败路径,失败明确失败关闭。 3. 看板对应视图渲染实时数据;未建表显示"无数据/待落库"。 4. 全链路无密钥/token 进表;raw 受访问控制。 5. 来源链可机械验证:`source_attribution` 按 `(block_id, revision)` 反查到候选;评测候选 `run_type='eval'` 不得 `state='accepted'`(05 §8.4)。 6. 框架改动与创作内容分开审查、分开提交;git 提交先取授权。 ## 7. 关联 SoT 与蒸馏去向 - 落库原则 owner:[领域索引 §3](系统架构/新版设计/阅读指南.md) - 存储/可恢复/raw/回执字段合同:[08](系统架构/新版设计/数据模型/存储与对象关系.md) §3/§5/§7 - 候选状态机/绑定键/接受语义/评测隔离:[05](系统架构/新版设计/编排与能力资源.md) §3/§5/§8.4 - 候选/规划存储结构:[01](系统架构/新版设计/模块设计/B01-作品规划.md) - 上下文冻结与取数:[04](系统架构/新版设计/模块设计/B09-上下文.md) - 质量评判记录与量表版本:[06](系统架构/新版设计/模块设计/B06-审校修订.md) §3/§5/§9 - 正文来源归因方向:父仓 架构-02 §3(原路径 ../../design-docs/架构-02-核心数据结构与双轨模型.md,已随旧实现退出,见固定基线);归因表 `muse_content_block_source_attribution`(主仓 V1) - 决策归档命名锚定:父仓 后端-04 §7/§11(Candidate Decision Archive);ADR-018(删的是 Decision Envelope) - raw 留存对账:父仓 专题-05 §9.2(原路径 ../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md,已随旧实现退出,见固定基线) - 只读看板合同:[可视化模块合同](系统架构/新版设计/工作台设计.md) - 表清单与现状:[`muse/authority/db/表映射.md`](系统架构/新版设计/数据模型/存储与对象关系.md) - 蒸馏去向:实现后表结构→`muse/authority/db/ddl/97–102`;清单约定→`muse/authority/db/表映射.md`;"哪些输入产出进哪类表"具体表名→08 §3。本文件届时删除。