Commit 62e69e345314e5529c1735490b8b39874e56292b

Authored by zichun
1 parent 970bdee3

refactor(skills): coding/ + crosscut/ SKILL.md 纯意图化;mr-create bash 抽到 create-mr.sh

强化"skill 只讲目的与约束,具体方法交给 LLM 自决"原则:
- 删冗余的 interrupt-check 预防性调用(除 feature-tdd 3.e 真触发位 + test-gate 失败横幅引导)
- 删 verbatim 子会话 prompt prose(feature-verify / test-gate),保 JSON schema 契约
- 删模板槽位枚举、bash 字面量、fork 解释括号等噪音

架构调整:
- coding-start 精简到守门 + 派发 4 步,模块定位职责完全交给 module-start
- sync 默认分支挪到 module-start 创建新分支前(避免全完成场景的浪费 sync)
- module-start 步骤 1 自包含 MR 状态契约(指向 CLAUDE.md 权威源避免 drift)
- mr-create 4 段 bash 抽到 scripts/create-mr.sh,SKILL 减 41%;
  靠 sed/awk pipe + curl --rawfile 保证模块报告全程不进 LLM 上下文
- 两入口(plan-start / coding-start)共用 flow-overview.txt 模式
skills/coding/feature-brainstorm/SKILL.md
1 1 ---
2 2 name: feature-brainstorm
3   -description: 功能循环第 1 步。针对单个 REQ-XXX-NNN 进行交互式头脑风暴,产出功能规格文件到 docs/superpowers/specs/。
  3 +description: 功能循环第 1 步。针对单个 REQ-XXX-NNN 进行交互式头脑风暴,产出功能规格到 docs/superpowers/specs/。
4 4 user-invocable: false
5 5 allowed-tools: Read Write Skill Bash(mysql *)
6 6 ---
... ... @@ -9,31 +9,17 @@ allowed-tools: Read Write Skill Bash(mysql *)
9 9  
10 10 # feature-brainstorm
11 11  
12   -## 说明
13   -
14   -针对一个 REQ-XXX-NNN,委托本插件的 `superpower-brainstorming`(superpowers:brainstorming 的本地 fork,已剥掉 approval gates)进行头脑风暴,再把输出填入标准规格模板,产出单页功能规格。
  12 +针对单个 REQ,委托 `superpower-brainstorming` 做交互式头脑风暴,把输出按规格模板渲染,产出单页功能规格。
15 13  
16 14 ## 执行步骤
17 15  
18   -1. **中断检查**:调用 `interrupt-check`。如果触发 → 停止。
19   -2. 确定输入:
20   - - 当前 REQ-XXX-NNN(从对话中获取,或 `docs/08` 当前模块下一个未完成的 REQ)。
21   - - REQ 卡片:`docs/01-需求清单/<module>/<req_id>.md`(一 REQ 一文件)。
22   - - 相关数据表(从 `docs/03` 或实时 mysql 命令行查询)。
23   -3. 委托本插件 `superpower-brainstorming`,以 REQ 卡片 + schema 引用作为上下文;把步骤 4 推导出的落盘路径作为 caller-provided path 传入。
24   -4. 推导路径:`docs/superpowers/specs/$(date +%F)-<REQ-id>.md`。如已存在,征求用户确认后覆盖。
25   -5. 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/feature-spec-template.md`,从头脑风暴输出填充槽位:
26   - - `goal`、`input`、`output`、`rules`、`constraints`、`schema_refs`、`api_refs`、`acceptance`
27   -6. 将填充后的规格写入推导路径。
28   -7. **验证**:模板中每个顶级节必须非空;**spec 全文不得包含 `【人工填写:...】` 或 `TBD`**。如出现:先在 `.env.local` / `docs/07-环境配置.md` / `CLAUDE.md` / 现有代码中查找真值并写入(同时注明来源),查不到则用 `AskUserQuestion` 向用户询问;拒绝把"待人工填写"的标记写入 B 阶段 spec(该标记仅供 A 阶段用户审阅文档用)。
29   -8. 输出 `feature-brainstorm: <REQ> → <path>`。
30   -
31   -## 衔接
32   -
33   -立即调用 `Skill(feature-plan)` 进入下一步。
  16 +1. 确定本次 REQ-XXX-NNN(由 module-start 派发时确定),收集上下文:REQ 卡片 `docs/01-需求清单/<module>/<req_id>.md` + 涉及的数据表定义(取自 docs/03 或实时 mysql 查询)。
  17 +2. 委托 `superpower-brainstorming`,把上下文 + 落盘路径 `docs/superpowers/specs/<YYYY-MM-DD>-<REQ-id>.md` 作为 caller-provided path 传入。文件已存在 → 征求用户确认后覆盖。
  18 +3. 按 `${CLAUDE_SKILL_DIR}/templates/feature-spec-template.md` 渲染头脑风暴输出,写入推导路径。
  19 +4. **验证**:所有顶级节非空;**全文不得出现 `【人工填写:...】` 或 `TBD`**——这两类标记仅供 A 阶段文档审阅用,B 阶段 spec 必须写实际值(先在 `.env.local` / `docs/07-环境配置.md` / `CLAUDE.md` / 现有代码查找并注明来源,查不到则用 `AskUserQuestion` 问用户)。
  20 +5. 输出 `feature-brainstorm: <REQ> → <path>`,立即调用 `Skill(feature-plan)`。
34 21  
35 22 ## 参考
36 23  
37 24 - `${CLAUDE_SKILL_DIR}/templates/feature-spec-template.md`
38   -- 委托:`superpower-brainstorming`(本插件 `skills/internal/superpower-brainstorming/`,superpowers:brainstorming 的无门 fork)
39   -- 守门:`interrupt-check`
  25 +- 委托:`superpower-brainstorming`(本插件 `skills/internal/superpower-brainstorming/`)
... ...
skills/coding/feature-plan/SKILL.md
... ... @@ -9,26 +9,20 @@ allowed-tools: Read Write Grep Skill
9 9  
10 10 # feature-plan
11 11  
12   -## 执行步骤
13   -
14   -1. **中断检查**:调用 `interrupt-check`。
15   -2. 确定输入:
16   - - 当前 REQ-XXX-NNN 及其规格文件 `docs/superpowers/specs/YYYY-MM-DD-<REQ>.md`(规格不存在则报错)。
17   - - 相关代码指针(已有的待修改文件,通过 Grep 发现)。
18   - - `docs/04-技术规范.md` 和 `docs/09-项目目录结构.md`(编码规范 + 目录规范)。
19   -3. 委托本插件 `superpower-writing-plans`(superpowers:writing-plans 的本地 fork,已剥掉"Which approach?"执行交接门),以规格 + 代码指针 + 规范作为上下文;把步骤 4 推导出的落盘路径作为 caller-provided path 传入。
20   -4. 推导路径:`docs/superpowers/plans/$(date +%F)-<REQ-id>.md`。
21   -5. 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/feature-plan-template.md`,填充 `files[]`、`tasks[]`、`commits[]`。
22   -6. 强制要求:每个任务有失败测试标识、实现路径和完成标准;**plan 全文不得包含 `【人工填写:...】` 或 `TBD`**——该标记仅限 A 阶段用户审阅文档,B 阶段 plan 必须写具体值(先在 `.env.local` / `docs/07` / `CLAUDE.md` / 现有代码查找并注明来源;查不到就 `AskUserQuestion` 向用户问)。
23   -7. 写入计划文件。
24   -8. 输出 `feature-plan: <REQ> → <path>`。
  12 +把当前 REQ 的功能规格转成任务级实现计划,委托 `superpower-writing-plans` 起草,按计划模板渲染落盘。
25 13  
26   -## 衔接
  14 +## 执行步骤
27 15  
28   -立即调用 `Skill(feature-tdd)` 进入下一步。
  16 +1. 收集输入:
  17 + - 当前 REQ 的规格文件 `docs/superpowers/specs/<YYYY-MM-DD>-<REQ-id>.md`(不存在则报错)
  18 + - 相关代码指针(待修改的现有文件,通过 grep 发现)
  19 + - `docs/04-技术规范.md` 与 `docs/09-项目目录结构.md`(编码规范 + 目录规范)
  20 +2. 委托 `superpower-writing-plans`,把上述上下文 + 落盘路径 `docs/superpowers/plans/<YYYY-MM-DD>-<REQ-id>.md` 作为 caller-provided path 传入。
  21 +3. 按 `${CLAUDE_SKILL_DIR}/templates/feature-plan-template.md` 渲染输出,写入推导路径。
  22 +4. **验证**:每个任务必须含失败测试标识、实现路径与完成标准;**plan 全文不得出现 `【人工填写:...】` 或 `TBD`**——这两类标记仅供 A 阶段文档审阅用,B 阶段 plan 必须写实际值(先在 `.env.local` / `docs/07-环境配置.md` / `CLAUDE.md` / 现有代码查找并注明来源,查不到则用 `AskUserQuestion` 问用户)。
  23 +5. 输出 `feature-plan: <REQ> → <path>`,立即调用 `Skill(feature-tdd)`。
29 24  
30 25 ## 参考
31 26  
32 27 - `${CLAUDE_SKILL_DIR}/templates/feature-plan-template.md`
33   -- 委托:`superpower-writing-plans`(本插件 `skills/internal/superpower-writing-plans/`,superpowers:writing-plans 的无门 fork)
34   -- 守门:`interrupt-check`
  28 +- 委托:`superpower-writing-plans`(本插件 `skills/internal/superpower-writing-plans/`)
... ...
skills/coding/feature-review/SKILL.md
1 1 ---
2 2 name: feature-review
3   -description: 功能循环第 5 步。AI 自审,输出审阅报告到 docs/superpowers/reviews/。approve 回调 module-start;request-changes 则编辑代码并 fix commit,重新执行 verify。自修复循环上限 5 轮。
  3 +description: 功能循环第 5 步。AI 自审 REQ 的 diff,approve 则回调 module-start;request-changes 则自修复 + 重 verify,循环上限 5 轮。
4 4 user-invocable: false
5 5 allowed-tools: Read Write Edit Skill Agent Bash(git add *) Bash(git commit *)
6 6 ---
... ... @@ -9,33 +9,29 @@ allowed-tools: Read Write Edit Skill Agent Bash(git add *) Bash(git commit *)
9 9  
10 10 # feature-review
11 11  
12   -## 执行步骤
  12 +委托 `superpower-code-reviewer` agent 对当前 REQ 引入的代码改动做 AI 自审,渲染审阅报告。`approve` 回模块主循环;`request-changes` 则自修复 must-fix 并重新 verify,最多 5 轮。
13 13  
14   -1. 通过 `Agent(subagent_type=superpower-code-reviewer)` 调用本插件 code-reviewer agent(superpowers:code-reviewer 的本地 fork),以该 REQ 的 diff(`git diff <feature-start>..HEAD`)和规格作为输入。
15   -2. 推导路径:`docs/superpowers/reviews/$(date +%F)-<REQ-id>.md`。
16   -3. 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/feature-review-template.md`,填充 `round`、`verdict`、`must_fix[]`、`nice_to_have[]`、`gaps`。verdict 必须是 `approve` 或 `request-changes`。
17   -4. 写入报告。
  14 +## 执行步骤
18 15  
19   -5. 分发:
20   - - **`verdict = approve`** → 用 `Edit` 在 `docs/08-模块任务管理.md § 二` 本模块 bullet 下找到 ` - [ ] <REQ-id> ...` 行勾选为 ` - [x] <REQ-id> ...`(功能级进度可视化;模块完成仍由 `MR:` + GitLab API state 判定,不依赖本勾选)。然后输出 `feature-review: <REQ> round <N> 通过`,调用 `Skill(module-start)` 回模块主循环(module-start 会自动把本 REQ 识别为 done 并推进下一个 REQ)。
21   - - **`verdict = request-changes`** → 执行"自修复子流程":
22   - - 逐项处理 `must_fix[]`:对每个条目用 `Edit` 修改其指向的代码文件。
23   - - 所有 Must-fix 修复后,拼 commit 消息(格式与 `feature-tdd` 一致,单行):`fix(<module_id>): 修复 review round <N> must-fix <REQ-id>`。
24   - - `Bash`: `git add <修改的代码文件>` + `git commit -m "<上一步拼出的消息>"`。
25   - - 调用 `Skill(feature-verify)` 重新执行验证;verify 通过后会再次链到本 skill,作为 round `<N+1>` 重审。
  16 +1. 派发 `Agent(subagent_type=superpower-code-reviewer)`,把本 REQ 引入的代码 diff 与规格作为输入。
  17 +2. 按 `${CLAUDE_SKILL_DIR}/templates/feature-review-template.md` 渲染审阅报告,写入 `docs/superpowers/reviews/<YYYY-MM-DD>-<REQ-id>.md`。`verdict` 取 `approve` 或 `request-changes`。
  18 +3. 按 `verdict` 分派:
26 19  
27   -6. 上限:**5 轮**。第 5 轮仍为 `request-changes` → 停止并打印摘要(升级给用户手工介入),不再自动修复,不回调 module-start。
  20 + **approve**
  21 + - `Edit docs/08-模块任务管理.md § 二`,把本模块下 `- [ ] <REQ-id> ...` 改为 `- [x] <REQ-id> ...`(仅功能级可视化;模块完成仍以 `MR:` + GitLab API state 为准,不依赖此勾选)
  22 + - 输出 `feature-review: <REQ> round <N> 通过`,调用 `Skill(module-start)`
28 23  
29   -## 衔接
  24 + **request-changes(round < 5)**
  25 + - 逐项编辑 `must_fix[]` 指向的代码文件
  26 + - 按 `feature-tdd/templates/commit-message-template.md` 格式 commit:`fix(<module_id>): 修复 review round <N> must-fix <REQ-id>`
  27 + - 调用 `Skill(feature-verify)` 重新验证;verify 通过后会再次链回本 skill,round `<N+1>` 重审
30 28  
31   -- `approve` → `Skill(module-start)` 回主循环。
32   -- `request-changes`(round < 5)→ `Skill(feature-verify)` 重新执行。
33   -- `request-changes`(round == 5)→ 停止。
  29 + **request-changes(round == 5)**
  30 + - 停止并打印摘要,升级给用户手工介入;不再自动修复,不回调 module-start
34 31  
35 32 ## 参考
36 33  
37 34 - `${CLAUDE_SKILL_DIR}/templates/feature-review-template.md`
38   -- Fix commit 格式与 `feature-tdd` 的 `commit-message-template.md` 对齐(`fix(<scope>): <subject> <req_id>`)
39   -- 委托:`superpower-code-reviewer`(本插件 `agents/superpower-code-reviewer.md`,superpowers:code-reviewer 的本地 fork)
40   -- 上游:`feature-verify`
41   -- 下游:`module-start`(approve)或 `feature-verify`(request-changes)
  35 +- 委托:`superpower-code-reviewer`(本插件 `agents/superpower-code-reviewer.md`)
  36 +- Fix commit 格式与 `feature-tdd/templates/commit-message-template.md` 一致
  37 +- 上游:`feature-verify`;下游:`module-start`(approve)/ `feature-verify`(request-changes)
... ...
skills/coding/feature-tdd/SKILL.md
1 1 ---
2 2 name: feature-tdd
3   -description: 功能循环第 3 步。逐任务执行计划:写失败测试 → 实现代码 → 测试通过 → 提交。所有测试运行均派发到子会话执行
  3 +description: 功能循环第 3 步。按 plan 逐任务做 TDD(失败测试 → 实现 → 通过 → commit),测试运行强制派发到子会话
4 4 user-invocable: false
5 5 allowed-tools: Read Write Edit Agent Skill Bash(git add *) Bash(git commit *)
6 6 ---
... ... @@ -9,39 +9,33 @@ allowed-tools: Read Write Edit Agent Skill Bash(git add *) Bash(git commit *)
9 9  
10 10 # feature-tdd
11 11  
  12 +按 plan 文件逐任务做 TDD:写失败测试 → 写最小实现 → 确认通过 → commit。**所有测试运行强制派发到 Agent 子会话**,主会话只接收 JSON 结果。
  13 +
12 14 ## 执行步骤
13 15  
14   -1. **中断检查**:调用 `interrupt-check`。
15   -2. 加载计划文件 `docs/superpowers/plans/YYYY-MM-DD-<REQ>.md`。
16   -3. **Schema 改动优先(如果计划声明了需要)**:若 plan 标注 "本 REQ 需要 schema 改动",**第一个任务必须是写 migration 文件 + 同步更新 docs/03**:
17   - - `ls sql/migrations/V*.sql` 得最大版本号 n_max,新文件版本号 = n_max + 1
18   - - 文件名格式 `V<n>__<snake_case_desc>.sql`,例 `V5__add_user_email.sql`
19   - - `Write` 该文件(只含 DDL:`ALTER TABLE ... ADD COLUMN ...` / `CREATE TABLE ...` 等)
20   - - **同步把新 CREATE/ALTER 反向更新到 `docs/03-数据库设计文档.md` 对应表小节**(字段表格 / 索引 / 外键 / 业务注记),保持 docs/03 仍是 schema SSoT;新增表则按 `docs-03-table-template.md` 格式追加一节
21   - - 把 migration + docs/03 改动**一起 commit**(避免 SSoT 与 migration 分裂)
22   - - 之后的代码任务(entity / DAO / service / 测试)在此之后做;测试运行时 Spring Boot 启动会由 Flyway 自动 apply 这个新 migration(`scripts/setup-test-db.sh` 只负责清空库)
23   -4. 按顺序处理每个(代码类)任务:
24   - a. 在 `test_file::test_name` 处编写失败测试。
25   - b. **派发子会话**(通过 `Agent`,general-purpose)运行测试并确认失败;子会话只返回 `{command, exit_code, failing_assertion}`。主会话**不直接**运行测试。
26   - c. 在 `impl_file` 处实现最小代码使测试通过。
27   - d. **再次派发子会话**运行测试并确认通过。
28   - e. 持续失败(同一测试 >10 次修复尝试)→ 调用 `interrupt-check`(中断 #1)。
29   - f. 暂存变更并使用 `${CLAUDE_SKILL_DIR}/templates/commit-message-template.md` 提交;`scope` 匹配任务的模块,`subject` ≤50 字符,`req_id` 必填。
30   -5. 所有任务完成后 → 交接给 `feature-verify`。
  16 +1. 加载计划文件 `docs/superpowers/plans/<YYYY-MM-DD>-<REQ-id>.md`。
  17 +2. **Schema 改动前置**(仅当 plan 声明需要):第一个任务必须是写 migration 文件 + 同步更新 docs/03,并一起 commit。
  18 + - 文件命名 `V<n>__<snake_case>.sql`,`<n>` = 现有 `sql/migrations/V*.sql` 最大版本号 + 1;文件只含 DDL
  19 + - **同步**把新 CREATE / ALTER 反向更新到 `docs/03-数据库设计文档.md` 对应表小节,保持 docs/03 是 schema 的 SSoT;新增表按表小节模板追加
  20 + - migration + docs/03 改动**同一 commit**,避免 SSoT 与 migration 分裂
  21 + - 测试运行时 Spring Boot 启动 Flyway 会自动 apply 这个新 migration;`scripts/setup-test-db.sh` 只负责清库
  22 +3. 按顺序处理每个代码类任务:
  23 + a. 在 `test_file::test_name` 处写**失败**测试
  24 + b. 派发 Agent 子会话(general-purpose)运行测试确认失败,子会话只返回 `{command, exit_code, failing_assertion}` JSON
  25 + c. 在 `impl_file` 处写**最小**实现使测试通过
  26 + d. 再次派发子会话确认通过
  27 + e. 同一测试 >10 次修复仍失败 → 调用 `interrupt-check`(中断 #1:测试反复失败)
  28 + f. 按 `${CLAUDE_SKILL_DIR}/templates/commit-message-template.md` 格式 commit(`scope` = 任务模块;`subject` ≤ 50 字符;`req_id` 必填)
  29 +4. 全部任务完成 → 调用 `Skill(feature-verify)`。
31 30  
32 31 ## 护栏
33 32  
34   -- **绝不**在主会话直接运行 `mvn test` / `pnpm test` / `scripts/test.sh`,必须通过子会话。
35   -- 每次提交必须包含 REQ-XXX-NNN 标签。
36   -- 不要将不相关的变更合并到一次提交中。
37   -- **禁止**在主会话直接 `mysql -e "ALTER ..."` 执行业务 DDL;所有业务 schema 变更必须走 `sql/migrations/V_n__<desc>.sql` 文件(只读查询 / 临时调试探索除外)。
38   -
39   -## 衔接
40   -
41   -立即调用 `Skill(feature-verify)` 进入下一步。
  33 +- **绝不**在主会话直接跑 `mvn test` / `pnpm test` / `scripts/test.sh`,必须通过子会话
  34 +- **绝不**在主会话直接 `mysql -e "ALTER ..."`;业务 schema 改动一律走 `sql/migrations/V*.sql` 文件(只读查询 / 临时调试除外)
  35 +- 每次 commit 必须含 `REQ-XXX-NNN` 标签;不混合无关改动到同一 commit
42 36  
43 37 ## 参考
44 38  
45 39 - `${CLAUDE_SKILL_DIR}/templates/commit-message-template.md`
46   -- 原则参考:`superpowers:test-driven-development`(本插件未镜像;仅作为 TDD 原则手册参考,不做运行时 invoke — 本 skill 已把"子会话跑测试 + REQ tag commit"流程直接写死)
47   -- 守门:`interrupt-check`
  40 +- 守门:`interrupt-check`(仅在步骤 3.e 触发,条件 1)
  41 +- 原则参考:`superpowers:test-driven-development`(外部 TDD 原则手册,本 skill 已固化"子会话跑测试 + REQ-tagged commit"流程,不做运行时 invoke)
... ...
skills/coding/feature-verify/SKILL.md
1 1 ---
2 2 name: feature-verify
3   -description: 功能循环第 4 步。将本功能的测试派发到子会话执行,用模板渲染验证证据。无证据不得声称完成。
  3 +description: 功能循环第 4 步。把功能测试派发到子会话跑,按模板渲染证据。无证据不声称完成。
4 4 user-invocable: false
5 5 allowed-tools: Skill Read Agent
6 6 ---
... ... @@ -9,32 +9,33 @@ allowed-tools: Skill Read Agent
9 9  
10 10 # feature-verify
11 11  
12   -## 执行步骤
  12 +把当前 REQ 的功能测试派发到 Agent 子会话执行,按模板把结构化结果渲染成证据。**主会话从不直接跑测试**,也不自由编写证据。
13 13  
14   -1. 从计划文件或项目标准命令中确定功能的测试目标(Maven profile / pnpm script / pytest path)。
15   -2. **派发子会话**(通过 `Agent`,general-purpose),prompt 类似:
  14 +## 执行步骤
16 15  
  16 +1. 从 plan 文件或项目标准命令中确定功能的测试目标(如 Maven profile / pnpm script / pytest path)。
  17 +2. 派发 Agent 子会话(general-purpose)运行该目标,子会话只返回结构化 JSON(不输出描述文字):
  18 + ```json
  19 + {
  20 + "command": "<cmd>",
  21 + "exit_code": <int>,
  22 + "passed": <int>,
  23 + "failed": <int>,
  24 + "failed_list": ["<test>", ...],
  25 + "stdout_excerpt": "<最后 30 行或最相关的失败片段>"
  26 + }
17 27 ```
18   - 任务:运行功能测试目标并报告结果。不要修改任何代码。步骤:
19   - 1. 执行:<command>(例如 mvn -pl user-module test -Dtest=REQ*)
20   - 2. 仅返回结构化 JSON:{"command":"<cmd>","exit_code":<int>,"passed":<int>,"failed":<int>,"failed_list":["<test>", ...],"stdout_excerpt":"<最后 30 行或最相关的失败摘录>"}
21   - 不要输出任何描述性文字。
22   - ```
23   -
24   -3. 解析 JSON;用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/feature-verify-evidence-template.md`,填充槽位(包括 `subagent_id` 和 `conclusion`)。
25   -4. 如果 `exit_code != 0` 或 `failed > 0` → 打印填充后的证据到会话并**停止**,不进入审阅。
26   -5. 通过 → 打印证据,交接给 `feature-review`。
  28 +3. 按 `${CLAUDE_SKILL_DIR}/templates/feature-verify-evidence-template.md` 渲染证据并打印到会话。
  29 +4. **`exit_code != 0` 或 `failed > 0`** → 停止,不进入 review。
  30 +5. 通过 → 调用 `Skill(feature-review)`。
27 31  
28 32 ## 护栏
29 33  
30   -- 不要将原始测试 stdout 粘贴到主会话(超过 30 行的 `stdout_excerpt`)。
31   -- 证据必须从模板渲染,不能自由编写。
32   -
33   -## 衔接
34   -
35   -立即调用 `Skill(feature-review)` 进入下一步。
  34 +- **绝不**在主会话直接跑测试,必须通过子会话
  35 +- **绝不**自由编写证据正文,必须从模板渲染
  36 +- 不要把原始 stdout 全文塞进主会话(`stdout_excerpt` ≤ 30 行)
36 37  
37 38 ## 参考
38 39  
39 40 - `${CLAUDE_SKILL_DIR}/templates/feature-verify-evidence-template.md`
40   -- 原则参考:`superpowers:verification-before-completion`(本插件未镜像;仅作为"证据先于断言"原则参考,不做运行时 invoke — 本 skill 已把子会话派发 + 模板渲染证据流程直接写死)
  41 +- 原则参考:`superpowers:verification-before-completion`(外部"证据先于断言"原则手册,本 skill 已固化子会话派发 + 模板渲染流程,不做运行时 invoke)
... ...
skills/coding/module-report/SKILL.md
1 1 ---
2 2 name: module-report
3   -description: 本地测试闸门通过后,生成标准化 12 节模块完成报告,嵌入本模块新增的 migration 清单和跨模块改动日志
  3 +description: 本地测试闸门通过后,生成标准化 12 节模块完成报告并 commit 到 module 分支供 MR 嵌入
4 4 user-invocable: false
5 5 allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash(git add *) Bash(git commit *)
6 6 ---
... ... @@ -9,46 +9,34 @@ allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash(
9 9  
10 10 # module-report
11 11  
12   -## 执行步骤
13   -
14   -0. **中断检查**:调用 `Skill(interrupt-check)` → 触发则停止(与 `interrupt-check` SKILL 描述"生成模块级制品前"对齐)。
  12 +`test-gate` 绿色后渲染 12 节模块完成报告,commit 到 module 分支供 MR 嵌入。**只读摘要,不读 diff 正文进上下文**。
15 13  
16   -1. 验证上游:`test-gate` 返回了绿色。否则停止。
17   -2. 收集输入(优先 shell 摘要,避免把 diff 正文读进上下文):
18   - - **文件变更 § ③** — 只用摘要,**不**读 diff 正文:
19   - - `git diff --stat <module-start-commit>..HEAD` → 每文件增减行数
20   - - `git diff --name-status <module-start-commit>..HEAD` → A/M/D 状态
21   - - `git log --oneline <module-start-commit>..HEAD` → commit 列表
22   - - `docs/superpowers/specs|plans|reviews/<date>-<本模块的 REQ>.md` → § ②、§ ⑨(正常 Read,一般不大)
23   - - **§ ⑥ 本模块新增 migration**:用 `git diff --name-only --diff-filter=A <module-start-commit>..HEAD -- 'sql/migrations/V*.sql'` 列出本模块提交的新 migration 文件;每个文件 Read 第一行(V_n 描述)作为说明
24   - - `docs/superpowers/module-reports/<module_id>-cross-module.md` → § ⑦
25   - - `docs/superpowers/module-reports/<module_id>-test-gate.md` → § ⑤
26   - - § ④(读写的表):**用 `grep -rlE "(SELECT|INSERT|UPDATE|DELETE).*FROM|INTO"` 定位涉及 SQL 的文件,再按需读取片段**。不要全量读取 docs/03。
27   -3. 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/module-report-template.md`,填充全部 12 节。
28   -4. **硬性验证 + 批量补齐跨模块 TBD**:
29   - - § ⑦:这是整模块周期里**唯一补齐 `TBD(CC 补)` 的时机**(编辑中途 CC 不应主动调 `cross-module-log`)。如果 cross-module 有任何行含 `TBD(CC 补)` → 调用 `Skill(cross-module-log)` 一次性批量补齐所有 TBD,补完再回本步骤重验。
30   - - § ⑦:如果非空但某行缺少影响评估(被填成空/敷衍)→ 同样调 `cross-module-log` 重补。
31   - - § ⑧ 必须列举所有偏离规格之处;如果没有,明确写"无偏离"。
32   -5. 写入 `docs/superpowers/module-reports/$(date +%F)-<module_id>.md`。
33   -
34   -5b. **commit 模块报告 + cross-module 日志到 module 分支**(确保审计证据随 MR 合并进默认分支;mr-create 的 worktree clean 前置条件依赖此步):
  14 +## 执行步骤
35 15  
  16 +1. 验证上游 `test-gate` 已绿;红色则停。
  17 +2. 收集输入(核心约束:取 git 摘要而非 diff 正文):
  18 + - § ③ 文件变更:用 `git diff --stat` / `--name-status` / `git log --oneline` 摘要(区间:module 分支起点 → HEAD)
  19 + - § ② / § ⑨:直接 Read `docs/superpowers/{specs,plans,reviews}/<日期>-<本模块的 REQ>.md`(小文件可全读)
  20 + - § ⑤:Read `docs/superpowers/module-reports/<module_id>-test-gate.md`
  21 + - § ⑥ Migration:`git diff --name-only --diff-filter=A -- 'sql/migrations/V*.sql'` 列新增 migration,每个 Read 第一行作说明
  22 + - § ⑦ 跨模块改动:Read `docs/superpowers/module-reports/<module_id>-cross-module.md`(如存在)
  23 + - § ④ 读写的表:用 grep 定位涉 SQL 的文件后按需读片段,**不全量读 docs/03**
  24 +3. 按 `${CLAUDE_SKILL_DIR}/templates/module-report-template.md` 渲染 12 节。
  25 +4. **硬验证**:
  26 + - § ⑦:跨模块日志中任何 `TBD(CC 补)` 或敷衍填充 → 调用 `Skill(cross-module-log)` 一次性批量补齐,补完回本步骤重验(**整模块周期内唯一补 TBD 的时机**)
  27 + - § ⑧:必须列举所有偏离规格之处;若无,写"无偏离"
  28 +5. 写入 `docs/superpowers/module-reports/<YYYY-MM-DD>-<module_id>.md`,连同跨模块日志(如存在)一起 commit 到 module 分支:
36 29 ```bash
37   - git add docs/superpowers/module-reports/$(date +%F)-<module_id>.md
38   - # cross-module log 若存在且有改动(cross-module-log 补齐过 TBD)也一并提交
39   - [ -f "docs/superpowers/module-reports/<module_id>-cross-module.md" ] && \
  30 + git add docs/superpowers/module-reports/<YYYY-MM-DD>-<module_id>.md
  31 + [ -f docs/superpowers/module-reports/<module_id>-cross-module.md ] && \
40 32 git add docs/superpowers/module-reports/<module_id>-cross-module.md
41 33 git commit -m "docs(<module_id>): add module completion report + cross-module log"
42 34 ```
43   -
44   -6. 交接给 `mr-create`。
45   -
46   -## 衔接
47   -
48   -立即调用 `Skill(mr-create)` 推送并创建 MR。
  35 + commit 是必需的——`mr-create` 的 worktree-clean 前置条件依赖此步。
  36 +6. 调用 `Skill(mr-create)` 推送并创建 MR。
49 37  
50 38 ## 参考
51 39  
52 40 - `${CLAUDE_SKILL_DIR}/templates/module-report-template.md`(12 节)
53   -- 上游:`test-gate`
  41 +- 上游:`test-gate`(绿色时派发)
54 42 - 下游:`mr-create`
... ...
skills/coding/module-report/templates/module-report-template.md
... ... @@ -41,7 +41,8 @@ git_range: {{git_range}}
41 41 - `sql/migrations/{{filename}}` — {{desc}}
42 42 {{/each}}
43 43  
44   -(若本模块无 schema 改动,写 "—")
  44 +<!-- 若本模块无 schema 改动,整节内容写 "—" -->
  45 +
45 46  
46 47 ## ⑦ 跨模块改动清单(软规则 S2)
47 48  
... ...
skills/coding/module-start/SKILL.md
1 1 ---
2 2 name: module-start
3   -description: 启动/恢复模块循环。按 docs/02 § 二 REQ 清单定位当前模块及其 REQ 序列,确保处于模块分支,扫描 docs/superpowers/reviews/ 计算已完成 REQ,驱动第一个未完成 REQ 的功能循环;全部完成则调用 test-gate。幂等可重入。
  3 +description: 模块循环入口。定位当前模块与未完成 REQ,派发到 feature-brainstorm(每个 REQ 一次)或 test-gate(本模块全部完成)。幂等可重入。
4 4 user-invocable: false
5   -allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *) Bash(git rev-parse *) Bash(curl *) Bash(jq *) Bash(mkdir -p .tmp) Bash(rm -f .tmp/*)
  5 +allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *) Bash(git rev-parse *) Bash(git pull *) Bash(git status *) Bash(git symbolic-ref *) Bash(curl *) Bash(jq *)
6 6 ---
7 7  
8 8 **所有输出必须使用中文。**
... ... @@ -11,67 +11,48 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *
11 11  
12 12 ## 执行步骤
13 13  
14   -### 步骤 1:按 `docs/02 § 二` REQ 序 + MR state 定位当前模块 + 本模块 REQ 列表
15   -
16   -> `MR:` 字段 × GitLab API state 的三组合判定规则见 `CLAUDE.md § ✅ 模块完成判定规则 § 模块状态语义`。
17   -
18   -与 `coding-start` 步骤 3 同构(完成判定以 `MR:` 字段 + GitLab API `state` 为准;curl 调用,凭据读 `.env.local` 的 `GITLAB_API_URL` / `GITLAB_TOKEN` / `GITLAB_PROJECT_ID`):
19   -
20   -- 用 `Read` 读取 `docs/02-开发计划.md`,用 `Grep`(pattern `^\|\s*[0-9]+\s*\|\s*\*\*(REQ-[A-Z0-9]+-[0-9]+)\*\*\s*\|\s*(module_\w+)`)抽取 § 二 表格数据行,按行号升序得 `req_order[]`。
21   -- 若 `req_order` 为空 → 打印"⚠️ docs/02 § 二 REQ 开发顺序清单为空或无法解析,请检查"并停止。
22   -- 初始化 `module_merged[module_id → bool]` 空缓存。按序遍历 `req_order[]`:
23   - - `module_merged[module_id]` 已缓存为 `true` → 跳过本 REQ。
24   - - `module_merged[module_id]` 已缓存为 `false` → `current_module = module_id`,结束遍历。
25   - - 未缓存 → 读取 docs/08 § 二 该模块条目的 ` - MR:` 字段:
26   - - `MR: —` → `module_merged[module_id] = false`,`current_module = module_id`,结束遍历。
27   - - `MR: !<iid>` → 先 `Bash`: `set -a; . ./.env.local; set +a`,然后**分步校验 HTTP + 返回条数 + state 枚举**(语义与 `coding-start` 步骤 3 严格一致):
28   - ```bash
29   - mkdir -p .tmp
30   - HTTP_CODE=$(curl -sS -o .tmp/mr.json -w '%{http_code}' \
31   - --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
32   - "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests?iid=<iid>")
33   - ```
34   - 硬停条件(任一触发 → 打印与 `coding-start` 同款诊断横幅后**停下**,不进入下游 skill):
35   - 1. `HTTP_CODE != 200`
36   - 2. `HTTP_CODE == 200` 但 `jq 'length' .tmp/mr.json != 1`
37   - 3. state 不在 `{merged, opened, closed}` 里
38   -
39   - 通过后按 state 分派:
40   - - `merged` → 缓存 `true`,跳过本 REQ
41   - - `opened` / `closed` → 缓存 `false`,`current_module = module_id`,结束遍历
42   -- **抽取本模块 REQ 序列 `req_list[]`**:从 `req_order[]` 取出所有 `module_id == current_module` 的项,按原序组成(同模块 REQ 必须连续,见 A5 约束)。
43   -- 用 `Read` 读取 docs/08 § 二 该模块行 + 后续缩进行,提取 `module_name` / `depends_on`(REQ 列表以 docs/02 为准,不再读取 docs/08)。
44   -
45   -### 步骤 2:所有模块已完成短路
46   -
47   -如果 `req_order[]` 全部遍历完 `current_module` 仍未赋值(即所有模块都 merged)→ 打印"所有模块已完成"摘要并停止。
  14 +### 步骤 1:定位当前模块与本模块 REQ 列表
  15 +
  16 +按 `docs/02 § 二 开发顺序清单` 的 REQ 顺序扫描,找到第一个所属模块尚未 merged 的模块作为 `current_module`,并抽取本模块 REQ 序列。
  17 +
  18 +模块状态判定(`MR:` 字段 × GitLab API state 三种组合的语义和应对动作)参见 `CLAUDE.md § ✅ 模块完成判定规则 § 模块状态语义`。
  19 +
  20 +找到 `current_module` 后,从 docs/02 § 二 的 REQ 列表里取出所有 `module_id == current_module` 的项,按原序得 `req_list[]`(A5 约束保证同模块 REQ 连续)。模块名、需求卡目录等其它字段由后续步骤按需从 `docs/08 § 二` 或 `docs/01-需求清单/` 取,不在本步骤预读。
  21 +
  22 +约束:
  23 +
  24 +- GitLab 凭据从 `.env.local` 读取(`GITLAB_API_URL` / `GITLAB_TOKEN` / `GITLAB_PROJECT_ID`)
  25 +- API 异常(HTTP 非 2xx / 找不到 MR / state 非合法值)一律硬停,**禁止静默假设未 merged**,向用户打印诊断信息,引导核查上述凭据与 docs/08 的 iid
  26 +- 任何文件读取或解析失败 → 打印错误并停止
  27 +
  28 +### 步骤 2:所有模块都完成时结束
  29 +
  30 +如果步骤 1 没找到任何未 merged 的模块(即整个项目已做完),打印"所有模块已完成"提示用户,结束流程,不再进入后续步骤。
48 31  
49 32 ### 步骤 3:确保处于模块分支
50 33  
51   -- `target_branch = module-<module_id>`(例 `module-module_sys`)。
52   -- 用 `Bash` 执行 `git branch --show-current` 得 `current_branch`。
53   -- `current_branch == target_branch` → 继续步骤 4。
54   -- 否则用 `Bash` 执行 `git rev-parse --verify <target_branch> 2>/dev/null`:
55   - - 存在 → `git checkout <target_branch>`
56   - - 不存在 → `git checkout -b <target_branch>`
57   -- 若当前工作区有未提交改动且 checkout 失败 → 打印错误并停止(请用户手工处理 dirty state)。
  34 +确保工作树位于 `target_branch = module-<module_id>`(例 `module-module_sys`)。
  35 +
  36 +- 已在该分支 → 继续步骤 4
  37 +- 该分支已存在但当前不在 → checkout 过去
  38 +- 该分支不存在 → 先把工作树切到远程默认分支(main 或 master)并 fast-forward 同步,作为新分支的干净 base,再 `git checkout -b` 创建模块分支
  39 +
  40 +任何错误(定位不到默认分支 / 切换前工作树脏 / 不能 fast-forward / checkout 失败)一律停下并打印诊断信息,不自动 stash、不强制覆盖。
  41 +
  42 +### 步骤 4:计算已完成 REQ 集合 `done_reqs[]`
58 43  
59   -### 步骤 4:计算已完成 REQ 集合 `done_reqs[]`(幂等断点恢复关键)
  44 +对 `req_list[]` 中每个 REQ,检查 `docs/superpowers/reviews/` 下是否存在该 REQ 的 review 文件、且其 `verdict` 字段为 `approve`。两条件都满足 → 收入 `done_reqs[]`,步骤 6 推进时跳过这些 REQ。
60 45  
61   -- 对 `req_list[]` 每个 `req_id`,用 `Glob` 查 `docs/superpowers/reviews/*-<req_id>.md`。
62   -- 命中后用 `Grep`(pattern `^verdict:\s*approve`,`-i` 不敏感)检查首部 verdict。
63   -- 两者都命中 → 加入 `done_reqs[]`。
  46 +每次进入本 skill 都重新计算(不缓存),保证中断/重跑后能从最新进度继续。
64 47  
65 48 ### 步骤 5:渲染并打印模块横幅
66 49  
67   -`Read ${CLAUDE_SKILL_DIR}/templates/module-start-banner-template.md`,填充槽位;`reqs[]` 每项的 `status` 字段根据 `done_reqs[]` 填 `x`(已完成)或空格(未完成)
  50 +按 `${CLAUDE_SKILL_DIR}/templates/module-start-banner-template.md` 渲染输出
68 51  
69   -### 步骤 6:推进主循环
  52 +### 步骤 6:派发
70 53  
71   -- 从 `req_list[]` 取第一个不在 `done_reqs[]` 中的 REQ 作为 `next_req`。
72   -- **没有 `next_req`**(全部完成)→ 调用 `Skill(test-gate)` 进入模块闸门。
73   -- **有 `next_req`** → 调用 `Skill(feature-brainstorm)` 启动该 REQ 的功能循环。功能循环链(brainstorm → plan → tdd → verify → review)完成后,`feature-review` 在 `verdict=approve` 分支会回调 `Skill(module-start)` —— 再次进入本 skill 时,步骤 4 会把刚通过的 REQ 加入 `done_reqs[]`,步骤 6 自动取下一 REQ,形成可重入推进。
74   -- 任何停止条件触发(中断触发 / 测试持续失败 / review 5 轮仍 request-changes)→ 停止本模块,不要静默跳下一 REQ。
  54 +- 还有未完成 REQ → 调用 `Skill(feature-brainstorm)` 启动该 REQ 的功能循环
  55 +- 本模块 REQ 全部完成 → 调用 `Skill(test-gate)` 进入模块测试闸门
75 56  
76 57 ## 参考
77 58  
... ... @@ -79,5 +60,4 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *
79 60 - `docs/08-模块任务管理.md § 二`(模块元数据,含 `MR:` 字段;完成判定以 MR state 为准)
80 61 - `docs/superpowers/reviews/*.md`(REQ 级进度事实——verdict=approve 即完成)
81 62 - `${CLAUDE_SKILL_DIR}/templates/module-start-banner-template.md`
82   -- 下游:`feature-*`、`test-gate`
83   -- 注:跨模块日志文件的创建由 `hooks/scripts/log-cross-module.sh` 在首次跨模块改动时按需完成,本 skill 不再做防御性初始化。
  63 +- 下游:`feature-brainstorm`(每个 REQ)/ `test-gate`(本模块完成)
... ...
skills/coding/module-start/templates/module-start-banner-template.md
1   -## Module start — {{module_id}} ({{module_name}})
  1 +## 当前模块:{{module_id}}({{module_name}})
2 2  
3   -- 模块依赖: {{depends_on}}
4   -- 对应需求文件: docs/01-需求清单/{{req_file}}
5   -- 分支: module-{{module_id}}
6   -- 功能清单(`x` = 已完成 review approve):
  3 +- 分支:module-{{module_id}}
  4 +- 需求卡片目录:docs/01-需求清单/{{req_dir}}/
  5 +- 功能清单(`x` = 已完成 review approve):
7 6 {{#each reqs}}
8 7 - [{{status}}] {{req_id}} — {{title}}
9 8 {{/each}}
10   -
11   -开始/恢复功能循环(Layer 3),本次处理清单中第一个未完成 REQ。触发中断 → 停;所有 REQ 完成 → 进入模块闸门。
... ...
skills/coding/mr-create/SKILL.md
1 1 ---
2 2 name: mr-create
3   -description: 模块报告完成后,验证当前分支为 module-<id> 且 worktree 干净,push 推代码和所有 evidence,创建 GitLab MR(报告嵌入描述),把 MR URL 追加到模块报告 § ⑫ 并 commit,把 MR iid 回写到 docs/08 该模块 `MR:` 字段并 commit,再次 push 同步。完成信号由 MR merged state 判定。停下等待人工审核
  3 +description: 模块报告完成后,把 module 分支推到远程并创建 GitLab MR,把 MR iid 回写 docs/08 + URL 回写报告 § ⑫,停下等人工 Approve + Merge
4 4 user-invocable: false
5   -allowed-tools: Read Write Edit Skill Bash(git *) Bash(curl *) Bash(jq *) Bash(sed *) Bash(awk *) Bash(cat *) Bash(echo *) Bash(mkdir -p .tmp) Bash(mv .tmp/*) Bash(rm -f .tmp/*)
  5 +allowed-tools: Read Edit Bash(git *) Bash(bash *)
6 6 ---
7 7  
8 8 **所有输出必须使用中文。**
... ... @@ -11,173 +11,82 @@ allowed-tools: Read Write Edit Skill Bash(git *) Bash(curl *) Bash(jq *) Bash(se
11 11  
12 12 ## 前置条件
13 13  
14   -- `module-report` 已生成报告文件并 commit 到 module 分支。
15   -- `test-gate` 返回了绿色,test-gate.md 已 commit 到 module 分支。
16   -- 当前分支 = `module-<module_id>`(由 `module-start` 步骤 3 负责切入)。
  14 +- `module-report` 已生成报告并 commit 到 module 分支
  15 +- `test-gate` 绿色,test-gate.md 已 commit 到 module 分支
  16 +- 当前分支 = `module-<module_id>`(由 `module-start` 步骤 3 切入)
17 17  
18 18 ## 执行步骤
19 19  
20   -### 步骤 0:中断检查
21   -
22   -调用 `Skill(interrupt-check)` → 触发则停止。
23   -
24 20 ### 步骤 1:验证当前分支
25 21  
26   -- `Bash`: `git branch --show-current` → `current_branch`。
27   -- `current_branch` 必须匹配 `module-*`;否则打印错误并**停止**(不自动创建分支——分支职责在 `module-start` 步骤 3)。
28   -- 从 `current_branch` 取 `module_id = current_branch` 去掉 `"module-"` 前缀。
29   -
30   -### 步骤 2:验证 worktree 干净(防止 evidence 文件漏 commit)
  22 +`git branch --show-current` 必须匹配 `module-*`,否则停下报错(不自动建分支——分支职责在 `module-start` 步骤 3)。从分支名取 `module_id` = 去掉 `module-` 前缀。
31 23  
32   -- `Bash`: `git status --porcelain`
33   -- 输出非空 → 打印 dirty 文件清单并**停止**:
34   - ```
35   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
36   - [mr-create] ⚠️ worktree 不干净,无法 push
  24 +### 步骤 2:验证 worktree 干净
37 25  
38   - 以下文件有未提交改动:
39   - <git status 输出>
  26 +`git status --porcelain` 输出非空 → 停下打印 dirty 文件清单:
40 27  
41   - push 前所有 evidence 必须已 commit 到 module 分支。检查点:
42   - - test-gate 步骤 3b 是否已 commit test-gate.md?
43   - - module-report 步骤 5b 是否已 commit 模块报告 + cross-module log?
44   - - 本 skill 前没人跑过额外的 Edit/Write?
45   -
46   - 修复方式:`git add <files> && git commit -m "..."`,然后重新运行 /erp-workflow:coding-start。
47   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
48   - ```
  28 +```
  29 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  30 + [mr-create] ⚠️ worktree 不干净,无法 push
49 31  
50   -### 步骤 3:push 推送全部已 commit 内容
  32 + <git status 输出>
51 33  
52   -`git push -u origin <current_branch>` — **不要**使用 `--no-verify`(hook `deny-no-verify.sh` 会拦截)。
  34 + push 前所有 evidence 必须已 commit。检查点:
  35 + - test-gate 步骤 3 是否已 commit test-gate.md?
  36 + - module-report 步骤 5 是否已 commit 报告 + cross-module log?
53 37  
54   -此 push 包含:代码 commit(feature-tdd 产出)+ 模块 review fix commit(feature-review 产出)+ test-gate evidence commit(test-gate 产出)+ 模块完成报告 commit(module-report 产出)。
  38 + 修复:git add <files> && git commit -m "...",然后重跑 /erp-workflow:coding-start。
  39 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  40 +```
55 41  
56   -### 步骤 4:读取 MR 标题模板
  42 +### 步骤 3:初次 push
57 43  
58   -用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/mr-title-template.md`,填充 `module_id`、`module_name`,得到 MR 标题字符串(一行,较短,进上下文 OK)
  44 +`git push -u origin <current_branch>`——**禁用 `--no-verify`**
59 45  
60   -### 步骤 5:生成 MR 描述文件(纯 shell,不读模块报告内容进上下文)
  46 +### 步骤 4:调脚本创建(或复用)MR
61 47  
62 48 ```bash
63   -mkdir -p .tmp
64   -DESC_FILE=.tmp/mr-desc.md
65   -REPORT="docs/superpowers/module-reports/<date>-<module_id>.md"
66   -
67   -# 先用 sed 替换 description 模板的简单槽位
68   -sed -e "s|{{test_gate_conclusion}}|<值>|g" \
69   - -e "s|{{test_subagent_id}}|<值>|g" \
70   - -e "s|{{module_id}}|<值>|g" \
71   - -e "s|{{date}}|<值>|g" \
72   - "${CLAUDE_SKILL_DIR}/templates/mr-description-template.md" > "$DESC_FILE"
73   -
74   -# 把模块报告完整内容直接管道注入,替换 {{module_report_contents}} 所在行
75   -awk -v report="$REPORT" '
76   - /\{\{module_report_contents\}\}/ { while ((getline line < report) > 0) print line; close(report); next }
77   - { print }
78   -' "$DESC_FILE" > .tmp/mr-desc.final
79   -mv .tmp/mr-desc.final "$DESC_FILE"
  49 +bash "${CLAUDE_SKILL_DIR}/scripts/create-mr.sh" <module_id> <current_branch> <YYYY-MM-DD>
80 50 ```
81 51  
82   -关键:**模块报告内容只经 awk 管道流过**,从不进入 LLM 上下文
  52 +脚本内部完成:加载 `.env.local` → 探测目标分支 → 从 docs/08 取 `module_name` 与 test-gate.md 取结论 → 渲染 description → 查已有 opened MR → 否则创建新 MR
83 53  
84   -### 步骤 5.3:加载 GitLab 凭据并探测目标分支
  54 +输出(stdout):单行 `<MR_IID> <MR_URL>`,由本步骤捕获供后续步骤使用。失败时脚本写诊断到 stderr 并 exit 1,本 skill 停下。
85 55  
86   -```bash
87   -# 加载 .env.local 中的 GITLAB_API_URL / GITLAB_TOKEN / GITLAB_PROJECT_ID
88   -set -a; . ./.env.local; set +a
89   -for v in GITLAB_API_URL GITLAB_TOKEN GITLAB_PROJECT_ID; do
90   - eval "val=\${$v:-}"; [ -n "$val" ] || { echo "[mr-create] ⚠️ .env.local 缺少 $v"; exit 1; }
91   -done
92   -
93   -# 探测默认分支作为 target_branch(与 coding-start 同策略)
94   -TARGET_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
95   -[ -n "$TARGET_BRANCH" ] || TARGET_BRANCH=$(git branch -r --format='%(refname:short)' | grep -E '^origin/(main|master)$' | head -1 | sed 's|^origin/||')
96   -[ -n "$TARGET_BRANCH" ] || { echo "[mr-create] ⚠️ 无法探测默认分支(origin/main 或 origin/master)"; exit 1; }
97   -```
  56 +### 步骤 5:回写 docs/08 MR 字段并 commit
98 57  
99   -### 步骤 5.5:幂等守门——检查 source branch 是否已有 opened MR
  58 +**先于步骤 6 执行**——若步骤 6 失败,重跑时步骤 4 脚本能识别已有 MR + docs/08 已含 IID,状态一致。
100 59  
101   -防止部分失败后重试创建重复 MR;查询失败不吞,硬停避免误创第二个 MR:
  60 +`Edit docs/08-模块任务管理.md`:把当前模块的 ` - MR: —` 改为 ` - MR: !<MR_IID>`。
102 61  
103 62 ```bash
104   -mkdir -p .tmp
105   -HTTP_CODE=$(curl -sS -o .tmp/existing.json -w '%{http_code}' \
106   - --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
107   - "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests?source_branch=${current_branch}&state=opened")
108   -if [ "$HTTP_CODE" != "200" ]; then
109   - echo "[mr-create] ⚠️ 查询已有 opened MR 失败 (HTTP $HTTP_CODE)" >&2
110   - jq -r '.message // .error // .' .tmp/existing.json | head -c 200 >&2; echo >&2
111   - echo " 请核对 .env.local 的 GITLAB_API_URL / GITLAB_TOKEN / GITLAB_PROJECT_ID 后重跑" >&2
112   - rm -f .tmp/existing.json
113   - exit 1
114   -fi
115   -EXISTING_IID=$(jq -r '.[0].iid // empty' .tmp/existing.json)
116   -EXISTING_URL=$(jq -r '.[0].web_url // empty' .tmp/existing.json)
117   -rm -f .tmp/existing.json
  63 +git add docs/08-模块任务管理.md
  64 +git commit -m "chore(<module_id>): record MR !<MR_IID> in docs/08"
118 65 ```
119 66  
120   -- `EXISTING_IID` 非空 → 打印 `[mr-create] 检测到已有 opened MR: !${EXISTING_IID}`,**跳过步骤 6**,直接用 `EXISTING_IID` / `EXISTING_URL` 进入步骤 7。
121   -- `EXISTING_IID` 为空 → 正常走步骤 6 创建新 MR。
  67 +### 步骤 6:追加 MR URL 到模块报告 § ⑫ 并 commit
122 68  
123   -### 步骤 6:创建 MR(仅当 5.5 未命中时)
  69 +`Edit docs/superpowers/module-reports/<date>-<module_id>.md` 的 § ⑫,把 `{{mr_url}}` 替换为 `<MR_URL>`(已替换则追加一行)。
124 70  
125 71 ```bash
126   -TITLE="<步骤 4 得到的标题>"
127   -
128   -CREATE_RESP=$(curl -sS -X POST \
129   - --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
130   - --header "Content-Type: application/json" \
131   - --data "$(jq -n \
132   - --arg src "$current_branch" \
133   - --arg tgt "$TARGET_BRANCH" \
134   - --arg title "$TITLE" \
135   - --rawfile desc "$DESC_FILE" \
136   - '{source_branch: $src, target_branch: $tgt, title: $title, description: $desc, remove_source_branch: false}')" \
137   - "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests")
138   -
139   -MR_IID=$(echo "$CREATE_RESP" | jq -r '.iid // empty')
140   -MR_URL=$(echo "$CREATE_RESP" | jq -r '.web_url // empty')
141   -[ -n "$MR_IID" ] || { echo "[mr-create] ⚠️ MR 创建失败,API 响应:"; echo "$CREATE_RESP" | jq . >&2; exit 1; }
142   -rm -f "$DESC_FILE"
  72 +git add docs/superpowers/module-reports/<date>-<module_id>.md
  73 +git commit -m "docs(<module_id>): record MR !<MR_IID> link in module report"
143 74 ```
144 75  
145   -对应 5.5 命中时复用 `EXISTING_IID` / `EXISTING_URL` 作为 `MR_IID` / `MR_URL`。
146   -
147   -### 步骤 7:回写 docs/08 的 MR 字段并 commit(durable state 先持久化)
148   -
149   -> 先写 docs/08 再追模块报告——这样如果步骤 8 失败,重跑时 5.5 能直接识别已有 MR 且 docs/08 已含 IID,避免状态不一致。
150   -
151   -- `Edit docs/08-模块任务管理.md`:把当前模块条目的 ` - MR: —` 改为 ` - MR: !<MR_IID>`(只改一行)。docs/08 § 二 中 `MR:` 是唯一动态字段。
152   -- `Bash`: `git add docs/08-模块任务管理.md && git commit -m "chore(<module_id>): record MR !<MR_IID> in docs/08"`。
153   -
154   -### 步骤 8:追加 MR URL 到模块报告 § ⑫ 并 commit
155   -
156   -- `Edit docs/superpowers/module-reports/<date>-<module_id>.md` 的 § ⑫:把 `{{mr_url}}` 占位替换为 `<MR_URL>`(若已替换过,追加一行)。
157   -- `Bash`: `git add docs/superpowers/module-reports/<date>-<module_id>.md && git commit -m "docs(<module_id>): record MR !<MR_IID> link in module report"`。
158   -
159   -### 步骤 9:再次 push
160   -
161   -步骤 3 的 push 之后,步骤 7、8 又产生了两个新 commit(docs/08 MR iid + 模块报告 MR link)。必须再次 push 让 MR 自动更新 commit 列表 + diff:
162   -
163   -`Bash`: `git push origin <current_branch>`
164   -
165   -### 步骤 10:向会话打印 MR URL
  76 +### 步骤 7:再次 push 同步新 commits
166 77  
167   -### 步骤 11:停止 — 等待人工 Approve + Merge
  78 +步骤 5、6 产生了两个新 commit,必须再 push 让 MR 自动更新 commit 列表 + diff:
168 79  
169   -用户合并后再次运行 `/erp-workflow:coding-start`,入口会自动检测 MR merged → 探测默认分支(`main` 或 `master`)→ `git checkout <默认分支>` + `git pull --ff-only origin <默认分支>` 同步远程 → 派发下一模块。
  80 +`git push origin <current_branch>`
170 81  
171   -## 设计要点
  82 +### 步骤 8:打印 MR URL,停下等 Approve + Merge
172 83  
173   -- **默认分支(main 或 master)是 protected branch**,只能通过 MR 修改。MR diff 覆盖代码、模块报告、test-gate evidence、cross-module log,以及 docs/08 的 `MR: !<iid>` 字段。
174   -- **完成信号以 MR state 为准**:docs/08 § 二 中仅 `MR:` 字段在 `—` / `!<iid>` 之间变化,避免提前合并未完成模块的顺序错误。
175   -- **worktree 干净前置**(步骤 2):保证 test-gate.md、module-report.md、cross-module log.md 都已进 repo,审计证据完整;防止下次 coding-start 切回默认分支时遇到 dirty state。
  84 +向会话打印 `<MR_URL>`,结束本 skill。用户在 GitLab merge 后再运行 `/erp-workflow:coding-start`,入口扫描到 `state=merged` 后自动推进下一模块。
176 85  
177 86 ## 参考
178 87  
  88 +- `${CLAUDE_SKILL_DIR}/scripts/create-mr.sh`(步骤 4 主流程脚本)
179 89 - `${CLAUDE_SKILL_DIR}/templates/mr-title-template.md`
180 90 - `${CLAUDE_SKILL_DIR}/templates/mr-description-template.md`
181 91 - 上游:`module-report`
182   -- 守门:`interrupt-check`
183 92 - 下游闸门:用户手工 MR Approve + Merge
... ...
skills/coding/mr-create/scripts/create-mr.sh 0 → 100755
  1 +#!/usr/bin/env bash
  2 +# create-mr.sh — mr-create 主流程:渲染 description、查已有 MR / 创建新 MR
  3 +#
  4 +# 用法:
  5 +# bash create-mr.sh <module_id> <current_branch> <date>
  6 +#
  7 +# 输出(stdout,单行,由调用方读取):
  8 +# <MR_IID> <MR_URL>
  9 +#
  10 +# 失败:诊断写 stderr,exit 1。
  11 +#
  12 +# 设计要点:
  13 +# - 模块报告整文只经 sed + awk 管道流入 description 与 GitLab API(curl --rawfile),
  14 +# 全程不进 LLM 上下文。
  15 +# - 幂等:同一 source_branch 已有 opened MR 时,复用其 iid/url,不再创建。
  16 +
  17 +set -euo pipefail
  18 +
  19 +MODULE_ID="${1:?usage: create-mr.sh <module_id> <current_branch> <date>}"
  20 +CURRENT_BRANCH="${2:?missing current_branch}"
  21 +DATE="${3:?missing date (YYYY-MM-DD)}"
  22 +
  23 +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
  24 +TPL_DIR="$SCRIPT_DIR/../templates"
  25 +DESC_TPL="$TPL_DIR/mr-description-template.md"
  26 +TITLE_TPL="$TPL_DIR/mr-title-template.md"
  27 +
  28 +REPORT="docs/superpowers/module-reports/${DATE}-${MODULE_ID}.md"
  29 +TEST_GATE="docs/superpowers/module-reports/${MODULE_ID}-test-gate.md"
  30 +
  31 +[ -f "$REPORT" ] || { echo "[create-mr] ⚠️ 模块报告不存在: $REPORT" >&2; exit 1; }
  32 +[ -f "$TEST_GATE" ] || { echo "[create-mr] ⚠️ test-gate evidence 不存在: $TEST_GATE" >&2; exit 1; }
  33 +
  34 +# 1. 加载凭据
  35 +[ -f .env.local ] || { echo "[create-mr] ⚠️ .env.local 不存在" >&2; exit 1; }
  36 +set -a; . ./.env.local; set +a
  37 +for v in GITLAB_API_URL GITLAB_TOKEN GITLAB_PROJECT_ID; do
  38 + eval "val=\${$v:-}"
  39 + [ -n "$val" ] || { echo "[create-mr] ⚠️ .env.local 缺少 $v" >&2; exit 1; }
  40 +done
  41 +
  42 +# 2. 探测目标分支(origin/HEAD → main → master)
  43 +TARGET_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||' || true)
  44 +[ -n "$TARGET_BRANCH" ] || TARGET_BRANCH=$(git branch -r --format='%(refname:short)' | grep -E '^origin/(main|master)$' | head -1 | sed 's|^origin/||' || true)
  45 +[ -n "$TARGET_BRANCH" ] || { echo "[create-mr] ⚠️ 无法探测默认分支(origin/main 或 origin/master)" >&2; exit 1; }
  46 +
  47 +# 3. 从 docs/08 § 二 提取 module_name
  48 +MODULE_NAME=$(awk -v mid="$MODULE_ID" '
  49 + $0 ~ "^- "mid" " { sub("^- "mid" ", ""); print; exit }
  50 +' docs/08-模块任务管理.md)
  51 +[ -n "$MODULE_NAME" ] || { echo "[create-mr] ⚠️ docs/08 § 二 找不到模块 $MODULE_ID" >&2; exit 1; }
  52 +
  53 +# 4. 从 test-gate evidence 提取 conclusion + subagent_id
  54 +TEST_SUBAGENT_ID=$(awk '/^- 子会话: / { sub("^- 子会话: ", ""); print; exit }' "$TEST_GATE")
  55 +TEST_GATE_CONCLUSION=$(awk '/^结论: / { sub("^结论: ", ""); print; exit }' "$TEST_GATE" | awk '{print $1}')
  56 +
  57 +# 5. 渲染 MR 标题(单行,可进 LLM 上下文)
  58 +TITLE=$(cat "$TITLE_TPL")
  59 +TITLE="${TITLE//\{\{module_id\}\}/$MODULE_ID}"
  60 +TITLE="${TITLE//\{\{module_name\}\}/$MODULE_NAME}"
  61 +
  62 +# 6. 渲染 description(整篇模块报告,全程不进 LLM 上下文)
  63 +mkdir -p .tmp
  64 +DESC_FILE=.tmp/mr-desc.md
  65 +
  66 +sed -e "s|{{test_gate_conclusion}}|$TEST_GATE_CONCLUSION|g" \
  67 + -e "s|{{test_subagent_id}}|$TEST_SUBAGENT_ID|g" \
  68 + -e "s|{{module_id}}|$MODULE_ID|g" \
  69 + -e "s|{{date}}|$DATE|g" \
  70 + "$DESC_TPL" > "$DESC_FILE"
  71 +
  72 +awk -v report="$REPORT" '
  73 + /\{\{module_report_contents\}\}/ { while ((getline line < report) > 0) print line; close(report); next }
  74 + { print }
  75 +' "$DESC_FILE" > .tmp/mr-desc.final
  76 +mv .tmp/mr-desc.final "$DESC_FILE"
  77 +
  78 +# 7. 幂等守门:查已有 opened MR
  79 +HTTP_CODE=$(curl -sS -o .tmp/existing.json -w '%{http_code}' \
  80 + --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
  81 + "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests?source_branch=${CURRENT_BRANCH}&state=opened")
  82 +
  83 +if [ "$HTTP_CODE" != "200" ]; then
  84 + echo "[create-mr] ⚠️ 查询已有 MR 失败 (HTTP $HTTP_CODE)" >&2
  85 + jq -r '.message // .error // .' .tmp/existing.json | head -c 200 >&2
  86 + echo >&2
  87 + rm -f .tmp/existing.json "$DESC_FILE"
  88 + exit 1
  89 +fi
  90 +
  91 +EXISTING_IID=$(jq -r '.[0].iid // empty' .tmp/existing.json)
  92 +EXISTING_URL=$(jq -r '.[0].web_url // empty' .tmp/existing.json)
  93 +rm -f .tmp/existing.json
  94 +
  95 +if [ -n "$EXISTING_IID" ]; then
  96 + echo "[create-mr] 复用已有 opened MR: !$EXISTING_IID" >&2
  97 + rm -f "$DESC_FILE"
  98 + echo "$EXISTING_IID $EXISTING_URL"
  99 + exit 0
  100 +fi
  101 +
  102 +# 8. 创建新 MR(--rawfile desc 把 description 文件流入 jq → curl,不进 LLM 上下文)
  103 +CREATE_RESP=$(curl -sS -X POST \
  104 + --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
  105 + --header "Content-Type: application/json" \
  106 + --data "$(jq -n \
  107 + --arg src "$CURRENT_BRANCH" \
  108 + --arg tgt "$TARGET_BRANCH" \
  109 + --arg title "$TITLE" \
  110 + --rawfile desc "$DESC_FILE" \
  111 + '{source_branch: $src, target_branch: $tgt, title: $title, description: $desc, remove_source_branch: false}')" \
  112 + "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests")
  113 +
  114 +MR_IID=$(echo "$CREATE_RESP" | jq -r '.iid // empty')
  115 +MR_URL=$(echo "$CREATE_RESP" | jq -r '.web_url // empty')
  116 +
  117 +if [ -z "$MR_IID" ]; then
  118 + echo "[create-mr] ⚠️ MR 创建失败:" >&2
  119 + echo "$CREATE_RESP" | jq . >&2
  120 + rm -f "$DESC_FILE"
  121 + exit 1
  122 +fi
  123 +
  124 +rm -f "$DESC_FILE"
  125 +echo "$MR_IID $MR_URL"
... ...
skills/coding/test-gate/SKILL.md
1 1 ---
2 2 name: test-gate
3   -description: MR 创建前的唯一硬闸门。子会话执行 scripts/test.sh(setup-test-db.sh 清库后,Spring Boot 启动时 Flyway 自动 apply 当前 sql/migrations/V*.sql),任一失败则停止
  3 +description: MR 创建前的硬闸门。子会话跑 scripts/test.sh 全量测试,绿则进入 module-report,红则停下并按失败类型引导用户
4 4 user-invocable: false
5 5 allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *)
6 6 ---
... ... @@ -9,71 +9,53 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *)
9 9  
10 10 # test-gate
11 11  
12   -## 执行步骤
  12 +模块所有 REQ 完成后的硬闸门:子会话跑 `./scripts/test.sh`(含本模块新增 + 已合并模块回归),按模板渲染证据并 commit 到 module 分支。绿色继续,红色停下,按失败类型给用户恢复路径。
13 13  
14   -1. **派发子会话**(`Agent`,general-purpose)运行 `./scripts/test.sh`:
  14 +## 执行步骤
15 15  
  16 +1. 派发 Agent 子会话(general-purpose)运行 `./scripts/test.sh`,子会话只返回结构化 JSON(不输出描述文字):
  17 + ```json
  18 + {
  19 + "command": "./scripts/test.sh",
  20 + "exit_code": <int>,
  21 + "passed": <int>,
  22 + "failed": <int>,
  23 + "stdout_excerpt": "<最后 30 行,含 FAIL 摘要>"
  24 + }
16 25 ```
17   - 任务:运行项目本地测试闸门。不要修改任何代码或数据。步骤:
18   - 1. cd 到仓库根目录。
19   - 2. 执行:./scripts/test.sh
20   - 3. 仅返回 JSON:{"command":"./scripts/test.sh","exit_code":<int>,"passed":<int>,"failed":<int>,"stdout_excerpt":"<最后 30 行,包含 FAIL 摘要>"}
21   - 不要输出任何描述性文字。
22   - ```
23   -
24   -2. 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/test-gate-result-template.md`,用结果填充槽位。
25   -
26   -3. 写入 `docs/superpowers/module-reports/<module_id>-test-gate.md`。
27   -
28   -3b. **commit evidence 到 module 分支**(确保 test-gate.md 随 MR 合并进默认分支,审计可追溯):
29   -
  26 +2. 按 `${CLAUDE_SKILL_DIR}/templates/test-gate-result-template.md` 渲染证据,写入 `docs/superpowers/module-reports/<module_id>-test-gate.md`。
  27 +3. Commit evidence 到 module 分支(保证证据随 MR 合并进默认分支可审计):
30 28 ```bash
31 29 git add docs/superpowers/module-reports/<module_id>-test-gate.md
32 30 git commit -m "chore(<module_id>): add local test-gate evidence"
33 31 ```
34   -
35   -4. 如果 `exit_code = 0` → 交接给 `module-report`(输出 `test-gate: 通过`)。
36   -
37   -5. 否则打印以下横幅并**停下**(不自动重试、不自动修复——失败分类需人工判断):
  32 +4. **`exit_code = 0`** → 调用 `Skill(module-report)`。
  33 +5. **失败** → 打印以下横幅并停止,不调用下游 skill;不自动重试、不自动修复(失败分类需人工判断):
38 34  
39 35 ```
40 36 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
41 37 [test-gate] ⚠️ 未通过
42   -
43   - 失败清单: <失败测试清单(来自子会话 JSON)>
44   - stdout 摘录: <最后 30 行 / FAIL 摘要>
  38 + 失败清单: <子会话 JSON 的 failed 摘要>
45 39 详细证据: docs/superpowers/module-reports/<module_id>-test-gate.md
46 40  
47   - 请根据失败类型选择下一步:
48   -
49   - ① 测试脆弱(flakey,偶发)
50   - → 重新运行 /erp-workflow:coding-start
51   - (module-start 幂等:reviews 已全 approve 会跳过功能循环,直接重新执行本闸门)
52   -
53   - ② 真有回归(某个 REQ 破坏了其他 REQ/已合并模块)
54   - → 定位到具体 REQ,删除其 review 记录:
55   - rm docs/superpowers/reviews/*-<REQ-id>.md
56   - → 重新运行 /erp-workflow:coding-start
57   - (module-start 把该 REQ 视为未完成,重走 brainstorm→...→review 循环修复)
58   -
59   - ③ 环境/依赖问题(DB 连不上、外部 API 失败、证书失效)
60   - → 触发中断 #3(外部接口不可达)
61   - → 调用 Skill(interrupt-check) 追加 Blocker 到本模块任一 plan 文件
62   - → 修复环境后重新运行 /erp-workflow:coding-start
  41 + 按失败类型选恢复路径:
  42 + ① 测试脆弱(偶发 flakey)→ 重跑 /erp-workflow:coding-start
  43 + (module-start 幂等:reviews 已全 approve 会跳过功能循环,直接重跑本闸门)
  44 + ② 真有回归(某 REQ 破坏其它 REQ 或已合并模块)
  45 + → rm docs/superpowers/reviews/*-<REQ-id>.md
  46 + → 重跑 /erp-workflow:coding-start(module-start 视该 REQ 未完成,重走功能循环)
  47 + ③ 环境/依赖问题(DB 连不上 / 外部 API 失败 / 证书失效)
  48 + → Skill(interrupt-check) 追加 Blocker 到任一 plan 文件 → 修复环境 → 重跑
63 49 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
64 50 ```
65 51  
66   - 然后**停止**,不调用下游 skill(module-report / mr-create)。
67   -
68 52 ## 护栏
69 53  
70   -- **绝不**在主会话直接执行 `./scripts/test.sh`。
71   -- **绝不**通过 `git push --no-verify` 绕过(hook `deny-no-verify.sh` 会拦截)。
72   -
73   -## 衔接
74   -
75   -立即调用 `Skill(module-report)` 生成模块报告。
  54 +- **绝不**在主会话直接执行 `./scripts/test.sh`,必须通过子会话
  55 +- **绝不**通过 `git push --no-verify` 绕过(hook `deny-no-verify.sh` 会硬拦)
76 56  
77 57 ## 参考
78 58  
79 59 - `${CLAUDE_SKILL_DIR}/templates/test-gate-result-template.md`
  60 +- 上游:`module-start`(本模块 REQ 全 approve 后派发到此)
  61 +- 下游:`module-report`(绿色时)
... ...
skills/crosscut/coding-start/SKILL.md
1 1 ---
2 2 name: coding-start
3   -description: B 阶段(Coding)入口。先验证 Plan 已完成;按 docs/02 § 二 REQ 开发顺序清单扫描,对每个 REQ 所属模块用 docs/08 的 `MR:` 字段 + GitLab API state 判定是否完成——merged 跳过,`—` 或 opened/closed 选为当前模块并派发到 module-start。派发前自动探测默认分支(main / master)并 git checkout + pull --ff-only 保持 base 最新
  3 +description: B 阶段(Coding)入口。验证 Plan 已完成后派发到 module-start;模块定位、分支管理与远程同步全部由 module-start 负责
4 4 user-invocable: true
5   -allowed-tools: Skill Read Glob Grep Bash(curl *) Bash(jq *) Bash(git branch *) Bash(git checkout *) Bash(git pull *) Bash(git status *) Bash(git symbolic-ref *) Bash(sed *) Bash(mkdir -p .tmp) Bash(rm -f .tmp/*)
  5 +allowed-tools: Skill Read Glob Grep Bash(cat *)
6 6 ---
7 7  
8 8 **所有输出必须使用中文。**
... ... @@ -11,157 +11,33 @@ B 阶段(Coding)的入口分发器。
11 11  
12 12 ## 执行步骤
13 13  
14   -### 步骤 1:确认 docs/08 存在
15   -
16   -检查 `docs/08-模块任务管理.md`存在。
17   -- 不存在 → 打印"⚠️ 项目尚未初始化,请先运行 `/erp-workflow:plan-start`"并停下。
18   -
19   -### 步骤 2:Plan 完成性检查
20   -
21   -用 `Grep` 在 `docs/08-模块任务管理.md` 搜索 `^- \[ \] A[0-5]`(pattern 可以直接匹配父项未勾的情况;也可以用更宽的 `^[[:space:]]*- \[ \].*A[0-5]` 覆盖子项)。
22   -
23   -- **命中任一A 阶段未勾选** → 打印并停下:
24   - ```
25   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
26   - [coding-start] ⚠️ Plan 尚未完成
27   -
28   - docs/08 § 一 还有未勾选项,请先运行:
29   - /erp-workflow:plan-start
30   -
31   - 继续 Plan 阶段直到 A5 下游文档生成完成,再回来运行 coding-start。
32   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
33   - ```
34   -
35   -- 无命中 → Plan 已完成,进入步骤 3。
36   -
37   -### 步骤 3:按 docs/02 REQ 序 + MR state 找当前模块
38   -
39   -> `MR:` 字段 × GitLab API state 的三组合判定规则见 `CLAUDE.md § ✅ 模块完成判定规则 § 模块状态语义`。
40   -
41   -1. 用 `Read` 读取 `docs/02-开发计划.md` 的 § 二;用 `Grep`(pattern `^\|\s*[0-9]+\s*\|\s*\*\*(REQ-[A-Z0-9]+-[0-9]+)\*\*\s*\|\s*(module_\w+)`,`-n`)抽取所有表格数据行,按行号升序得 `req_order[]`,每项含 `req_id` + `module_id`。
42   -2. 若 `req_order` 为空 → 打印错误并**停下**(与原逻辑相同,略)。
43   -3. **初始化模块完成缓存 `module_merged[module_id → bool]`**(空)。
44   -4. 按序遍历 `req_order[]`:
45   - - 若 `module_merged[module_id]` 已有缓存:
46   - - `true` → 跳过本 REQ,继续下一个
47   - - `false` → `current_module = module_id`,结束遍历,进入步骤 4
48   - - 未缓存 → 读取 docs/08 § 二 该模块条目的 ` - MR:` 字段:
49   - - `MR: —` → `module_merged[module_id] = false`;`current_module = module_id`,结束遍历
50   - - `MR: !<iid>` → 先 `Bash`: `set -a; . ./.env.local; set +a` 加载凭据,然后**分步校验 HTTP 状态 + 返回条数 + state 枚举**(v3 API 用 iid 过滤列表):
51   - ```bash
52   - mkdir -p .tmp
53   - HTTP_CODE=$(curl -sS -o .tmp/mr.json -w '%{http_code}' \
54   - --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
55   - "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests?iid=<iid>")
56   - ```
57   - **硬停条件**(触发任一则打印诊断横幅并**停下**,不派发;任何"查不到就假设未 merged"的静默处理都禁止):
58   - 1. `HTTP_CODE != 200`:API 不可达 / token 错 / URL 错
59   - 2. `HTTP_CODE == 200` 但 `jq 'length' .tmp/mr.json != 1`:docs/08 记了 `!<iid>` 但远程查不到对应 MR(数据不一致)
60   - 3. `state = jq -r '.[0].state' .tmp/mr.json` 不在 `{merged, opened, closed}` 三个合法值里
61   -
62   - 诊断横幅模板:
63   - ```
64   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
65   - [coding-start] ⚠️ 无法确定 MR !<iid>(模块 <module_id>)的状态
66   -
67   - 原因: <HTTP <code> | 查不到 MR | state=<异常值>>
68   - API : ${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}
69   - body: <jq -r '.message // .error // .' .tmp/mr.json | head -c 200>
70   -
71   - 请按下列顺序核查:
72   - 1. .env.local 的 GITLAB_TOKEN 是否有效(在 GitLab Profile → Private token 页检查)
73   - 2. GITLAB_API_URL 前缀 / v3 路径 / host 是否匹配你的 GitLab 部署
74   - 3. GITLAB_PROJECT_ID 是否是该项目的 URL-encoded 路径或数字 ID
75   - 4. docs/08 记的 iid 是否存在于 GitLab 项目的 MR 列表
  14 +### 步骤 0:打印 B 阶段整体流程图
76 15  
77   - 修正后重跑 /erp-workflow:coding-start。
78   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
79   - ```
80   - 清理:`rm -f .tmp/mr.json`。
81   -
82   - 校验通过后按 state 分派:
83   - - `merged` → `module_merged[module_id] = true`,跳过本 REQ
84   - - `opened` / `closed` → `module_merged[module_id] = false`;`current_module = module_id`,结束遍历
85   -5. 全遍历完仍无命中(所有模块都 merged) → 打印:
86   - ```
87   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
88   - [coding-start] ✅ 所有模块已完成
89   -
90   - docs/02 § 二 清单中每个 REQ 所属模块的 MR 都已 merged。项目结束。
91   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
92   - ```
93   - 并**停下**。
94   -6. 命中后:记录 `current_module` 的 `MR:` 字段值(`—` / `!<iid>-opened` / `!<iid>-closed` / `!<iid>-查不到`,用于步骤 5 横幅展示)。
95   -
96   -### 步骤 4:探测默认分支 + 切回并同步远程(准备 module-start 切新分支的干净 base)
97   -
98   -4.0 **探测默认分支**:
  16 +每次入口都先展示总图,再做后续校验和派发:
99 17  
100 18 ```bash
101   -DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
102   -if [ -z "$DEFAULT_BRANCH" ]; then
103   - # HEAD 未设置,回退:在 main / master 里取第一个实际存在的远程分支
104   - DEFAULT_BRANCH=$(git branch -r --format='%(refname:short)' | grep -E '^origin/(main|master)$' | head -1 | sed 's|^origin/||')
105   -fi
  19 +cat "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/coding-start/banners/flow-overview.txt"
106 20 ```
107 21  
108   -- `DEFAULT_BRANCH` 为空 → 打印错误并**停下**(既无 `origin/main` 也无 `origin/master`,说明远程未就绪,提示用户先完成 Plan 的首次 push 或 `git remote set-head origin -a` 设置 HEAD)。
109   -
110   -4.1 **切回 + 同步**:
111   -
112   -- `Bash`: `git branch --show-current` → `current_branch`。
113   -- 若 `current_branch != $DEFAULT_BRANCH`:
114   - - `Bash`: `git status --porcelain`;非空 → 打印:
115   - ```
116   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
117   - [coding-start] ⚠️ 当前分支 <current_branch> 有未提交改动,无法切换到 <DEFAULT_BRANCH>
118   -
119   - <git status 输出>
120   -
121   - 请手工处理后重新运行 /erp-workflow:coding-start。
122   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
123   - ```
124   - 并**停下**。
125   - - `Bash`: `git checkout "$DEFAULT_BRANCH"`。
126   -- `Bash`: `git pull --ff-only origin "$DEFAULT_BRANCH"`。
127   - - 失败(非 fast-forward / 网络 / 冲突)→ 打印错误横幅:
128   - ```
129   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
130   - [coding-start] ⚠️ 同步 <DEFAULT_BRANCH> 失败
131   -
132   - 本地 <DEFAULT_BRANCH> 无法 fast-forward 到 remote。请手工处理:
133   - git status
134   - git log <DEFAULT_BRANCH>..origin/<DEFAULT_BRANCH> # 远程领先的 commit
135   - git log origin/<DEFAULT_BRANCH>..<DEFAULT_BRANCH> # 本地未推的 commit
136   - 修复后重新运行 /erp-workflow:coding-start。
137   - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
138   - ```
139   - 并**停下**。
  22 +### 步骤 1:确认 docs/08 存在
140 23  
141   -### 步骤 5:打印横幅并分发
  24 +检查 `docs/08-模块任务管理.md`存在。
  25 +- 不存在 → 打印"⚠️ 项目尚未初始化,请先运行 `/erp-workflow:plan-start`"并停下。
142 26  
143   -```
144   -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
145   - [coding-start]
146   - 阶段:B 编码
147   - 当前模块:<current_module>
148   - MR 状态:<未建 | opened | closed | 查不到>
149   - 下一步:invoke module-start
150   -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
151   -```
  27 +### 步骤 2:Plan 完成性检查
152 28  
153   -然后立即用 `Skill` 工具调用 `module-start`
  29 +读取 `docs/08-模块任务管理.md § 一`,判断 A0~A5 是否全部勾选(含子项)
154 30  
155   -> 分发前先调用 `interrupt-check`;触发中断则停在此不分发。
  31 +- 任一未勾选 → 提示用户先运行 `/erp-workflow:plan-start` 完成 A 阶段,并停下
  32 +- 全部勾选 → 进入步骤 3
156 33  
157   -## 设计要点
  34 +### 步骤 3:派发到 module-start
158 35  
159   -- **完成判定直接读取 `MR:` 字段 + GitLab API state**(curl,`PRIVATE-TOKEN` 头):MR 未 merge 前 docs/08 没有任何"已完成"标记;用户提前触发 coding-start 时,步骤 3 扫描到 MR opened 仍会选中当前模块,module-start 会 `git checkout module-<id>` 回到原分支继续,不会跳到下一模块。
160   -- **每次派发前都 pull 默认分支**:代码同步的同时,也保证 module-start 切出新分支时 base 新鲜。默认分支由步骤 4.0 探测(main 或 master),不硬编码。
  36 +打印一句 `[coding-start] → invoke module-start` 后立即用 `Skill` 工具调用 `module-start`。当前模块的定位、MR 状态、分支管理与 REQ 列表全部由 `module-start` 自行处理。
161 37  
162 38 ## 参考
163 39  
164   -- `docs/02-开发计划.md § 二 开发顺序清单`(分发追踪)
165   -- `docs/08-模块任务管理.md § 二`(模块元数据,含 `MR:` 字段)
166   -- `CLAUDE.md`(项目指令)
  40 +- `docs/08-模块任务管理.md § 一`(A0~A5 进度勾选,本 skill 步骤 2 读取)
  41 +- `module-start`(下游:模块定位 + REQ 列表 + 推进)
167 42 - `plan-start`(姊妹入口,A 阶段)
  43 +- `CLAUDE.md`(项目指令)
... ...
skills/crosscut/coding-start/banners/flow-overview.txt 0 → 100644
  1 +┌────────────────────────────────────────────────────────┐
  2 +│ 🛠️ 阶段 B:编码(按模块循环) │
  3 +│ │
  4 +│ coding-start │
  5 +│ (Plan 完成校验) │
  6 +│ ↓ │
  7 +│ module-start │
  8 +│ (定位当前模块 + 推进未完成 REQ) │
  9 +│ ↓ │
  10 +│ ┌─ 功能循环(每个 REQ)─────────────┐ │
  11 +│ │ feature-brainstorm │ │
  12 +│ │ ↓ │ │
  13 +│ │ feature-plan │ │
  14 +│ │ ↓ │ │
  15 +│ │ feature-tdd │ │
  16 +│ │ ↓ │ │
  17 +│ │ feature-verify │ │
  18 +│ │ ↓ │ │
  19 +│ │ feature-review │ │
  20 +│ │ ├ approve → 回 module-start │
  21 +│ │ └ request-changes ↺ 重跑 verify │
  22 +│ │ (自修复 ≤5 轮) │
  23 +│ └────────────────────────────────────┘ │
  24 +│ ↓ (本模块所有 REQ approve) │
  25 +│ test-gate (子会话跑 ./scripts/test.sh) │
  26 +│ ↓ │
  27 +│ module-report (生成 12 节模块完成报告) │
  28 +│ ↓ │
  29 +│ mr-create (push + 创建 GitLab MR) │
  30 +│ ↓ │
  31 +│ 停下,等待人工 Approve + Merge │
  32 +│ ↺ 用户重跑 coding-start │
  33 +│ ╰──→ 回到 module-start(下一模块) │
  34 +└────────────────────────────────────────────────────────┘
... ...
skills/crosscut/cross-module-log/SKILL.md
1 1 ---
2 2 name: cross-module-log
3   -description: 为 log-cross-module.sh hook 自动追加到跨模块改动日志中的条目批量补填「原因」和「影响评估」。**仅由 module-report § ⑦ 硬验收时调用**,CC 编辑中途不主动调用(节省 LLM 调用次数)
  3 +description: 批量补填跨模块改动日志中 hook 留下的 `TBD(CC 补)`(原因 / 影响评估两列)。仅由 module-report § ⑦ 硬验收时调用
4 4 user-invocable: false
5 5 allowed-tools: Read Write Edit Bash(git branch *)
6 6 ---
... ... @@ -9,29 +9,23 @@ allowed-tools: Read Write Edit Bash(git branch *)
9 9  
10 10 # cross-module-log
11 11  
12   -## 说明
13   -
14   -软规则 S2 执行:对**非当前模块**文件的每次编辑(无论目标模块是否已 MR merged)必须记录原因 + 影响评估。
15   -
16   -**本日志由 hook + skill 协作维护**——hook 自动落存根(4 列机械数据),CC 不主动处理 TBD;由 `module-report` § ⑦ 硬验收阶段统一调用本 skill,一次性推断补齐「原因 / 影响评估」两列。**不需要人工填写**,人工只在最终看 MR 描述时复核。
  12 +软规则 S2 自动留痕:hook `log-cross-module.sh` 在每次对**非当前模块**文件的改动时追加 4 列存根(时间戳 / 目标模块 / 文件 / 改动摘要),「原因」「影响评估」两列写 `TBD(CC 补)`。本 skill 在 `module-report § ⑦` 硬验收阶段一次性推断补齐两列;CC 编辑代码中途不主动调用(节省 LLM 调用次数)。
17 13  
18 14 ## 执行步骤
19 15  
20   -1. 确定当前模块(从当前 git 分支名推导:`git branch --show-current` → `module-<module_id>` → 取 `module_id`。`module-start` 步骤 3 保证本 skill 执行时一定处于 `module-*` 分支)。
21   -2. 打开 `docs/superpowers/module-reports/<current>-cross-module.md`。**文件不存在 → 打印 `cross-module-log: 无跨模块改动,跳过` 并退出**(hook 是日志文件的唯一创建者;文件缺失意味着本模块周期内 hook 从未追加过条目,没有 TBD 需要补)。
22   -3. 找到「原因」或「影响评估」列中含 `TBD(CC 补)` 的行。
23   -4. 对每个 TBD 行,CC **自主推断**填写以下两列(基于当前 session 的改动上下文 + REQ 卡片 + 目标模块的代码):
24   - - **原因**:为什么要修改目标模块的代码?当前模块的哪个需求迫使这样做?
25   - - **影响评估**:目标模块的哪些 API / 行为 / 调用方可能受影响?其现有测试是否仍然有效?是否需要新测试?(1-3 句话)
26   -5. 编辑该行;保持时间戳 / 目标模块 / 文件 / 改动摘要列不变。
27   -6. 输出确认:`cross-module-log: 更新了 N 行`。
28   -
29   -## 下游
30   -
31   -填充后的日志会被 `module-report` 原文嵌入到 `module-report-template.md` § ⑦。
  16 +1. 从 `git branch --show-current` 取 `module_id`(去掉 `module-` 前缀;`module-start` 步骤 3 保证此时在 `module-*` 分支)。
  17 +2. 打开 `docs/superpowers/module-reports/<module_id>-cross-module.md`。文件不存在 → 输出 `cross-module-log: 无跨模块改动,跳过` 并结束(hook 是日志文件唯一创建者;缺失意味着本模块周期内没有跨模块改动)。
  18 +3. 用 `Edit` 逐行替换「原因」或「影响评估」列含 `TBD(CC 补)` 的行:
  19 + - **保持时间戳 / 目标模块 / 文件 / 改动摘要四列不变**
  20 + - **原因**:为什么要改目标模块的代码?当前模块的哪个 REQ 迫使这样做?
  21 + - **影响评估**:目标模块的哪些 API / 行为 / 调用方可能受影响?现有测试是否仍有效?是否需要新测试?(1-3 句话)
  22 + - 推断依据:当前 session 的改动上下文 + REQ 卡片 + 目标模块代码
  23 +4. 输出 `cross-module-log: 更新了 N 行`。
32 24  
33 25 ## 参考
34 26  
35   -- `${CLAUDE_SKILL_DIR}/templates/cross-module-log-template.md`(仅供 `hooks/scripts/log-cross-module.sh` 创建日志文件时渲染表头;本 skill 自身不再读取)
36   -- `${CLAUDE_SKILL_DIR}/templates/cross-module-log-row-template.md`(行结构参考,hook 内联拼接行字符串,本 skill 直接编辑已有行)
37   -- `CLAUDE.md` § 🟡 软规则 S2
  27 +- `${CLAUDE_SKILL_DIR}/templates/cross-module-log-template.md`(hook 创建日志文件时渲染表头,本 skill 不读)
  28 +- `${CLAUDE_SKILL_DIR}/templates/cross-module-log-row-template.md`(行结构参考,hook 拼接用;本 skill 直接 Edit 已有行)
  29 +- `CLAUDE.md § 🟡 软规则 S2`
  30 +- 上游:`module-report § ⑦`(唯一调用方)
  31 +- 下游:`module-report` 把补齐后的日志原文嵌入 § ⑦
... ...
skills/crosscut/interrupt-check/SKILL.md
1 1 ---
2 2 name: interrupt-check
3   -description: 在每个功能循环步骤和生成重要制品前运行。检查 CLAUDE.md 中的 3 项中断清单,触发任一项则追加 Blocker 到计划文件并停止
  3 +description: 检查 CLAUDE.md § 🚩 中断机制 3 项是否触发,触发则追加 Blocker 到当前 plan 文件并停下,等用户决策
4 4 user-invocable: false
5 5 allowed-tools: Read Write Bash(mysql *)
6 6 ---
... ... @@ -9,19 +9,18 @@ allowed-tools: Read Write Bash(mysql *)
9 9  
10 10 # interrupt-check
11 11  
12   -## 说明
  12 +核对 CLAUDE.md § 🚩 中断机制中的 3 项是否触发;任一触发 → 按模板渲染 Blocker 块追加到当前 plan 文件,**停下,用户决策前不调用任何下游 skill**。
13 13  
14   -验证 CLAUDE.md § 🚩 中断机制中的 3 项均未触发。触发任一项则中断
  14 +> 需求歧义 / schema 缺口 / 技术栈外组件引入等场景不在本清单,由各 feature-* 的 `AskUserQuestion` 流程处理
15 15  
16   -> 需求歧义 / schema 缺口 / 技术栈外组件引入等场景由各 feature-* skill 的 `AskUserQuestion` 流程承接,不进入本清单,不会在这里触发。
  16 +## 调用方(现役)
17 17  
18   -## 调用时机
  18 +- **feature-tdd 步骤 3.e**:同一测试连续 >10 次修复失败时主动调用(命中条件 1)
  19 +- **test-gate 失败横幅 ③**:环境/依赖问题时引导用户手工调用(命中条件 3)
19 20  
20   -- 每个功能循环步骤开始前(3.1-3.5)
21   -- 生成模块级制品前(模块报告、MR 描述)
22   -- 用户请求涉及外部依赖、环境凭据变更时
  21 +其它 skill 均已不再预防性调用本 skill;条件 2 / 3 在自然出错路径上由各 skill 自身的诊断信息覆盖,本 skill 主要承接条件 1 的硬触发与用户主动登记。
23 22  
24   -## 检查清单(3 项 — 权威来源:CLAUDE.md
  23 +## 检查清单(权威来源:`CLAUDE.md § 🚩 中断机制`
25 24  
26 25 1. **测试反复失败** — 同一功能中同一测试连续 10 次修复失败
27 26 2. **要改密钥/账密/包名** — 涉及 `docs/07-环境配置.md` 中的人工填写字段
... ... @@ -29,21 +28,12 @@ allowed-tools: Read Write Bash(mysql *)
29 28  
30 29 ## 执行步骤
31 30  
32   -1. 读取当前功能的规格/计划文件路径(从对话或 `docs/08` 获取)。
33   -2. 逐项检查 3 个中断。如果全部未触发 → 输出 `interrupt-check: 通过`,退出。
34   -3. 触发时:
35   - - 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/interrupt-block-template.md`
36   - - 填充槽位(interrupt_number、interrupt_name、description、affected_scope、recommendation、decision_needed)
37   - - 将渲染后的块追加到当前计划文件:`docs/superpowers/plans/YYYY-MM-DD-<REQ-id>.md`
38   - - 向会话打印一句话摘要 + 指向计划文件的路径
39   - - **停止** — 在用户决策前不调用任何后续 skill
40   -
41   -## 输出
42   -
43   -`interrupt-check: 通过`(仅会话),或一个 `## 🚩 Blocker` 块追加到功能计划文件。
  31 +1. 逐项核对 3 个中断条件。**全部未触发** → 输出 `interrupt-check: 通过`,结束。
  32 +2. **触发任一** → 按 `${CLAUDE_SKILL_DIR}/templates/interrupt-block-template.md` 渲染 Blocker 块,追加到当前 plan 文件(典型路径 `docs/superpowers/plans/<YYYY-MM-DD>-<REQ-id>.md`;test-gate 场景下追加到本模块任一已有 plan 文件)。
  33 +3. 向会话打印一句话摘要 + 指向 plan 文件路径,**停下**。
44 34  
45 35 ## 参考
46 36  
47 37 - `${CLAUDE_SKILL_DIR}/templates/interrupt-block-template.md`
48   -- `CLAUDE.md` § 🚩 中断机制(权威 3 条)
49   -- `CLAUDE.md` § 🟡 软规则(S2 跨模块改动,不触发中断但需留痕)
  38 +- `CLAUDE.md § 🚩 中断机制`(权威 3 条)
  39 +- `CLAUDE.md § 🟡 软规则`(S2 跨模块改动不触发中断;由 `cross-module-log` 处理)
... ...
skills/crosscut/plan-start/SKILL.md
... ... @@ -36,10 +36,10 @@ docs/08 § 一 是**Plan 阶段进度追踪**(A0~A5 çš„ checkbox)。§ 二çš
36 36  
37 37 ### 2.1 Plan 已完æˆ
38 38  
39   -A 阶段所有 checkbox å‡ `[x]`。无åŽç»­ skill,本步骤**è‡ªè¡Œæ‰“å°æµç¨‹å›¾**,然åŽ**åœä¸‹**:
  39 +A 阶段所有 checkbox å‡ `[x]`。无åŽç»­ skill,本步骤**å…ˆæ‰“å°æ•´ä½“æµç¨‹å›¾**,å†è¾“å‡ºå®Œæˆæ¨ªå¹…,然åŽ**åœä¸‹**:
40 40  
41 41 ```bash
42   -cat "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/plan-start/banners/flow-done.txt"
  42 +cat "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/plan-start/banners/flow-overview.txt"
43 43 ```
44 44  
45 45 å†å‘ç”¨æˆ·è¾“å‡ºå®Œæˆæ¨ªå¹…:
... ... @@ -66,6 +66,12 @@ cat &quot;${CLAUDE_PLUGIN_ROOT}/skills/crosscut/plan-start/banners/flow-done.txt&quot;
66 66  
67 67 ### 2.2 正常派å‘(`åŽç»­` éžç©ºï¼‰
68 68  
  69 +å…ˆæ‰“å°æ•´ä½“æµç¨‹å›¾ï¼Œå†æ‰“å°åˆ†å‘通知:
  70 +
  71 +```bash
  72 +cat "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/plan-start/banners/flow-overview.txt"
  73 +```
  74 +
69 75 打å°ç®€çŸ­åˆ†å‘通知:
70 76  
71 77 ```
... ...
skills/crosscut/plan-start/banners/flow-done.txt renamed to skills/crosscut/plan-start/banners/flow-overview.txt
... ... @@ -12,6 +12,4 @@
12 12 │ A4 初始化 DB │
13 13 │ ↓ │
14 14 │ A5 生成下游文档 │
15   -│ │
16   -│ ▶ 规划阶段到此结束 │
17 15 └────────────────────────────────────────────────────────┘
... ...
skills/plan/downstream-gen/SKILL.md
... ... @@ -123,7 +123,7 @@ cp &quot;${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md&quot; docs/10-验收检æ
123 123 1. 审核 docs/01~10 + CLAUDE.md + sql/migrations/V1 + å„ scripts/*
124 124  
125 125 2. 把全部 Plan 产物 commit:
126   - git add -A && git commit -m "chore: plan phase A0~A5 done"
  126 + git add -A && git commit -m "chore: plan phase done"
127 127  
128 128 3. 推到远程,按仓库状æ€äºŒé€‰ä¸€ï¼š
129 129  
... ...