muse-agent-example/docs/superpowers/plans/2026-07-20-writer-agent-v1.md
zizi e36cd57010 框架: 评测合同与提示词去支架化 + skill 三层重组(Phase 0-4)
【评测合同与提示词】
- writer/detector/judge 评测提示词去支架化:删评测身份/输出格式叮嘱/盲化反向叮嘱/机器字段
  (改由运行时 --json-schema/--tools ""/--strict-mcp-config/输入设计强制),装回各角色本业纪律
- writer 加写作纪律:戏剧化节拍禁抄细纲概述句、具体压倒抽象、每场戏三件套、篇幅用场景写够不注水不缩水
- 篇幅自纠环修订指令区分偏短(加场景)/偏长(删冗余);机械门要求清单(章末钩子/硬事件/角色/伏笔)注入写手硬约束
- 引文校验从「必须恰好1次」放宽为「0次失败关闭、≥1次绑首次」(检测+盲评同口径)
- llm 立 chat_governed 为主入口(chat 降为仅调试),clean_detect 改用 chat_governed 弃自带降级链
- rewrite/expansion/polish 输出合同对齐 writer.md(返回文本、写手不读写工作区、主会话落工作区)
- 修复 confirm/replay-eval 探针两组坏自测(夹具适配现行合同、探针测试自包含不硬编码漂移哈希);补 clean_detect 离线测试
- AGENTS.md 新增 §10「Agent 提示词与 Skill 审查标准」

【skill 三层重组:单向依赖 底座→能力→编排,断两环+修生产倒挂】
- Phase 0: 新建 runtime 底座(claude_runtime/file_cas/raw_vault),断环 C1、修 continuation 生产倒挂
- Phase 1: 评分尺+门判(writer_rubric/fine_outline_rubric/writer_gate/gate_input_builder)收进 quality-gate,断环 C2、名实相符
- Phase 2: 升格管线从 parse-book 独立成 upgrade skill(备份审计契约键名稳定、仅改路径定位)
- Phase 3: replay-eval 瘦成纯编排
- read-context 共用簇(build_snapshot/audit_leakage/check_snapshot/load_reference_work)下沉到新 snapshot skill,消除能力层向上引用
- Phase 4: run_writer_replay.py(130KB)拆成包(_common/budget/authorization/sample/blind/execute),__init__ 全量 re-export 测试零改动

【base 配置】三角色 effort 提 high;提示词更新;探针重测绑定 writer 合同;预算 writer 45 次/总 450 美元(含篇幅修订)

全量离线测试 36 个文件全绿;函数逻辑零改动(仅搬位置/改 import/改文档,capture_code_identity 仅改路径定位)。
2026-07-26 03:28:22 +08:00

574 lines
33 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.

# 正文智能体实验台 v1 Implementation Plan
> **类型:历史实施计划,非 SoT,禁止继续执行。** 文中的 v1 合同、文件路径、任务状态和命令只记录 2026-07-20 的实施基线;正文稳定合同以父仓 `design-docs/专题-03/04/05` 为准,后续执行只认当前 skill、配置和代码事实。
>
> **已迁移(2026-07-26 skill 重组):** 文中 `replay-eval/scripts/writer_rubric.py`、`writer_gate.py` 等评分/裁决模块已迁入 `quality-gate/scripts/`;`claude_runtime.py`/`file_cas.py`/`raw_vault.py` 运行时底座已迁入新建 `runtime/scripts/`。下文路径仅为历史基线,不代表当前位置。
> **执行约束(创始人 2026-07-20 确认):** 不使用 worktree,不使用 superpower。执行类任务由子代理直接在当前 `main` 工作树实现,主代理负责文件边界、代码审查与机械验证;不得暂存或覆盖用户已有改动。
**Goal:** 在参考作品回放环境中实现一套可机械验证的正文智能体:知识卡只承担索引职责,智能体必须顺着卡片证据回读冻结线内的历史原文,再依据大纲、细纲和事实证据生成正文,并经过审查、盲评及 Gate A/B 验收。
**Architecture:** 实验链路分为确定性上下文层、无工具写作层、审查收敛层和离线评测层。检索层在只读快照内生成 `RetrievalPlan` 与 `RetrievalManifest`;上下文层区分事实证据和文风证据;写手只接收冻结后的 `WriterContext v1`,不能自行调用工具;候选正文必须通过 detector 和接受前置检查。A/B/C 回放仅用于诊断,任何评测产物都不得进入 Canonical 正文。
**Tech Stack:** Python 3.12、标准库 `unittest`、PostgreSQL/psycopg、现有 `.claude/skills` 流程规范、Claude CLI adapter、YAML/JSON 元数据契约。
---
## 边界与完成定义
- 本计划只实现 `agent-example` 的正文实验台,不修改 `muse-cloud`、产品 API、正式状态机或业务数据库结构。
- v1 只验收“依据细纲生成下一章”的 `continuation` 场景;改写、扩写、润色、纠错、去 AI 味和角色声音仍复用 writer 身份,但不纳入本轮 Gate,不得宣称这些场景已优化完成。
- 生产化接口、数据库迁移和 UI 入口必须等 Gate B 通过后另立设计与实施计划。
- 所有冻结规则在可信的检索/组装层执行,不能依赖写手提示词自觉。
- `抽取卡 -> 原文` 是强制链路:抽取卡若没有可追踪的历史原文来源,不得单独作为正文硬事实。作者已确认的正式设定、Canonical 状态与细纲声明的新事实可以直接成为事实证据,并标为 `declared_new` 或相应来源类型。
- “完成”至少包含:测试通过、dry-run 通过、真实回放所需配置齐全;没有真实模型回放结果时只能称“实现完成”,不能称 Gate A/B 通过。
## 环境准备:当前主工作树本地依赖
- [ ] 在 `agent-example` 当前 `main` 工作树复用已安装依赖的 `.venv`,先确认解释器版本与依赖可用:
```bash
cd /Users/qingse/Sync/local-git/oh-my-muse/agent-example
.venv/bin/python --version
```
- [ ] 后续所有 Python 命令都在当前 `agent-example` 主工作树执行并使用 `.venv/bin/python`;若 `requirements.txt` 变化,先重装依赖再验证。
## 任务 0:回写稳定设计 SoT,标明实验边界
> 本任务直接在外层仓库 `/Users/qingse/Sync/local-git/oh-my-muse` 的当前 `main` 工作树执行。只提交下列精确路径,保留外层和内层工作树中的用户已有改动。
**Files:**
- Modify: `/Users/qingse/Sync/local-git/oh-my-muse/design-docs/专题-01-正文建议接受(Accept Suggestion)实现规范.md`
- Modify: `/Users/qingse/Sync/local-git/oh-my-muse/design-docs/专题-03-AI编排上下文与质量评测实现规范.md`
- Modify: `/Users/qingse/Sync/local-git/oh-my-muse/design-docs/专题-04-生成质量门控与创作健康度设计方案.md`
- Modify: `/Users/qingse/Sync/local-git/oh-my-muse/design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md`
- Modify: `/Users/qingse/Sync/local-git/oh-my-muse/design-docs/专题-06-元数据驱动的智能体架构.md`
- Modify: `/Users/qingse/Sync/local-git/oh-my-muse/design-docs/专题-07-知识消费契约与质量闭环.md`
- Modify: `/Users/qingse/Sync/local-git/oh-my-muse/design-docs/架构-04-状态机与约束清单.md`
- Modify: `/Users/qingse/Sync/local-git/oh-my-muse/.agents/workflows/ai-development-protocol.md`
- [ ] 在专题-07 中把“卡是索引,根据卡回读原文”设为正文消费契约,明确卡不能替代原文。
- [ ] 在专题-03 中补齐 `WriterContext v1`、`WriterOutput v1`、`RetrievalManifest` 和冻结语义。
- [ ] 在专题-04 中补齐正文五维评分、双盲评、第三评委仲裁、Gate A/B 唯一判定顺序。
- [ ] 在专题-05 中明确写手 adapter 的无工具、无会话持久化、超时失败关闭边界。
- [ ] 在专题-06 中登记 generation purpose 的严格 schema、卡索引视图和双证据字段;只引用各 owner 文档,不复制完整定义。
- [ ] 在专题-01 中补齐编辑后生成新 candidateVersion、重新 detector、`accept_preflight` 与 CAS 接受边界。
- [ ] 在架构-04 中标注实验态候选不能进入 Canonical,正式接受仍需 CAS 和 detector 绿证据。
- [ ] 在既有 `.agents/workflows/ai-development-protocol.md` 中沉淀反序验证门禁:清洗/抽卡/范式 -> 正文 Gate B -> 细纲 -> 大纲+设定;正文层固定采用卡索引与原文回读双线。
- [ ] 按外层 `CLAUDE.md` 检查概念 owner,只在 owner 文档定义,在其他文档放链接和一句话摘要;所有实质修改同步递增版本号和更新日期。
- [ ] 在文档中明确“本阶段不改 API 契约/DB”;只有 Gate B 通过后的产品化计划才更新 `docs/api-contracts/*` 和 Flyway。
- [ ] 运行文档一致性检查:
```bash
cd /Users/qingse/Sync/local-git/oh-my-muse
rg -n "卡是索引|WriterContext v1|acceptanceEligible|Gate A|Gate B|Canonical" \
'design-docs/专题-01-正文建议接受(Accept Suggestion)实现规范.md' \
design-docs/专题-03-AI编排上下文与质量评测实现规范.md \
design-docs/专题-04-生成质量门控与创作健康度设计方案.md \
design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md \
design-docs/专题-06-元数据驱动的智能体架构.md \
design-docs/专题-07-知识消费契约与质量闭环.md \
design-docs/架构-04-状态机与约束清单.md \
.agents/workflows/ai-development-protocol.md
```
- [ ] Commit:
```bash
git -C /Users/qingse/Sync/local-git/oh-my-muse add \
'design-docs/专题-01-正文建议接受(Accept Suggestion)实现规范.md' \
design-docs/专题-03-AI编排上下文与质量评测实现规范.md \
design-docs/专题-04-生成质量门控与创作健康度设计方案.md \
design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md \
design-docs/专题-06-元数据驱动的智能体架构.md \
design-docs/专题-07-知识消费契约与质量闭环.md \
design-docs/架构-04-状态机与约束清单.md \
.agents/workflows/ai-development-protocol.md
git -C /Users/qingse/Sync/local-git/oh-my-muse commit \
-m "设计: 固化正文智能体卡索引原文回读契约"
```
## 任务 1:建立 WriterContext/WriterOutput 严格契约
**Files:**
- Modify: `meta/schemas/generation_context.yaml`
- Modify: `meta/schemas/outline.yaml`
- Modify: `meta/schemas/README.md`
- Create: `.claude/skills/read-context/scripts/writer_contract.py`
- Create: `.claude/skills/read-context/scripts/test_writer_contract.py`
- [ ] 先写失败测试,覆盖:
- `runId` 不参与 manifest identity;相同输入得到相同 hash。
- Unicode NFC 归一化后计算偏移和 hash。
- 汉字数只计算 CJK Unified Ideographs,不以 Markdown 字符数冒充正文长度。
- 目标长度采用 half-up 取整,且受 min/max 硬边界约束。
- `evaluation`/`diagnostic` 上下文始终 `acceptanceEligible=false`。
- 未知字段、缺字段、错误版本号均 fail closed。
```bash
.venv/bin/python \
.claude/skills/read-context/scripts/test_writer_contract.py -v
```
- [ ] 实现 `normalize_text()`、`canonical_json()`、`retrieval_identity()`、`han_count()`、`calculate_target_chars()`。
- [ ] 定义并校验 `WriterContext v1`:大纲定位、细纲硬约束、冻结点、事实证据、文风证据、检索清单、目标长度、用途与接受资格。
- [ ] 定义并校验 `WriterOutput v1`:正文、claim ledger、evidence requests、新设定声明、候选版本和上下文 hash。
- [ ] 更新 YAML schema,使字段名、枚举和 Python 校验器一致;将 `generation_context` 从待启用改为实验台启用,并同步 `meta/schemas/README.md` 的状态和实例落点说明。
- [ ] 测试转绿并检查 schema 可读性。
- [ ] Commit:
```bash
git add meta/schemas/generation_context.yaml meta/schemas/outline.yaml meta/schemas/README.md \
.claude/skills/read-context/scripts/writer_contract.py \
.claude/skills/read-context/scripts/test_writer_contract.py
git commit -m "实现: 建立正文上下文与输出严格契约"
```
## 任务 2:实现确定性的卡检索和冻结原文读取
**Files:**
- Modify: `.claude/skills/search/scripts/search.py`
- Modify: `.claude/skills/replay-eval/scripts/load_reference_work.py`
- Create: `.claude/skills/read-context/scripts/retrieve_writer_sources.py`
- Create: `.claude/skills/read-context/scripts/test_retrieve_writer_sources.py`
- [ ] 先写失败测试,使用 fake repository 覆盖:
- 卡片按 `score DESC, source_version ASC, source_id ASC, source_offset ASC` 稳定排序。
- 同分检索多次结果一致。
- `stateAsOf` 只由 `chapter <= asOfChapter` 的里程碑派生。
- 终态摘要、未来章号、目标章正文和未来来源引用全部被拒绝。
- 每条抽取卡索引保留 `sourceVersion/sourceRefs/stateAsOf`;正式设定和细纲新事实使用各自的 Canonical 来源引用。
- 原文读取事务为 `REPEATABLE READ READ ONLY`。
- 作品生产检索只读 active Canonical entity 和有效 binding,拒绝 draft/eval 卡。
- 参考作品回放只读预注册的 `upgrade_book` 卡,并固定 `productionRetrievalEligible=false`,不能流入生产仓储适配器。
```bash
.venv/bin/python \
.claude/skills/read-context/scripts/test_retrieve_writer_sources.py -v
.venv/bin/python \
.claude/skills/replay-eval/scripts/test_load_reference_work.py -v
```
- [ ] 从 `search.py` 提取可复用的 `search_cards()`,CLI 继续调用同一实现,避免两套检索语义。
- [ ] 实现 `CardIndexRepository` 和 `ProseRepository` 协议:作品适配器复用 `search.py` 的授权过滤;回放适配器复用 `load_reference_work.py` 的授权快照、冻结投影和泄露审计;测试使用内存 fake。禁止复制一套旁路 SQL。
- [ ] 生成 `RetrievalPlan`:从大纲、细纲实体和状态需求确定卡片查询,不允许写手临场改变检索范围。
- [ ] 抽取卡命中后必须展开 `sourceRefs` 并读取冻结线内原文;没有来源的抽取卡事实标为 `unverifiedIndexHint`,不能单独进入事实证据。正式设定、Canonical 状态和细纲声明的新事实走独立可信来源,不强造历史原文。
- [ ] 测试转绿。
- [ ] Commit:
```bash
git add .claude/skills/search/scripts/search.py \
.claude/skills/replay-eval/scripts/load_reference_work.py \
.claude/skills/read-context/scripts/retrieve_writer_sources.py \
.claude/skills/read-context/scripts/test_retrieve_writer_sources.py
git commit -m "实现: 卡索引驱动冻结原文检索"
```
## 任务 3:组装双证据 WriterContext
**Files:**
- Create: `.claude/skills/read-context/scripts/assemble_writer_context.py`
- Create: `.claude/skills/read-context/scripts/test_assemble_writer_context.py`
- Modify: `.claude/skills/read-context/SKILL.md`
- [ ] 先写失败测试,覆盖:
- 连续前 4 章全文作为基础 prose evidence;不足 4 章时从第一章开始,不重复。
- 卡片来源原文作为补充 prose evidence,按来源去重并稳定排序。
- `factEvidence` 只含冻结后的历史事实、正式设定、Canonical 状态或细纲声明的新事实;`proseEvidence` 只含可引用原文。
- `evidenceCoverage` 显示细纲实体、关系、物品、地点、力量体系的覆盖和缺口。
- 同一快照、同一输入生成相同 manifest/context hash。
- 超出上下文预算时优先保留细纲硬约束、最近原文和高风险事实,裁剪结果可追踪。
```bash
.venv/bin/python \
.claude/skills/read-context/scripts/test_assemble_writer_context.py -v
```
- [ ] 实现确定性的 `assemble_context()`,输出 JSON 和可供人审阅的 Markdown manifest。
- [ ] 将每个事实绑定到证据引用:历史抽取事实必须回到章节、块和字符区间;正式设定、Canonical 状态和细纲新事实必须回到各自不可变版本引用。
- [ ] 更新 read-context 流程:先计划、再卡索引、再原文回读、最后组装,禁止直接把卡片全文倾倒给写手。
- [ ] 测试转绿。
- [ ] Commit:
```bash
git add .claude/skills/read-context/SKILL.md \
.claude/skills/read-context/scripts/assemble_writer_context.py \
.claude/skills/read-context/scripts/test_assemble_writer_context.py
git commit -m "实现: 组装正文事实与文风双证据上下文"
```
## 任务 4:收紧无工具写手并实现动态篇幅
**Files:**
- Modify: `.claude/agents/writer.md`
- Modify: `.claude/skills/continuation/SKILL.md`
- Modify: `README.md`
- Create: `.claude/skills/continuation/scripts/run_writer.py`
- Create: `.claude/skills/continuation/scripts/test_run_writer.py`
- [ ] 先写失败测试,fake subprocess 断言:
- adapter 使用 `--tools ""` 和 `--no-session-persistence`。
- adapter 同时使用 `--print --output-format json --agent writer --model opus`,CLI 参数与当前安装版本一致。
- 只把 `WriterContext v1` 通过 stdin 交给写手。
- 超时、非零退出、非 JSON、schema 不符均失败关闭,不产生可接受候选。
- 输出正文汉字数落在动态目标区间;越界返回结构化失败。
- claim ledger 的每项包含事实类型、正文偏移、候选文本 hash 和证据引用。
```bash
.venv/bin/python \
.claude/skills/continuation/scripts/test_run_writer.py -v
```
- [ ] 从 `writer.md` 移除 `Read/Write/Grep/Glob` 工具声明,明确禁止自行检索和写文件;adapter 以参数列表调用 CLI,禁止 shell 字符串拼接。
- [ ] 写手提示词把细纲定义为硬骨架,把大纲定义为方向,把 fact evidence 定义为设定约束,把 prose evidence 定义为叙事和文风参考。
- [ ] 实现动态目标长度:依据细纲场景数、动作/对话/转折权重和前文中位章长计算,不再写死 4000-5000 字。
- [ ] 要求输出 `claimLedger/evidenceRequests/newSettingDeclarations`,不得静默补设定。
- [ ] 更新 README 的 writer 能力说明和篇幅口径,删除固定“2500-3500 字”的旧描述,并明确 v1 仅验收 continuation。
- [ ] 测试转绿。
- [ ] Commit:
```bash
git add .claude/agents/writer.md .claude/skills/continuation/SKILL.md README.md \
.claude/skills/continuation/scripts/run_writer.py \
.claude/skills/continuation/scripts/test_run_writer.py
git commit -m "实现: 无工具正文写手与动态篇幅控制"
```
## 任务 5:实现 detector 硬门和有限收敛循环
**Files:**
- Modify: `.claude/agents/detector.md`
- Modify: `.claude/skills/detect/SKILL.md`
- Create: `.claude/skills/detect/scripts/check_writer_candidate.py`
- Create: `.claude/skills/detect/scripts/test_check_writer_candidate.py`
- Create: `.claude/skills/continuation/scripts/run_writer_pipeline.py`
- Create: `.claude/skills/continuation/scripts/test_run_writer_pipeline.py`
- [ ] 先写失败测试,覆盖:
- 细纲关键事件、角色、伏笔、章末钩子是硬约束,缺一项即不通过。
- claim ledger 的 Unicode 偏移、候选 hash 和证据引用不匹配即不通过。
- 新设定未声明或与冻结事实冲突即不通过。
- evidence request 最多 3 次;重写最多 2 次;达到上限返回稳定失败码。
- 状态只能通过 CAS 从 `DRAFT -> CHECKING -> PASSED/REJECTED`,并发旧版本不能覆盖新版本。
- 运行结果临时文件写完并 fsync 后原子替换正式结果。
```bash
.venv/bin/python \
.claude/skills/detect/scripts/test_check_writer_candidate.py -v
.venv/bin/python \
.claude/skills/continuation/scripts/test_run_writer_pipeline.py -v
```
- [ ] 实现机械校验器,模型 detector 只负责无法机械判定的语义项。
- [ ] 实现“请求证据 -> 重新组装上下文 -> 重写 -> 重审”的有限状态机。
- [ ] 更新 detector 和 detect 规范,输出结构化 failure codes,保留全部审查轨迹。
- [ ] 测试转绿。
- [ ] Commit:
```bash
git add .claude/agents/detector.md .claude/skills/detect/SKILL.md \
.claude/skills/detect/scripts/check_writer_candidate.py \
.claude/skills/detect/scripts/test_check_writer_candidate.py \
.claude/skills/continuation/scripts/run_writer_pipeline.py \
.claude/skills/continuation/scripts/test_run_writer_pipeline.py
git commit -m "实现: 正文细纲硬审查与有限收敛循环"
```
## 任务 6:实现接受前置检查,隔离评测产物
**Files:**
- Modify: `.claude/skills/confirm/SKILL.md`
- Modify: `meta/chains/README.md`
- Create: `.claude/skills/confirm/scripts/check_writer_acceptance.py`
- Create: `.claude/skills/confirm/scripts/test_writer_acceptance.py`
- [ ] 先写失败测试,覆盖:
- `acceptanceEligible=false` 的诊断/评测候选不可接受。
- 用户编辑后必须产生新 candidateVersion,并重新跑 detector。
- `expectedRevision` 不匹配时返回冲突,不覆盖 Canonical。
- 只有 detector 绿、上下文 hash 一致、候选未过期才能进入 Shadow 待接受态。
- `accept/merge/discard` 都要求明确确认;接受成功后才允许异步触发抽卡。
```bash
.venv/bin/python \
.claude/skills/confirm/scripts/test_writer_acceptance.py -v
```
- [ ] 实现纯函数 preflight,实验台仅验证状态转换,不写正式正文库。
- [ ] 更新 confirm 和 chain 文档,删除“修改后直接合并”的模糊路径。
- [ ] 测试转绿。
- [ ] Commit:
```bash
git add .claude/skills/confirm/SKILL.md meta/chains/README.md \
.claude/skills/confirm/scripts/check_writer_acceptance.py \
.claude/skills/confirm/scripts/test_writer_acceptance.py
git commit -m "实现: 正文候选接受前置检查"
```
## 任务 7:建立正文五维量表和盲评仲裁
**Files:**
- Modify: `.claude/agents/judge.md`
- Modify: `.claude/skills/eval/SKILL.md`
- Modify: `.claude/skills/quality-gate/SKILL.md`
- Create: `.claude/skills/replay-eval/scripts/writer_rubric.py`
- Create: `.claude/skills/replay-eval/scripts/test_writer_rubric.py`
- [ ] 先写失败测试,覆盖五维各 0-10 分、0.5 步长:
- 设定与实体保真。
- 细纲与情节忠实。
- 文风一致性。
- 叙事张力。
- 文笔与可读性。
- [ ] 测试双评委去盲;同一维两次评分差异 `>0.5` 时启动一次第三评委。
- [ ] 第三评委后,若三评分中至少一对差值 `<=0.5`,该维取三者中位数;不存在稳定配对则样本标为 `invalid_unstable`,不强行给输赢。
- [ ] 评委必须逐项标注证据来自细纲、历史原文、卡片还是自行推断,便于识别假阴/假阳。
- [ ] writer rubric 必须作为独立 profile 接入,不覆盖现有 `fine_outline_replay` profile;运行既有细纲 rubric 回归测试。
```bash
.venv/bin/python \
.claude/skills/replay-eval/scripts/test_writer_rubric.py -v
.venv/bin/python \
.claude/skills/replay-eval/scripts/test_rubric.py -v
```
- [ ] 同步 judge/eval/quality-gate 的维度、阈值和无效样本语义。
- [ ] 测试转绿。
- [ ] Commit:
```bash
git add .claude/agents/judge.md .claude/skills/eval/SKILL.md \
.claude/skills/quality-gate/SKILL.md \
.claude/skills/replay-eval/scripts/writer_rubric.py \
.claude/skills/replay-eval/scripts/test_writer_rubric.py
git commit -m "实现: 正文五维盲评与稳定性仲裁"
```
## 任务 8:实现 A/B/C 同条件回放编排
**Files:**
- Create: `.claude/skills/replay-eval/scripts/run_writer_replay.py`
- Create: `.claude/skills/replay-eval/scripts/test_run_writer_replay.py`
- [ ] 先写失败测试,验证三臂唯一变量:
- A:仅历史原文,无卡索引,诊断候选。
- B:仅冻结卡片索引,不回读原文;卡内容放入 `indexHints` 而非生产 `factEvidence`,用于测“把卡当原文替代品”的诊断候选。
- C:卡索引 + 原文回读,诊断候选。
- 三臂共享同一作品、冻结点、大纲、细纲、目标长度、模型版本、采样参数和 detector。
- 三臂 manifest 清楚记录差异,候选全部 `acceptanceEligible=false`。
- 任一臂泄露目标章/未来章时整组样本作废。
- real-run 输出目录不在 `/private/tmp` 时失败关闭,防止原书或候选误入仓库。
```bash
.venv/bin/python \
.claude/skills/replay-eval/scripts/test_run_writer_replay.py -v
.venv/bin/python \
.claude/skills/replay-eval/scripts/test_run_replay.py -v
```
- [ ] 实现 dry-run:只生成计划、manifest 和上下文摘要,不调用模型。
- [ ] 复用现有 replay-eval 的 `build_snapshot.py`、`check_snapshot.py`、`audit_leakage.py`、`load_reference_work.py` 和授权预检;`run_writer_replay.py` 只增加正文 profile、三臂上下文和 writer/detector/judge 编排,不另造冻结、授权或数据库旁路。
- [ ] 固定 CLI:`--config`、`--run-id`、`--output-dir`;默认 dry-run,只有显式 `--execute` 才调用模型。real-run 强制 `output-dir` 位于 `/private/tmp`。
- [ ] 实现 real-run:调用三臂、detector、双盲评和必要的第三评委;原书、候选、完整 prompt/response 只写入显式传入的 `/private/tmp` 运行目录,结构化结果中不得嵌入原文全文。
- [ ] 测试转绿。
- [ ] Commit:
```bash
git add .claude/skills/replay-eval/scripts/run_writer_replay.py \
.claude/skills/replay-eval/scripts/test_run_writer_replay.py
git commit -m "实现: 正文三臂冻结回放编排"
```
## 任务 9:实现 Gate A/B 唯一判定器
**Files:**
- Create: `.claude/skills/replay-eval/scripts/writer_gate.py`
- Create: `.claude/skills/replay-eval/scripts/test_writer_gate.py`
- [ ] 先写表驱动失败测试,固定终态优先级。
- [ ] Gate A 判定顺序:有效样本 `<5` -> `insufficient_evidence`;否则只要存在 schema 非法、未来泄漏、系统失败、C 臂 detector 高严重度残留或细纲硬约束覆盖率 `<100%` -> `failed`;其余 -> `passed`。
- [ ] Gate B 判定顺序:Gate A=`insufficient_evidence` -> `insufficient_evidence`;Gate A=`failed` -> `failed`;否则若作品 `<2`、任一作品样本 `<5`、总样本 `<10`、五类场景未覆盖或不稳定样本占比 `>20%` -> `insufficient_evidence`;再判断 C 臂硬约束覆盖率 `<100%`、高严重度残留、文风/叙事张力平均增量 `<-0.25`,或任一维下降 `>0.5` 的样本占比 `>20%`,命中 -> `failed`;再判断 C-A“设定与实体保真”平均增量 `>=0.25` 且正向样本比例 `>=0.60`,达标 -> `passed`;其余 -> `no_gain`。
- [ ] Gate B 不允许用单章、单作品或只选卡友好场景得出普适结论。
- [ ] 报告必须列出假阴、假阳、泄露、评委不稳定和新角色无卡等混淆项。
```bash
.venv/bin/python \
.claude/skills/replay-eval/scripts/test_writer_gate.py -v
```
- [ ] 实现判定器并测试转绿。
- [ ] Commit:
```bash
git add .claude/skills/replay-eval/scripts/writer_gate.py \
.claude/skills/replay-eval/scripts/test_writer_gate.py
git commit -m "实现: 正文 Gate A B 唯一判定器"
```
## 任务 10:预注册 Gate A 样本并完成全量机械验证
**Files:**
- Create: `.claude/skills/replay-eval/configs/writer-gate-a-deep-space-v1.json`
- Modify: `.claude/skills/replay-eval/SKILL.md`
- Modify: `docs/2026-07-20-正文智能体正式优化设计与计划.md`
- [ ] 预注册深空之影 5 个目标章,固定为:第 489 章“圣蒂曼围攻/加特朗战”=战斗;第 321 章“莫妮卡道别与朋友确认”=人物对话;第 544 章“迷途之地内应反水”=转折;第 199 章“赛莉丝身份与联赛锁死真相”=信息揭示;第 523 章“伊蕾莉雅与旧部重逢”=老角色回归。不得根据生成结果换章或改分类。
- [ ] 每章记录冻结点、目标章、原始大纲/细纲来源、预期长度、主要实体、新角色比例和泄露检查方式。
- [ ] 更新 replay-eval 流程和正文设计文档,使实际命令、输出路径、Gate 状态与实现一致。
- [ ] 运行全部新增测试:
```bash
.venv/bin/python -m unittest discover \
-s .claude/skills/read-context/scripts -p 'test_*.py' -v
.venv/bin/python -m unittest discover \
-s .claude/skills/continuation/scripts -p 'test_*.py' -v
.venv/bin/python -m unittest discover \
-s .claude/skills/detect/scripts -p 'test_*.py' -v
.venv/bin/python -m unittest discover \
-s .claude/skills/confirm/scripts -p 'test_*.py' -v
.venv/bin/python -m unittest discover \
-s .claude/skills/replay-eval/scripts -p 'test_*.py' -v
```
- [ ] 运行静态检查:
```bash
git diff --check
if rg -n "TODO|TBD|implement later" \
.claude/skills/read-context .claude/skills/continuation .claude/skills/detect \
.claude/skills/confirm .claude/skills/replay-eval meta/schemas; then
echo "发现未完成占位文本" >&2
exit 1
fi
```
- [ ] 运行不烧模型额度的 dry-run:
```bash
.venv/bin/python \
.claude/skills/replay-eval/scripts/run_writer_replay.py \
--config .claude/skills/replay-eval/configs/writer-gate-a-deep-space-v1.json \
--dry-run
```
- [ ] 检查 dry-run:五个样本均冻结正确、三臂差异仅为证据策略、目标章和未来章读取数为 0、所有候选不可接受。
- [ ] Commit:
```bash
git add .claude/skills/replay-eval/SKILL.md \
.claude/skills/replay-eval/configs/writer-gate-a-deep-space-v1.json \
docs/2026-07-20-正文智能体正式优化设计与计划.md
git commit -m "验证: 预注册正文 Gate A 回放样本"
```
## 任务 11:真实 Gate A 回放和人工复核门
**Files:**
- Generated outside repo: `/private/tmp/muse-writer-replay/<run-id>/manifest.json`
- Generated outside repo: `/private/tmp/muse-writer-replay/<run-id>/gate-report.json`
- Generated outside repo: `/private/tmp/muse-writer-replay/<run-id>/raw/`
- Create after sanitization: `docs/replay/<run-id>-writer-summary.md`
- [ ] 执行前记录模型版本、价格窗口、随机参数、代码 commit、数据 snapshot identity;任一项缺失则不启动。
- [ ] 运行真实回放。该步骤会消耗 Claude/MiniMax 调用,执行者在运行前向用户报预算和样本规模。
- [ ] 获得预算确认后,使用同一 shell 中的固定 `RUN_ID` 执行:
```bash
RUN_ID="writer-gate-a-$(date -u +%Y%m%dT%H%M%SZ)"
RUN_DIR="/private/tmp/muse-writer-replay/$RUN_ID"
.venv/bin/python .claude/skills/replay-eval/scripts/run_writer_replay.py \
--config .claude/skills/replay-eval/configs/writer-gate-a-deep-space-v1.json \
--run-id "$RUN_ID" --output-dir "$RUN_DIR" --execute
.venv/bin/python .claude/skills/replay-eval/scripts/writer_gate.py \
--run-dir "$RUN_DIR" --summary-output "docs/replay/$RUN_ID-writer-summary.md"
```
- [ ] 人工抽查每章三臂的冻结边界、证据引用、细纲执行和评委归因;发现目标章泄露则整批作废并修复后重跑。
- [ ] 运行 `writer_gate.py` 生成唯一 Gate A 结果;不得手工改状态。
- [ ] 若 Gate A 为 `passed`,进入任务 12 的 Gate B 多作品预注册;若 `failed/insufficient_evidence`,按 failure code 修正文层,不提前启动细纲智能体。
- [ ] 最终提交只包含配置、代码和不含原书全文/完整细纲/完整 prompt-response 的评分摘要;原书正文、生成正文和评委原始响应只留在 `/private/tmp/muse-writer-replay/<run-id>/raw/`,不得复制进仓库。
- [ ] Commit:
```bash
git add "docs/replay/$RUN_ID-writer-summary.md"
git commit -m "验证: 裁决正文智能体 Gate A"
```
## 任务 12:预注册 Gate B 多作品评估集
**Files:**
- Create: `.claude/skills/replay-eval/configs/writer-gate-b-v1.json`
- Modify: `.claude/skills/replay-eval/scripts/test_run_writer_replay.py`
- Modify: `.claude/skills/replay-eval/scripts/test_writer_gate.py`
- [ ] 只有 Gate A=`passed` 才执行本任务;否则保持配置未启用并修正文层。
- [ ] 固定 2 本书、每书 5 章、总计 10 章,且两书都覆盖五类场景:
- 深空之影 work=8:489 战斗、321 人物对话、544 转折、199 信息揭示、523 老角色回归。
- 机动风暴 work=4:489 战斗、95 人物对话、450 转折、210 信息揭示、414 老角色回归。
- [ ] 配置固定每章的 `asOf=targetChapter-1`、作品/source 版本、授权快照、模型、采样参数、篇幅算法、最大预算、臂定义和随机化种子;不得根据 Gate A 或生成结果替换章节。
- [ ] 增加配置校验测试:作品数、每书样本数、总样本数、场景覆盖、重复章、冻结点和授权任一不符即拒绝。
- [ ] 增加判定测试:不稳定样本占比、平均退化、单样本大幅退化、保真平均增量和正向比例均按任务 9 的唯一顺序裁决。
```bash
.venv/bin/python .claude/skills/replay-eval/scripts/test_run_writer_replay.py -v
.venv/bin/python .claude/skills/replay-eval/scripts/test_writer_gate.py -v
.venv/bin/python .claude/skills/replay-eval/scripts/run_writer_replay.py \
--config .claude/skills/replay-eval/configs/writer-gate-b-v1.json \
--dry-run
```
- [ ] dry-run 必须证明:10/10 样本冻结正确、两书各 5 章、五类场景全覆盖、目标章/未来章读取数为 0、三臂除证据策略外无差异、所有候选不可接受。
- [ ] Commit:
```bash
git add .claude/skills/replay-eval/configs/writer-gate-b-v1.json \
.claude/skills/replay-eval/scripts/test_run_writer_replay.py \
.claude/skills/replay-eval/scripts/test_writer_gate.py
git commit -m "验证: 预注册正文 Gate B 多作品评估集"
```
## 任务 13:真实 Gate B 回放与正文层最终裁决
**Files:**
- Generated outside repo: `/private/tmp/muse-writer-replay/<run-id>/gate-report.json`
- Create after sanitization: `docs/replay/<run-id>-writer-gate-b-summary.md`
- Modify after result: `docs/2026-07-20-正文智能体正式优化设计与计划.md`
- [ ] 执行前向用户报告 10 章 x 3 臂 x detector/judge/仲裁的调用上限、模型和预算;没有明确预算记录不启动。
- [ ] 获得预算确认后运行 Gate B,全量原始输入输出只落 `/private/tmp`:
```bash
RUN_ID="writer-gate-b-$(date -u +%Y%m%dT%H%M%SZ)"
RUN_DIR="/private/tmp/muse-writer-replay/$RUN_ID"
.venv/bin/python .claude/skills/replay-eval/scripts/run_writer_replay.py \
--config .claude/skills/replay-eval/configs/writer-gate-b-v1.json \
--run-id "$RUN_ID" --output-dir "$RUN_DIR" --execute
.venv/bin/python .claude/skills/replay-eval/scripts/writer_gate.py \
--run-dir "$RUN_DIR" --summary-output "docs/replay/$RUN_ID-writer-gate-b-summary.md"
```
- [ ] 人工抽查两书各至少 2 章的 manifest、冻结边界、卡到原文指针、claim ledger 和评委归因;发现泄露或控制变量漂移则整批作废。
- [ ] 由 `writer_gate.py` 生成唯一终态:`passed` / `failed` / `insufficient_evidence` / `no_gain`,不得手工覆盖。
- [ ] 只有 Gate B=`passed` 才把正文层标为通过并启动“细纲智能体”设计与回放;其余终态继续修正文层或补合法样本。
- [ ] 将脱敏摘要和终态回写任务 SoT;不提交原书、候选正文、完整细纲、完整 prompt/response 或供应商原始响应。
- [ ] Commit:
```bash
git add "docs/replay/$RUN_ID-writer-gate-b-summary.md" \
docs/2026-07-20-正文智能体正式优化设计与计划.md
git commit -m "验证: 裁决正文智能体 Gate B"
```
## 完成检查单
- [ ] 设计 SoT、schema、Python 校验器和技能规范字段一致。
- [ ] 写手无工具、无会话、不能自行绕过冻结检索。
- [ ] 抽取卡只作为索引;抽取卡承载的既有事实能回到冻结原文,正式设定/Canonical 状态/细纲新事实能回到各自权威版本。
- [ ] 细纲执行由 detector 硬门保证,不依赖评委事后打分。
- [ ] 诊断候选与生产候选在契约和状态机上隔离。
- [ ] A/B/C 回放控制变量完整,包含假阴/假阳分析。
- [ ] Gate A/B 由唯一判定器输出,单章结果不能宣称正文层完成。
- [ ] 本计划的正文层最终完成条件是 Gate B=`passed`;Gate A 通过只代表链路可运行。
- [ ] Gate B 通过前不启动细纲智能体,不修改产品 API/DB/Canonical 主链。