Commit 1117bb656ebff59c985a737fbd19c551285204b2
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>
Showing
2 changed files
with
35 additions
and
8 deletions
skills/plan/add-req/SKILL.md
| @@ -32,11 +32,13 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan <root> | @@ -32,11 +32,13 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan <root> | ||
| 32 | 32 | ||
| 33 | 解析输出 JSON 的 `ledgerExists`: | 33 | 解析输出 JSON 的 `ledgerExists`: |
| 34 | 34 | ||
| 35 | -- `false`(项目还没有 `.req-ledger.json`)→ 这是首次启用增量台账。**先建基线**: | 35 | +- `false`(项目还没有 `.req-ledger.json`)→ 这是首次启用增量台账。**先建基线并提交**: |
| 36 | ``` | 36 | ``` |
| 37 | node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs commit <root> | 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 | [add-req] 已为现有 <N> 个需求单元建立台账基线(.req-ledger.json)。 | 43 | [add-req] 已为现有 <N> 个需求单元建立台账基线(.req-ledger.json)。 |
| 42 | 首次基线无法区分存量与新增,故本次不做增量生成。 | 44 | 首次基线无法区分存量与新增,故本次不做增量生成。 |
| @@ -101,13 +103,23 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan <root> | @@ -101,13 +103,23 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan <root> | ||
| 101 | 103 | ||
| 102 | 逐条记录已删的 tag,供步骤 6 横幅汇总。 | 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 <root> | @@ -119,7 +131,7 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs commit <root> | ||
| 119 | 新增 migration:<V_n 文件名 或 无> | 131 | 新增 migration:<V_n 文件名 或 无> |
| 120 | 作废 tag:<列出已删的 req-done/* 与 milestone/* 或 无> | 132 | 作废 tag:<列出已删的 req-done/* 与 milestone/* 或 无> |
| 121 | 133 | ||
| 122 | - 台账已更新(.req-ledger.json)。 | 134 | + 台账已更新并随全部增量产物 git 提交(工作树干净)。 |
| 123 | 运行 /erp-workflow:coding-start 增量编码(Router 只跑缺 tag 的模块/功能)。 | 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,6 +2052,7 @@ log(`coding: ${todo.length}/${routed.modules.length} modules to run`) | ||
| 2052 | const results = [] | 2052 | const results = [] |
| 2053 | let haltedAtIdx = -1 | 2053 | let haltedAtIdx = -1 |
| 2054 | for (const [idx, module] of todo.entries()) { | 2054 | for (const [idx, module] of todo.entries()) { |
| 2055 | + const decStart = autonomousDecisions.length // 本模块自主决策水位线(P1#1 增量 flush 用) | ||
| 2055 | try { | 2056 | try { |
| 2056 | phase('Milestone') | 2057 | phase('Milestone') |
| 2057 | await runBranchSetup(module) | 2058 | await runBranchSetup(module) |
| @@ -2093,6 +2094,20 @@ for (const [idx, module] of todo.entries()) { | @@ -2093,6 +2094,20 @@ for (const [idx, module] of todo.entries()) { | ||
| 2093 | }) | 2094 | }) |
| 2094 | await runMilestone(module) | 2095 | await runMilestone(module) |
| 2095 | results.push({ module: module.id, status:'done' }) | 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 | } catch (e) { | 2111 | } catch (e) { |
| 2097 | results.push({ module: module.id, status:'halted', reason: String(e.message||e) }) | 2112 | results.push({ module: module.id, status:'halted', reason: String(e.message||e) }) |
| 2098 | haltedAtIdx = idx | 2113 | haltedAtIdx = idx |