muse-agent-example/docs/2026-07-30-落库与看板设计.md
zizi b0bc7a8745 框架: 技能按动作-对象重组 + 先审后入创作闭环
一、技能重组(动作-对象命名)
- 旧目录 clean/confirm/continuation/db/detect/embed/… 重组为
  clean-book-text/decide-candidate/write-next-chapter/access-database/
  check-content-consistency/embed-knowledge/…(git 识别为 rename,内容保持)
- agents/*.md、AGENTS.md/CLAUDE.md 收编、example_skill 登记表同步新名

二、先审后入创作闭环(本次核心)
正文接受从"机械门一过就写正典"改为"机械门+语义审查双通过+用户批准+单事务原子提交",
DB 级兜底,编排层跳步即被硬拒。
- candidate_cas.py + example_candidate_cas(109):持久化 CAS 状态链
- fact_delta.py + example_fact_delta/example_fact_ledger(106):结构化事实增量,
  模型只提六型闭集增量+正文证据引文,仅用户批准的增量随正文同事务入账本
- projection_registry.py + example_projection_run(107):投影登记与恢复
- acceptance_state.py:接受前置实时状态重读
- lesson_registry.py + example_lesson(108):经验升格链,禁止自动升格
- DDL 105:example_candidate 增 semantic_status/semantic_report_sha256
- write_canonical.accept:语义兜底+同事务合并增量+登记投影;
  run_writer_pipeline/persist_writer_run/run_writer_semantic_detector/step2 接入全链
- claude_runtime:兼容新 CLI modelUsage 信息字段

三、审查修复(独立子代理四维审查后)
- 事实增量 propose→approve 翻态正道,不撞唯一键
- 冻结配置探针重刷(CLI 2.1.211→2.1.231 漂移),profileSha256/adapterVersion 再登记
- 可视化合同悬空路径/五六空间矛盾、 SoT 旧技能名漂移、行尾空白清理

测试:离线 65 套 + 真实库集成 5 套(CAS/接受故障注入/事实增量/投影/经验升格)+ 回放 79 项全绿。
创作内容(docs/design、生成正文 artifacts)按"框架与创作分开"未入本提交。
2026-08-14 10:24:08 +08:00

265 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 落库与看板设计 v2(八张待落库表 + 只读看板)
> 目标读者:创始人。状态:**设计待审(已吸收四路评审),未动代码**。
> 任务:把"一切输入产出必须落库可见"落成具体的表、写路径与只读看板。
> SoT 去向:本文件是**任务设计**,不是长期 SoT。实现后蒸馏进三处——表结构进 `db/ddl/`、表清单与约定进 `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-数据权威与可视化领域](../.agent/docs/architecture/domains/08-数据权威与可视化领域.md)。
- 落库原则唯一 owner 是 [领域索引 §3](../.agent/docs/architecture/domains/_index.md);看板合同唯一 owner 是 [可视化模块合同](../.agent/docs/architecture/可视化模块合同.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` 风格):
- 文件名 `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:<hex>`(71 字符),snapshot 系用裸 64 hex。**入库一律剥 `sha256:` 前缀存裸 64 hex**,列统一 `CHAR(64)`;读取按列语义决定是否复原。所有 `*_sha256` 列同此。
- 一律 `.venv/bin/python .claude/skills/access-database/scripts/db.py apply 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](../.agent/docs/architecture/domains/05-创作流程领域.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 侧(`.claude/agents/*.md`、`.claude/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](../.agent/docs/architecture/可视化模块合同.md)、`db/表映射.md`。§4 旧 raw 清单删"未接受候选正文"、`raw_content.kind` 删 `candidate`(候选正文单存候选表,整表 raw 级访问控制——对齐 08 §3 落库合同表)。
## 5. 看板模块设计
合同在 [可视化模块合同](../.agent/docs/architecture/可视化模块合同.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 先落 `db/ddl/` 再 apply;`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](../.agent/docs/architecture/domains/_index.md)
- 存储/可恢复/raw/回执字段合同:[08](../.agent/docs/architecture/domains/08-数据权威与可视化领域.md) §3/§5/§7
- 候选状态机/绑定键/接受语义/评测隔离:[05](../.agent/docs/architecture/domains/05-创作流程领域.md) §3/§5/§8.4
- 候选/规划存储结构:[01](../.agent/docs/architecture/domains/01-作品领域.md)
- 上下文冻结与取数:[04](../.agent/docs/architecture/domains/04-上下文领域.md)
- 质量评判记录与量表版本:[06](../.agent/docs/architecture/domains/06-质量与复利领域.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)
- 只读看板合同:[可视化模块合同](../.agent/docs/architecture/可视化模块合同.md)
- 表清单与现状:[`db/表映射.md`](../db/表映射.md)
- 蒸馏去向:实现后表结构→`db/ddl/97–102`;清单约定→`db/表映射.md`;"哪些输入产出进哪类表"具体表名→08 §3。本文件届时删除。