Forráskód Böngészése

chore(task): 登记 M2 写章流程任务规划(prd/design/implement)

复杂任务三件套,brainstorm 收敛后定:
- D1 单任务分期(同 M1):fixture+Writers → 近况+备料 → 机检 → 定稿
- D2 机检 7 个确定性项;统计项(句式体检/高频意象)推 M3+ 体检
- D3 定稿以 git commit 为原子单元,写工作树→commit→最后清工作区,断电安全
- D4 6 个 Writer 小端口;原子性在 finalize 编排
范围=八阶段脚本面(步骤 1脚本/3/5/8),零 AI;出口=细纲→定稿全程脚本跑通+断电注入工作区原样。
lingfengQAQ 1 napja
szülő
commit
93d46949f6

+ 1 - 0
.trellis/tasks/06-27-m2-writing-flow/check.jsonl

@@ -0,0 +1 @@
+{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}

+ 116 - 0
.trellis/tasks/06-27-m2-writing-flow/design.md

@@ -0,0 +1,116 @@
+# 技术设计:M2 写章流程脚本面(零 AI 全通)
+
+## 1. 设计范围与分层
+
+实现八阶段中「执行体=脚本」的四块(spec §8 步骤 1脚本部分/3/5/8),全部零 AI:
+
+```
+全书近况组装  ──┐
+               ├─→ 备料(prep) ─→ [写稿 AI=M4] ─→ 机检(check) ─→ [两审 AI=M4] ─→ [审稿 作者] ─→ 定稿(finalize, 原子)
+(M1 报表复用) ──┘
+```
+
+模块落点(填 M0 占位 + 新增 Writer 端口):
+- `v7/src/prep/` —— 全书近况组装 + 备料 `prepareChapterMaterials`
+- `v7/src/mechanical-check/` —— 机检 `mechanicalCheck`(7 项,D2)
+- `v7/src/finalize/` —— 定稿 `finalizeChapter`(原子编排)
+- `v7/src/storage/adapters/` —— Writer 端口真实现 + 新增(见 §3)
+
+复用 M1:41 读接口/Storage Reader 端口、`run(args,options,ctx)` 命令契约、防呆序列化(serializeFrontMatter/yaml-dialect,保留未知字段=不变量 9)、`.cache` 重建器、`parseFrontMatter`。
+
+## 2. 数据流与工作区契约(spec §7)
+
+工作区四件套(默认 gitignored,实现**不得假设**其未被 git 跟踪):
+- `工作区/细纲.md` —— 四段(全书近况/本章提案/本章要写到的事/备选);M2 读"本章要写到的事"与定位
+- `工作区/本章写作材料.md` —— 备料产出
+- `工作区/草稿-*.md` —— 写稿产出(M2 测试用手工伪造)
+- `工作区/审稿.md` —— 草稿+审意见+待确认新专名+章摘要(M2 测试用手工伪造;定稿读其中的章摘要定稿版)
+
+`.gitignore` 须含 `.cache/` 与 `工作区/`(spec §2 行 67)。
+
+## 3. Writer 端口(Q4 决策:小端口 + finalize 编排)
+
+延续 M1「小端口、职责最小」。定稿写多种文件 → 每文件类型一个 Writer(防呆序列化 + 保留未知字段),**原子性不在 Writer 层,在 finalize 编排**:
+
+| Writer | 职责 | 状态 |
+|--------|------|------|
+| `ChapterWriter` | 写 `定稿/正文/NNNN-标题.md`(front matter 章档案 + 正文) | M1 占位 → 真实现 |
+| `ThreadLedgerWriter` | 三类条目 front matter 更新 + `## 履历` 追加 | M1 占位 → 真实现 |
+| `EntityWriter`(新) | 角色卡 front matter 更新(位置/状态/境界/持有/最后变更章)+ 名册行 upsert | 新增 |
+| `TimelineWriter`(新) | `定稿/设定/时间线/第NN卷.md` 追加表格行 | 新增 |
+| `SecretWriter`(新) | `定稿/设定/信息差/` 写/更新 | 新增 |
+| `SummaryWriter`(新) | `定稿/摘要/章摘要/NNNN.md` 写出 | 新增 |
+
+每个 Writer 方法返回 `{ok, error}`,纯文件 IO,不碰 git、不清工作区。所有 front matter 写出走 `serializeFrontMatter`(块列表/危险值引号/保留未知字段)。
+
+## 4. 定稿原子性(Q3 决策:git commit 为原子单元)
+
+`finalizeChapter(ctx, {chapterNum, title, draftPath, reviewSheet, ledgerChanges, settingChanges})`:
+
+```
+1. 前置校验:草稿/审稿单存在;机检结果=pass(不 pass 不进定稿);章号未占用
+2. 写工作树(全部落 定稿/,非 工作区):
+   - ChapterWriter 写正文 + 章档案 front matter
+   - EntityWriter/TimelineWriter/SecretWriter 落 设定 变更
+   - ThreadLedgerWriter 落 条目 front matter + 履历
+   - SummaryWriter 落 章摘要
+3. git add <上述具体文件>  →  git commit -m "ch(NNN): 标题\n\n条目: ...\n设定: ..."   ← 原子点
+4. 清工作区(rm 草稿-*/细纲/本章写作材料/审稿)  ← 必须在 commit 成功之后
+返回 {ok, commitHash, error}
+```
+
+**断电安全论证**(对齐出口"工作区原样保留"):
+- **commit 前中断**:`定稿/` 的写入只是未提交的工作树改动,git 历史未变;恢复 = `git restore --staged --worktree 定稿/ 大纲/`(或回退到 HEAD),把半成品丢弃;`工作区/` 草稿在第 4 步才删,**原样保留** → 可重跑定稿。
+- **commit 后、清工作区前中断**:章已定稿(commit 在),仅工作区残留;重跑 finalize 检测到该章已提交 → 幂等地补清工作区。
+- **保证**:要么 commit 发生(整章定稿),要么没发生(`定稿/` git 历史不变 + 工作区草稿不丢)。**不存在「半章入档」**。
+- commit message `ch(NNN):` ASCII 前缀是机器协议(spec §8,便于 `git log --grep`)。
+
+**git 操作**:M2 用 `node:child_process` 跑 `git`(add/commit/restore/log)。git 健康检查(半提交/锁/损坏)是 M3 状态机职责,M2 假设 git 仓库健康,只保证自身原子性。
+
+## 5. 备料与全书近况
+
+**全书近况组装**(`assembleBookStatus(ctx)`)复用 M1:卷进度(list-volumes + chapters MAX)、悬了太久(report-overdue-threads)、连续弱钩(report-weak-hook-streak)、全书统计(report-book-stats)→ 结构化对象 + Markdown 段(喂细纲 step1 与备料 step3)。
+
+**备料**(`prepareChapterMaterials(ctx, {chapterNum})`)组装 `工作区/本章写作材料.md`,八组件(spec §8 step3):全书近况 + 本章要写到的事(读细纲)+ 事实切片(精准片段:当前卷+上一卷时间线、相关条目、近章结尾)+ 信息差边界(未揭晓 list-secrets)+ 近章结尾(read-chapters --recent --tail)+ 反复读清单(高频意象,M2 占位/空)+ 文风锚点(文风铁律 铁律/节奏偏好 + 金句库)+ 反和解规则(文风铁律 `## 反和解`)。默认精准片段(§11.1)。
+
+## 6. 机检(7 项,D2)
+
+`mechanicalCheck(ctx, {chapterNum, draftPath})` → `{ok, pass, issues:[], candidates:[]}`。不过关(pass=false)= 存在硬性违规(字数越界/禁词/禁句式/front matter 缺失/新专名…按项定阻断性)。候选(信息差关键词)只列不拦。
+
+| # | 项 | 数据源 | 阻断? |
+|---|---|--------|------|
+| 1 | 字数区间 | book.yaml `每章目标字数` ± 容差 | 是 |
+| 2 | 禁词 | 文风铁律 front matter `禁词` | 是 |
+| 3 | 禁句式 | 文风铁律 `禁句式`(正则) | 是 |
+| 4 | 本章内复读 | 草稿自身(n-gram 重复短语阈值) | 是(高于阈值) |
+| 5 | 新专名比名册 | 草稿专名候选 vs entities/aliases | 否(进审稿单待确认) |
+| 6 | front matter 格式完整性 | 草稿/章档案必填字段 | 是 |
+| 7 | 信息差关键词候选 | secrets `关键词` 命中正文 | 否(只出候选) |
+
+统计项(跨章高频意象、句式体检)**留 M3+ 体检**(D2),`mechanicalCheck` 预留 `checks` 注册表便于扩展。专名抽取用保守规则(连续中文 + 已知专名表比对),不做 NLP。
+
+## 7. fixture 扩展
+
+`v7/test/fixtures/sample-book/` 补:
+- `文风/文风铁律.md`(front matter 禁词/禁句式/口癖 + ## 铁律/反和解/节奏偏好)
+- `工作区/细纲.md`(四段)、`工作区/草稿-A.md`(伪造草稿)、`工作区/审稿.md`(含章摘要定稿版)—— 注意 `工作区/` 在被测仓库里要存在但 fixture 仓库非真 git,测试用临时 git 仓库验证定稿 commit
+
+定稿/git 类测试用 `mkdtemp` + `git init` 临时书仓库(同 M1 rebuilder 测试模式),不污染 fixture。
+
+## 8. 测试策略(镜像 src,TDD)
+
+- `test/prep/`:assembleBookStatus、prepareChapterMaterials(喂 fixture,断言材料文件含八组件锚点)
+- `test/mechanical-check/`:7 项逐项正例+反例(字数越界/命中禁词/禁句式正则/复读超阈/缺 front matter 字段/新专名进候选/信息差候选)
+- `test/finalize/`:
+  - 正常:伪造草稿+审稿单 → finalize → 断言 定稿/正文 落档、设定/条目/章摘要更新、工作区清空、git log 出现 `ch(NNN):`
+  - **原子性(出口)**:注入 step2 与 step3 之间抛错 → 断言无新 commit + 工作区草稿原样 + `git status` 可净恢复
+  - 删 `.cache` 重建后查询与定稿前后一致(不破坏不变量 2)
+- `test/storage/adapters/`:6 个 Writer 各正例(写出走防呆、保留未知字段)
+
+## 9. 边界与非目标
+
+- ❌ AI 步骤(拟提案/写稿/两审)、作者交互、状态机编排(M3/M4)
+- ❌ 自动模式/批次/叠加视图/污染传播(M6)
+- ❌ 统计型机检(句式体检/高频意象)→ M3+ 体检
+- ❌ 增量缓存更新(定稿后只写变化行)→ M6;M2 定稿后靠 M1 全量重建保持缓存一致
+- ❌ git 健康检查/异常修复(M3);M2 假设仓库健康

+ 1 - 0
.trellis/tasks/06-27-m2-writing-flow/implement.jsonl

@@ -0,0 +1 @@
+{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}

+ 89 - 0
.trellis/tasks/06-27-m2-writing-flow/implement.md

@@ -0,0 +1,89 @@
+# 执行计划:M2 写章流程脚本面
+
+> 前置:已读 spec §6.1(文风铁律)/§7(工作区)/§8(八阶段)、v7-implementation-plan §1.5、M2 prd/design。
+> 落点 `v7/src/{prep,mechanical-check,finalize,storage/adapters}` 与 `v7/test/`。
+> 本机:`cd v7 && PYTHONUTF8=1 node --test`;零依赖铁律延续;命令走 M1 `run(args,options,ctx)` 契约。
+> 工作方式:不开子代理;TDD(先红后绿);诚实分期 commit。
+
+## 分期(D1:单任务分期,紧依赖链)
+
+```
+P0 fixture + Writer 端口(finalize 的地基)
+   ↓
+P1 全书近况组装 + 备料(用 M1 读端口)
+   ↓
+P2 机检 7 项(用 文风铁律 + readers)
+   ↓
+P3 定稿原子编排 + 原子性/出口测试
+   ↓
+P4 CLI 接口 wire + 全量 AC 复核
+```
+
+## P0 fixture 扩展 + Writer 端口真实现
+
+- [ ] P0.1 fixture 补 `文风/文风铁律.md`(front matter 禁词/禁句式/口癖 + ## 铁律/反和解/节奏偏好),`工作区/{细纲.md,草稿-A.md,审稿.md}`(伪造,含章摘要定稿版)
+- [ ] P0.2 `v7/.gitignore` 确认含 `工作区/`(已有 `.cache/`)
+- [ ] P0.3 ChapterWriter 真实现:`writeChapter(num,title,frontMatter,body)` → `定稿/正文/NNNN-标题.md`,front matter 走 serializeFrontMatter(防呆、保留未知字段)
+- [ ] P0.4 ThreadLedgerWriter 真实现:`updateThread(id,updates)` front matter 改 + `appendHistory(id,entry)` `## 履历` 追加
+- [ ] P0.5 EntityWriter(新):`updateCharacter(name,updates)` 角色卡 front matter + `upsertRosterRow(row)` 名册行
+- [ ] P0.6 TimelineWriter(新):`appendRow(volumeNum,row)` 时间线表格追加
+- [ ] P0.7 SecretWriter(新):`write(id,frontMatter,content)` 信息差
+- [ ] P0.8 SummaryWriter(新):`writeChapterSummary(num,text)` `定稿/摘要/章摘要/NNNN.md`
+- [ ] P0.9 `storage/index.js` 导出新 Writer;`test/storage/adapters/*Writer.test.js` 各正例(写出走防呆、保留未知字段、临时仓库验证)
+
+**验证 P0**:`node --test test/storage/adapters/` 全绿
+**提交 P0**:`feat(v7): M2 P0——Writer 端口真实现(6 端口)+ 文风/工作区 fixture`
+
+## P1 全书近况组装 + 备料
+
+- [ ] P1.1 `src/prep/book-status.js`:`assembleBookStatus(ctx)` 复用 report-overdue-threads/weak-hook-streak/book-stats + list-volumes → `{结构化, markdown}`
+- [ ] P1.2 `src/prep/index.js`:`prepareChapterMaterials(ctx,{chapterNum})` 组装八组件,写 `工作区/本章写作材料.md`
+- [ ] P1.3 读细纲"本章要写到的事"、文风锚点(文风铁律)、反和解段、信息差边界(list-secrets)、近章结尾(read-chapters --recent --tail)
+- [ ] P1.4 `test/prep/`:book-status 断言四指标;prepareChapterMaterials 断言材料文件含八组件锚点 + 精准片段
+
+**验证 P1**:`node --test test/prep/` 全绿
+**提交 P1**:`feat(v7): M2 P1——全书近况组装 + 备料(prepareChapterMaterials)`
+
+## P2 机检 7 项
+
+- [ ] P2.1 `src/mechanical-check/index.js`:`mechanicalCheck(ctx,{chapterNum,draftPath})` → `{ok,pass,issues,candidates}`,checks 注册表(预留统计项扩展点)
+- [ ] P2.2 七项:字数区间 / 禁词 / 禁句式(正则) / 本章内复读(n-gram) / 新专名比名册 / front matter 完整性 / 信息差关键词候选
+- [ ] P2.3 阻断性:1-4、6 阻断;5(新专名)、7(信息差候选)只列不拦
+- [ ] P2.4 `test/mechanical-check/`:每项正例+反例(越界/命中禁词/禁句式/复读超阈/缺字段/新专名进候选/信息差候选)
+
+**验证 P2**:`node --test test/mechanical-check/` 全绿
+**提交 P2**:`feat(v7): M2 P2——机检 7 项可计数(统计项留 M3+ 体检)`
+
+## P3 定稿原子编排 + 出口
+
+- [ ] P3.1 `src/finalize/git.js`:薄封装 `node:child_process` git(add/commit/restore/log/status),错误转中文
+- [ ] P3.2 `src/finalize/index.js`:`finalizeChapter(ctx,{...})` 四步编排(校验→写工作树→git commit→清工作区);commit message `ch(NNN): 标题` + 条目/设定行
+- [ ] P3.3 `test/finalize/`:
+  - 正常:伪造草稿+审稿 → finalize → 定稿/正文 落档、设定/条目/章摘要更新、工作区清空、`git log` 含 `ch(NNN):`
+  - **原子性(AC 出口)**:注入 step2↔step3 抛错 → 无新 commit + 工作区草稿原样 + git 可净恢复
+  - 删 `.cache` 重建一致(不变量 2)
+
+**验证 P3**:`node --test test/finalize/` 全绿(含原子性注入)
+**提交 P3**:`feat(v7): M2 P3——定稿原子 commit + 断电安全(出口达成)`
+
+## P4 CLI wire + AC 复核
+
+- [ ] P4.1 `src/commands/prepare-chapter.js`、`mechanical-check.js`、`finalize-chapter.js`:run 契约薄封装上述 Use Case,bin 可跑
+- [ ] P4.2 `test/commands/` 三命令冒烟
+- [ ] P4.3 全量 `node --test` 绿;过 prd Acceptance(细纲→定稿零 AI 跑通 / 断电注入 / 缓存可重建)
+- [ ] P4.4 推送验证 CI 双平台(含 git 操作在 Windows 跑)
+
+**提交 P4**:`feat(v7): M2 P4——写章流程 CLI 接口 + AC 复核`
+
+## 回滚点
+
+- 各 P 独立,未提交前 `git restore v7/` 对应子目录
+- P3 git 封装单点,定稿逻辑出问题回退 P2 末
+
+## 出口判据(对齐 prd Acceptance)
+
+- [ ] 伪造草稿+细纲,一章 备料→机检→定稿 全程脚本跑通、零 AI
+- [ ] 定稿中断注入后工作区原样保留(要么完成要么原样)
+- [ ] 定稿后删 `.cache` 全量重建一致(不变量 2)
+- [ ] CI 双平台绿(git 操作在 Windows 验证)
+- [ ] 6 Writer 端口 + prep/check/finalize 各有镜像测试

+ 49 - 0
.trellis/tasks/06-27-m2-writing-flow/prd.md

@@ -0,0 +1,49 @@
+# M2 写章流程脚本面(零 AI 全通)
+
+## Goal
+
+实现八阶段写章流程里「执行体 = 脚本」的部分,使一章能**全程脚本、零 AI 调用**地从细纲走到定稿:备料 → 机检 → 原子定稿。为 M4(AI 写稿/两审)和 M3(状态机编排)提供确定性的脚本地基。
+
+> 上游法律文本:story-repo-spec §7(工作区/细纲)、§8(八阶段流程)、§8.1(自动模式,本任务不实现)。架构原则见 v7-implementation-plan §1.5(脚本只做能数的,AI 不碰文件,状态机不判业务)。
+
+## Background(已确认事实,来自 spec §7/§8 + M1 成果)
+
+**八阶段中属于 M2(脚本执行体)的步骤**:1 的脚本部分 / 3 / 5 / 8(第 2/7 步是作者,第 1 拟提案/4 写稿/6 两审是 AI=M4)。
+
+- **§8 步骤表**:① 起草细纲(脚本读全书近况 + AI 拟提案)② 作者确认 ③ **备料(脚本)** ④ 写稿(AI)⑤ **机检(脚本,零 token)** ⑥ 两审(AI×2)⑦ 作者审稿 ⑧ **定稿(脚本,原子)**
+- **工作区**(§7):默认整体 gitignored(定稿前可丢失),但**实现不得假设工作区未被 git 跟踪**。`工作区/细纲.md` 四段固定(全书近况/本章提案/本章要写到的事/备选)。
+- **定稿一次 commit 含**(§8):草稿→`定稿/正文/`(front matter 写章档案 + 条目变动);`设定/` 变更(位置/状态/境界/持有/信息差/名册/时间线追加);三类条目文件更新(front matter + 履历追加);`摘要/章摘要/`;工作区清空。commit message 约定 `ch(152): 标题` + `条目:`/`设定:` 行(ASCII 前缀是机器协议)。
+- **机检可计数项**(§8 第 5 步,9 类):字数、禁词/禁句式、复读检测、跨章高频意象统计、句式体检(句长方差/段落长度分布/高频句式开头)、新专名比对名册、front matter 格式完整性、条目文件是否变动(只查形式不判内容)、信息差关键词命中(**只出候选清单,不拦截**)。不过关直接打回第 4 步。
+
+**M1 已就绪可复用**:41 精准读取接口 + Storage Adapter 读端口;`run(args,options,ctx)` 命令契约;`.cache` 重建器;解析/防呆序列化库。**Writer 端口仍是占位**(ChapterWriter/ThreadLedgerWriter 抛「M2 实现」)。
+
+**现有空壳模块**(M0 占位,待 M2 填真):`v7/src/prep/`、`v7/src/mechanical-check/`、`v7/src/finalize/`。
+
+## Requirements(待 brainstorm 收敛,先列骨架)
+
+- R1 全书近况组装:复用 M1 报表(悬了太久/连续弱钩/全书统计/卷进度)产出结构化近况
+- R2 备料 prepareChapterMaterials:组装 `工作区/本章写作材料.md`(默认精准片段)
+- R3 机检 mechanicalCheck:可计数项检查,产结构化结果(不过关项 + 候选清单),打回判定
+- R4 定稿 finalizeChapter:原子 commit(多文件写入 + 工作区清空),断电安全;含 Writer 端口真实现
+- R5 写出防呆与容错:所有写入走 M1 防呆序列化 + 保留未知字段(不变量 9)
+
+## Acceptance Criteria(来自 §8 M2 出口,待细化)
+
+- [ ] 用手工伪造的草稿与细纲,一章从细纲走到定稿全程脚本可跑、**零 AI 调用**
+- [ ] 定稿中断注入测试(断电模拟)后**工作区原样保留**(要么完成要么原样回退)
+- [ ] 定稿后 `.cache` 删光可全量重建出一致结果(不破坏 M1 不变量 2)
+
+## Out of Scope
+
+- ❌ 第 1 步 AI 拟提案、第 4 步 AI 写稿、第 6 步两审(M4)
+- ❌ 第 2/7 步作者交互编排、状态机单入口(M3)
+- ❌ §8.1 自动模式(连写/批次/叠加视图/污染传播)(M6)
+- ❌ 增量更新缓存(定稿后只写变化行)——M2 先全量重建,增量是 M6 优化
+
+## 决策记录(brainstorm)
+
+- **D1 交付粒度**:单任务分期(同 M1),不拆父子。内部分期:全书近况+备料 → 机检 → 定稿+Writers,每期一 commit。理由:三块是紧依赖链(出口要三者集成跑通一章),M1 已证明单任务分期可控。
+- **D2 机检 MVP 深度**:做 7 个确定性可计数项——字数、禁词/禁句式、本章内复读(简单 n-gram)、新专名比对名册、front matter 格式完整性、条目文件变动(只查形式)、信息差关键词候选。**统计项(跨章高频意象统计、句式体检)推到 M3+ 体检**(与 M1 已 defer 的文体指纹提取重叠,避免重复造轮子);M2 机检框架预留扩展点。
+
+- **D3 定稿原子性**(design §4):git commit 为原子单元;写工作树→git add→commit→**最后**清工作区;commit 前中断则 `git restore` 丢半成品、工作区原样,不存在半章入档。
+- **D4 Writer 端口**(design §3):延续 M1 小端口——Chapter/ThreadLedger 做真 + 新增 Entity/Timeline/Secret/Summary 共 6 端口;原子性在 finalize 编排,不在 Writer 层。

+ 26 - 0
.trellis/tasks/06-27-m2-writing-flow/task.json

@@ -0,0 +1,26 @@
+{
+  "id": "m2-writing-flow",
+  "name": "m2-writing-flow",
+  "title": "M2 写章流程",
+  "description": "",
+  "status": "in_progress",
+  "dev_type": null,
+  "scope": null,
+  "package": null,
+  "priority": "P2",
+  "creator": "codex",
+  "assignee": "codex",
+  "createdAt": "2026-06-27",
+  "completedAt": null,
+  "branch": null,
+  "base_branch": "v7",
+  "worktree_path": null,
+  "commit": null,
+  "pr_url": null,
+  "subtasks": [],
+  "children": [],
+  "parent": null,
+  "relatedFiles": [],
+  "notes": "",
+  "meta": {}
+}

+ 0 - 17
v7/test/storage/adapters/Writer.test.js

@@ -1,17 +0,0 @@
-import { test } from 'node:test'
-import assert from 'node:assert/strict'
-import { ChapterWriter } from '../../../src/storage/adapters/ChapterWriter.js'
-import { ThreadLedgerWriter } from '../../../src/storage/adapters/ThreadLedgerWriter.js'
-
-// Writer 端口在 M1 只定接口占位,调用应抛明确的 M2 提示(不静默成功)
-test('ChapterWriter 方法抛 M2 占位错误', async () => {
-  const w = new ChapterWriter('/x')
-  await assert.rejects(() => w.writeChapter(1, {}, ''), /M2/)
-  await assert.rejects(() => w.updateFrontMatter(1, {}), /M2/)
-})
-
-test('ThreadLedgerWriter 方法抛 M2 占位错误', async () => {
-  const w = new ThreadLedgerWriter('/x')
-  await assert.rejects(() => w.updateThread('伏笔-001', {}), /M2/)
-  await assert.rejects(() => w.appendHistory('伏笔-001', {}), /M2/)
-})