# craft A/B 成稿质量前后对照评估回路（灵感 F2）

把「加 craft 杠杆」与「验证 craft 有效」绑成一件事的评估回路。每引入或改动一个 craft
杠杆（① 写章教条 / F1 genre 片段 / 开篇黄金三章 / 后续 ② 反哺、③ 人物塑造审查等），
就跑一次这里，做 craft-on vs craft-off 的前后对照——**没有它，craft 改动都是盲飞，
很可能把文风做得更 AI 公式化而不自知**（见计划 §5 风险 #13）。

## 它是什么

- 固定一组**金标准题材输入**（`fixtures.py`：仙侠 / 都市 / 悬疑，各含最小 spec+world+outline，
  且都是开篇章以覆盖黄金三章 marker）。
- 对每份 fixture 走**真实生产组装路径**（`assemble()` + `build_write_request()`）产出两版
  写章请求：
  - **craft-on** = 生产路径：craft 教条置顶 system 块 + genre 片段进 stable_core 缓存前缀 +
    开篇 marker 进 volatile。
  - **craft-off** = 同一 fixture 抹掉 craft 层的基线（剥掉 genre/开篇两节、不加教条块）。
    两版**唯一差异即 craft 贡献**，便于并排 diff 与 LLM 裁判对比。

## 两种模式

### dry（默认，零成本、免真实 LLM）

```bash
export PATH="$HOME/.local/bin:$PATH"
uv run python -m tests.craft_eval            # 全部题材
uv run python -m tests.craft_eval --genre 仙侠
```

只做**确定性校验 + prompt 并排 dump**：断言 craft 教条块、genre 片段、开篇 marker 确实按
fixture 注入了正确内容（且 craft-off 基线不含这三者），并把两版**将发送给模型的 prompt**
并排写进报告供人眼看。**不碰 LLM**，任一断言失败退出码非零——这些断言即
`tests/test_craft_eval.py`，随常规 `pytest` / CI 跑，是 craft 注入路径的回归门禁。

### live（真实付费生成 + LLM 五维裁判）

```bash
uv run python -m tests.craft_eval --live
```

**成本警告**：`--live` **真实调用付费 LLM**——每个题材跑 writer 生成 craft-on/craft-off 两章
＋ analyst 五维裁判 1 次（3 题材 ≈ 6 次写章 + 3 次裁判）。凭据从 DB 读、路由走 `tier_routing`，
与生产写章同一条网关路径（需 pg 在跑且已配好 provider 凭据；`--live` 前会先跑 dry 校验，
未全绿则拒绝进入付费生成）。**绝不进 CI**：live 路径在 `live.py`，pytest 不导入它。

报告默认写系统临时目录（`--out PATH` 自定义）；含每题材的 dry 校验清单、prompt 并排、
以及 live 模式下的两版成稿与五维裁判结论。

## 加了新 craft 杠杆后怎么用它把关

1. 改 craft（教条 `write_craft.md` / `GENRE_CRAFT` / 新审查维度……）。
2. 跑 `pytest tests/test_craft_eval.py` 确认注入路径没被改坏（dry 门禁）。
3. 跑 `--live` 生成前后对照，人眼 + LLM 五维裁判判断**是更对味还是更公式化**——
   据此决定该杠杆保留 / 回退（计划 §5 通用回滚：每杠杆可独立回退）。

## 加题材 / 调 fixture

在 `fixtures.py` 追加一个 `FixtureCase`（`genre` 必须命中 `ww_config.GENRE_CRAFT` 才有
片段可注入）。`harness.py` 的 craft-off 靠 `assemble` 的节标题（`本作题材写法` / `开篇黄金三章`）
剥离——上游若改节名，剥离失配会被 dry 断言当场炸出（craft-off 里仍含片段 → 断言失败）。
