Commit 1117bb656ebff59c985a737fbd19c551285204b2

Authored by yanghl
1 parent c684f5c0

fix: add-req 提交增量产物(P0) + RESUME.md 每模块增量 flush(P1#1)

P0 — add-req 从不 git-commit 自己的产物,导致工作树脏、coding-start 起 coding.mjs
时撞「工作树必须干净」前置(HALT 或被误并进功能分支):
- 步骤 0 基线:写 .req-ledger.json 后 git add+commit
- 步骤 6:把本次全部增量产物(docs/01/02/03/05/08 + sql/migrations/V_n + .req-ledger.json)
  在当前(默认)分支统一 git commit,并用 status --porcelain 复核工作树干净

P1#1 — RESUME.md 原先只在主循环末尾写,硬中断(进程被杀)到不了写入点 → 本次运行零 handoff:
- 每个模块 runMilestone 落定后即 best-effort 追加一条「✅ 模块完成」(含本模块自主决策摘要),
  按 decStart 水位线切出本模块决策;使硬中断也能复盘已完成到哪、各模块做过哪些假设
- loop-end 的 halt / 全完成汇总条目保留(halt 原因是 per-milestone 无法捕获的)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
skills/plan/add-req/SKILL.md
... ... @@ -32,11 +32,13 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan &lt;root&gt;
32 32  
33 33 解析输出 JSON 的 `ledgerExists`:
34 34  
35   -- `false`(项目还没有 `.req-ledger.json`)→ 这是首次启用增量台账。**先建基线**:
  35 +- `false`(项目还没有 `.req-ledger.json`)→ 这是首次启用增量台账。**先建基线并提交**:
36 36 ```
37 37 node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs commit <root>
  38 + git -C <root> add .req-ledger.json
  39 + git -C <root> commit -m "chore(req-ledger): 建立需求台账基线"
38 40 ```
39   - 然后打印并**停下**:
  41 + (`.req-ledger.json` 必须 git 提交——否则它是未提交的脏文件,后续 `coding-start` 起 coding.mjs 时会撞「工作树必须干净」前置。)然后打印并**停下**:
40 42 ```
41 43 [add-req] 已为现有 <N> 个需求单元建立台账基线(.req-ledger.json)。
42 44 首次基线无法区分存量与新增,故本次不做增量生成。
... ... @@ -101,13 +103,23 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan &lt;root&gt;
101 103  
102 104 逐条记录已删的 tag,供步骤 6 横幅汇总。
103 105  
104   -## 步骤 6:提交台账 + 完成横幅
  106 +## 步骤 6:更新台账 + git 提交全部增量产物 + 完成横幅
105 107  
106   -```
107   -node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs commit <root>
108   -```
  108 +1. 把当前哈希写回 `.req-ledger.json`(new/changed 单元自此成为新基线):
  109 + ```
  110 + node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs commit <root>
  111 + ```
  112 +
  113 +2. **git 提交本次全部增量产物**(关键——否则工作树脏,`coding-start` 起 coding.mjs 时会撞 `runBranchSetup`/`runMilestone` 的「工作树必须干净」前置,导致 HALT 或被误并进功能分支)。在**当前分支(默认分支)**提交:
  114 + ```
  115 + git -C <root> add docs/01-需求清单 docs/02-开发计划.md docs/03-数据库设计文档.md docs/05-API接口契约.md docs/08-模块任务管理.md sql/migrations .req-ledger.json
  116 + git -C <root> commit -m "plan(add-req): 增量需求 <新增/变更 id 摘要>(docs/03+05+02+08 delta + V_n + 台账)"
  117 + ```
  118 + - 覆盖范围 = 步骤 2~5 实际改动的全部文件:人工新写的 REQ 卡(docs/01)、新增 migration(sql/migrations/V_n)、同步的 docs/03、补的 docs/05/02 端点与顺序、docs/08 模块行/FE 行与复位的里程碑字段、`.req-ledger.json`。
  119 + - 步骤 5 的 `git tag -d`(删 req-done/milestone)是对 ref 的操作,不产生工作树文件,不需进本 commit;但删 tag 应在本次 commit **之前或之后**都可(与文件提交独立)。
  120 + - commit 后用 `git -C <root> status --porcelain` 复核工作树**干净**(无残留);若仍有未跟踪/未提交项,排查后补提交,确保交给 coding-start 时是干净树。
109 121  
110   -把当前哈希写回 `.req-ledger.json`(new/changed 单元自此成为新基线)。然后打印横幅并**停下**(不自动进编码,与「Plan 完不自动进 B」一致):
  122 +3. 然后打印横幅并**停下**(不自动进编码,与「Plan 完不自动进 B」一致):
111 123  
112 124 ```
113 125 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
... ... @@ -119,7 +131,7 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs commit &lt;root&gt;
119 131 新增 migration:<V_n 文件名 或 无>
120 132 作废 tag:<列出已删的 req-done/* 与 milestone/* 或 无>
121 133  
122   - 台账已更新(.req-ledger.json)。
  134 + 台账已更新并随全部增量产物 git 提交(工作树干净)。
123 135 运行 /erp-workflow:coding-start 增量编码(Router 只跑缺 tag 的模块/功能)。
124 136 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
125 137 ```
... ...
workflows/coding.mjs
... ... @@ -2052,6 +2052,7 @@ log(`coding: ${todo.length}/${routed.modules.length} modules to run`)
2052 2052 const results = []
2053 2053 let haltedAtIdx = -1
2054 2054 for (const [idx, module] of todo.entries()) {
  2055 + const decStart = autonomousDecisions.length // 本模块自主决策水位线(P1#1 增量 flush 用)
2055 2056 try {
2056 2057 phase('Milestone')
2057 2058 await runBranchSetup(module)
... ... @@ -2093,6 +2094,20 @@ for (const [idx, module] of todo.entries()) {
2093 2094 })
2094 2095 await runMilestone(module)
2095 2096 results.push({ module: module.id, status:'done' })
  2097 + // P1#1 增量 flush:每个模块里程碑落定即追加 RESUME.md,使**硬中断**(进程被杀,到不了主循环末尾)
  2098 + // 也能复盘已完成到哪、各模块做过哪些自主假设——不必等 loop-end 才写。best-effort,绝不阻断。
  2099 + {
  2100 + const md = autonomousDecisions.slice(decStart)
  2101 + const digest = md.length
  2102 + ? md.map(d => ` - [\`${d.site}\`] ${d.question || '?'} → ${d.choice || '?'}(${d.confidence || '?'})`).join('\n')
  2103 + : ' - (本模块无自主默认记录)'
  2104 + await recordResume([
  2105 + '## ✅ 模块完成 `' + module.id + '` → milestone/' + module.id + '(<ts>)',
  2106 + '',
  2107 + '- **本模块自主默认决策**(缺值时自动取的解读,可能含错误假设):',
  2108 + digest,
  2109 + ].join('\n'))
  2110 + }
2096 2111 } catch (e) {
2097 2112 results.push({ module: module.id, status:'halted', reason: String(e.message||e) })
2098 2113 haltedAtIdx = idx
... ...