Commit 2a3f8d0965f10afef41002e5740b58d887b2d389
1 parent
52014d4e
scope-lock: write REQ cards directly, align to new template, auto-chain A1->A2
- D-step: CC writes _module.md/REQ-*.md directly (no render.mjs/vars.json)
- req-card template restructured: input/output example tables copied verbatim, CC fills 6 {{}} scalars; E.1 validates {{}} residual only
- E.2: write all config (incl. secret placeholders) into config-vars.yaml
- E.4: no human-review stop — auto Skill(skeleton-gen) into A2
Showing
2 changed files
with
64 additions
and
54 deletions
skills/plan/scope-lock/SKILL.md
| 1 | --- | 1 | --- |
| 2 | name: scope-lock | 2 | name: scope-lock |
| 3 | -description: A1 计划范围锁定——引导用户填写项目概述 + 技术栈 + 需求索引,并按模块子目录生成 REQ 卡片骨架(CC 推断 req_id/title/goal/rules/constraints/acceptance;输入/输出 字段表为结构化 6 列表单由人工逐行填真实数据);末尾执行 A1 终结校验:每张 REQ 卡片字段含真实数据、配置字段名锁进 config-vars.yaml(非敏感填值 + secrets_ref 键名引用 .env.local)、build/lint/unit/e2e 命令锁进 docs/04 §零,缺则当场 AskUserQuestion 问清。 | 3 | +description: A1 计划范围锁定——引导用户填写项目概述 + 技术栈 + 需求索引,并按模块子目录生成 REQ 卡片(CC 据 index.md 填 req_id/title/goal/rules/constraints/acceptance 这 6 个 `{{}}` 占位,模板其余内容含输入/输出示例字段表原样复制);末尾执行 A1 终结校验:每张 REQ 卡片 6 个占位均填真实数据、全部配置锁进 config-vars.yaml(非敏感填值、敏感凭据留占位待人工填)、build/lint/unit/e2e 命令锁进 docs/04 §零,缺则当场 AskUserQuestion 问清。 |
| 4 | user-invocable: false | 4 | user-invocable: false |
| 5 | -allowed-tools: Read Write Edit Grep Glob Skill AskUserQuestion Bash(mkdir *) Bash(node *) | 5 | +allowed-tools: Read Write Edit Grep Glob Skill AskUserQuestion Bash(mkdir *) |
| 6 | --- | 6 | --- |
| 7 | 7 | ||
| 8 | **所有输出必须使用中文。** | 8 | **所有输出必须使用中文。** |
| @@ -25,63 +25,47 @@ allowed-tools: Read Write Edit Grep Glob Skill AskUserQuestion Bash(mkdir *) Bas | @@ -25,63 +25,47 @@ allowed-tools: Read Write Edit Grep Glob Skill AskUserQuestion Bash(mkdir *) Bas | ||
| 25 | 25 | ||
| 26 | ### D. 生成 REQ 卡片骨架并停下等人工审阅 | 26 | ### D. 生成 REQ 卡片骨架并停下等人工审阅 |
| 27 | 27 | ||
| 28 | -1. 用 `Grep` 校验 `docs/01-需求清单/index.md` 无 `【人工填写:` 残留;有则回步骤 C。 | ||
| 29 | -2. 用 `Read` 读 `index.md` 解析模块索引。 | ||
| 30 | -3. **每模块/每 REQ 渲染**:`mkdir -p` → `Write` vars.json → `node render.mjs`。`<MOD>` / `<模块名>` / `<REQ-MOD-NNN>` 按 `index.md` 实际值替换。 | ||
| 31 | - | ||
| 32 | - ```bash | ||
| 33 | - # 模块头:先 Write docs/01-需求清单/<MOD>-<模块名>/_module.vars.json,内容形如 | ||
| 34 | - # {"module_code":"<MOD>","module_name":"<模块名>","module_brief":"<module_brief>"} | ||
| 35 | - mkdir -p "docs/01-需求清单/<MOD>-<模块名>" | ||
| 36 | - node "${CLAUDE_PLUGIN_ROOT}/lib/render.mjs" \ | ||
| 37 | - "${CLAUDE_SKILL_DIR}/templates/_module-template.md" \ | ||
| 38 | - "docs/01-需求清单/<MOD>-<模块名>/_module.vars.json" \ | ||
| 39 | - "docs/01-需求清单/<MOD>-<模块名>/_module.md" | ||
| 40 | - | ||
| 41 | - # 每个 REQ:先 Write 该 REQ 的 vars JSON,内容形如 | ||
| 42 | - # {"req_id":"<REQ-MOD-NNN>","title":"<title>","goal":"<goal>","rules":"<rules>","constraints":"<constraints>","acceptance":"<acceptance>"} | ||
| 43 | - node "${CLAUDE_PLUGIN_ROOT}/lib/render.mjs" \ | ||
| 44 | - "${CLAUDE_SKILL_DIR}/templates/req-card-template.md" \ | ||
| 45 | - "docs/01-需求清单/<MOD>-<模块名>/<REQ-MOD-NNN>.vars.json" \ | ||
| 46 | - "docs/01-需求清单/<MOD>-<模块名>/<REQ-MOD-NNN>.md" | ||
| 47 | - ``` | ||
| 48 | -4. 用 `Edit` 在 `docs/08-模块任务管理.md` 勾选(A1 子项): | 28 | +1. 读 `index.md` 解析模块索引;读两个模板 `${CLAUDE_SKILL_DIR}/templates/_module-template.md`、`${CLAUDE_SKILL_DIR}/templates/req-card-template.md` 作为卡片结构参照。 |
| 29 | +2. **每模块/每 REQ 直接 `Write`**:对每个模块先 `mkdir -p "docs/01-需求清单/<MOD>-<模块名>"`,再照模板结构 `Write`,`<MOD>` / `<模块名>` / `<REQ-MOD-NNN>` 按 `index.md` 实际值替换: | ||
| 30 | + - **模块头** `_module.md`:据 `index.md` 填 `module_code` / `module_name` / `module_brief`;`依赖模块: TBD(A5 自动补)` / `涉及表: TBD(A3 自动补)` 两行原样保留。 | ||
| 31 | + - **每个 REQ** `<REQ-MOD-NNN>.md`:**照模板原样 `Write`**,只把 `{{req_id}}` / `{{title}}` / `{{goal}}` / `{{rules}}` / `{{constraints}}` / `{{acceptance}}` 这 6 个占位替换为据 `index.md` 推断的真实值;模板其余内容(`输入` / `输出` 示例字段表、`依赖表: TBD(A3 自动补)` / `依赖接口: TBD(A5 自动补)` 两行)**原样复制不动**;模板顶部 HTML 引导注释**不写进产物**。 | ||
| 32 | +3. 用 `Edit` 在 `docs/08-模块任务管理.md` 勾选(A1 子项): | ||
| 49 | - ` - [ ] REQ 卡片骨架已生成(docs/01-需求清单/<module>/REQ-*.md,业务内容留待人工填写)` | 33 | - ` - [ ] REQ 卡片骨架已生成(docs/01-需求清单/<module>/REQ-*.md,业务内容留待人工填写)` |
| 50 | -5. 打印「请人工填写 REQ 卡片」横幅并提示用户填完后回来继续(不停止,下一步是 A1 终结校验): | 34 | +4. 打印「请人工填写 REQ 卡片」横幅并提示用户填完后回来继续: |
| 51 | 35 | ||
| 52 | ``` | 36 | ``` |
| 53 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | 37 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| 54 | [scope-lock] REQ 卡片骨架已生成 | 38 | [scope-lock] REQ 卡片骨架已生成 |
| 55 | 39 | ||
| 56 | - 产出: docs/01-需求清单/<module>/{_module.md, REQ-*.md} | 40 | - 产出: docs/01-需求清单/<module>/{_module.md, REQ-*.md} |
| 57 | - - 请逐张填真实字段表, 完成后选「继续」进 A1 终结校验. | 41 | + - 6 个占位已填真实值;输入/输出字段表为模板示例内容(如需可自行调整)。 |
| 42 | + - 审阅后选「继续」进 A1 校验. | ||
| 58 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | 43 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| 59 | ``` | 44 | ``` |
| 60 | 45 | ||
| 61 | -用 `AskUserQuestion` 确认「所有 REQ 卡片的结构化字段都填成真实数据了吗?」,给「继续」和「有疑问想先沟通」两个选项。 | 46 | +用 `AskUserQuestion` 确认「REQ 卡片已生成(6 个占位已填真实值),确认进入 A1 校验吗?」,给「继续」和「有疑问想先沟通」两个选项。 |
| 62 | 47 | ||
| 63 | -- 选「继续」→ 进入步骤 E(A1 终结校验)。 | 48 | +- 选「继续」→ 进入步骤 E。 |
| 64 | - 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 | 49 | - 选「有疑问想先沟通」→ 回答用户问题后,再确认一次。 |
| 65 | 50 | ||
| 66 | -### E. A1 终结校验(硬闸:全部通过才勾选 A1 顶层) | 51 | +### E. A1 校验 |
| 67 | 52 | ||
| 68 | -E.1/E.2/E.3 全过后才勾 A1 顶层。 | 53 | +#### E.1 占位校验(每张 REQ 卡片) |
| 69 | 54 | ||
| 70 | -#### E.1 真实数据校验(每张 REQ 卡片) | 55 | +卡片正文是模板原样复制,只有 6 个 `{{}}` 标量由 CC 填——本步只校验这 6 个占位填全填真。 |
| 71 | 56 | ||
| 72 | 1. 用 `Glob` 列出所有 `docs/01-需求清单/<module>/REQ-*.md`。 | 57 | 1. 用 `Glob` 列出所有 `docs/01-需求清单/<module>/REQ-*.md`。 |
| 73 | 2. 对每张卡片用 `Read` + `Grep` 校验: | 58 | 2. 对每张卡片用 `Read` + `Grep` 校验: |
| 74 | - - **无模板默认占位**:卡片内**不得**出现 `【示例行,替换为真实字段】` 或 `<示例值>`(用 `Grep` 搜这两个字面量,命中即视为未完成)。 | ||
| 75 | - - **结构化字段非空**:`输入字段` / `输出字段` 两张表每行 6 列均非空,且不是模板示例行内容;至少各有 1 行真实字段(除非该 REQ 确实无输入/输出,需在卡片显式标注)。 | ||
| 76 | - - **`示例值` 列已填真实取值**:每行示例值列为真实约束下的合法取值,非占位。 | ||
| 77 | - - **`{{...}}` 残留**:不得残留任何 `{{` 占位(说明渲染未替换)。 | ||
| 78 | -3. 任一卡片不通过:打印不通过的卡片路径 + 具体缺口行,用 `AskUserQuestion` 引导用户当场补齐(可针对具体字段含义/校验规则发问),修订后重跑 E.1,直到全部通过。 | 59 | + - **无 `{{` 残留**:不得残留任何 `{{` 占位(命中即说明 6 个标量未全部替换)。 |
| 60 | + - **6 个标量为真实值**:`req_id` / `title` / `goal` / `rules` / `constraints` / `acceptance` 均据 `index.md` 填为真实内容,非空、非回显占位名。 | ||
| 61 | + - 输入/输出字段表为模板原样复制内容,**不在此校验**。 | ||
| 62 | +3. 任一卡片不通过:打印不通过的卡片路径 + 具体缺口行,用 `AskUserQuestion` 引导用户当场补齐,修订后重跑 E.1,直到全部通过。 | ||
| 79 | 63 | ||
| 80 | -#### E.2 配置字段名锁进 config-vars.yaml(敏感键名引用 .env.local) | 64 | +#### E.2 全部配置锁进 config-vars.yaml(含敏感凭据,单一文件,随项目提交) |
| 81 | 65 | ||
| 82 | 1. 据 `docs/04` § 零 + REQ 卡片盘点配置. | 66 | 1. 据 `docs/04` § 零 + REQ 卡片盘点配置. |
| 83 | -2. `Read` 模板 `${CLAUDE_SKILL_DIR}/templates/config-vars-template.yaml` → `Write` `config-vars.yaml`: 非敏感字段填默认值, 无技术栈整节删, 不可推断留 `【人工填写】`; 敏感字段只把键名+含义登 `secrets_ref`, 不写真实值. | ||
| 84 | -3. `AskUserQuestion` 让用户确认齐全. | 67 | +2. `Read` 模板 `${CLAUDE_SKILL_DIR}/templates/config-vars-template.yaml` → `Write` `config-vars.yaml`: 非敏感字段(包名 / 端口 / 前端包名 / 初始账号等)CC 据上下文填默认值, 无技术栈整节删, 不可推断留 `【人工填写】`; 敏感字段(`database.password` / `admin_init.password` / `secrets.*` 等真实凭据)CC **不臆造**, 一律留 `【人工填写:<说明>】` 占位待人工填. |
| 68 | +3. `AskUserQuestion` 让用户确认非敏感项齐全, 并提示敏感凭据需用户**自己在 config-vars.yaml 填真实值**. | ||
| 85 | 69 | ||
| 86 | #### E.3 build / lint / unit / e2e 命令锁进 docs/04 § 零 | 70 | #### E.3 build / lint / unit / e2e 命令锁进 docs/04 § 零 |
| 87 | 71 | ||
| @@ -93,12 +77,12 @@ E.1/E.2/E.3 全过后才勾 A1 顶层。 | @@ -93,12 +77,12 @@ E.1/E.2/E.3 全过后才勾 A1 顶层。 | ||
| 93 | - **e2e**(端到端测试命令,如 `npm run test:e2e`;无则显式记 `无`) | 77 | - **e2e**(端到端测试命令,如 `npm run test:e2e`;无则显式记 `无`) |
| 94 | 3. 把确认后的命令写入 `docs/04-技术规范.md` § 零(若 § 零无「命令」小节则用 `Edit` 新增一个「命令清单」小节,按 stack 分组列出 build/lint/unit/e2e 四行)。这些命令是 Coding 阶段 `coding.mjs` 的 tdd / test-gate 读取来源,必须在此锁全。 | 78 | 3. 把确认后的命令写入 `docs/04-技术规范.md` § 零(若 § 零无「命令」小节则用 `Edit` 新增一个「命令清单」小节,按 stack 分组列出 build/lint/unit/e2e 四行)。这些命令是 Coding 阶段 `coding.mjs` 的 tdd / test-gate 读取来源,必须在此锁全。 |
| 95 | 79 | ||
| 96 | -#### E.4 全部通过后勾选 A1 顶层并停止 | 80 | +#### E.4 全部通过后勾选 A1 顶层并自动进入 A2 |
| 97 | 81 | ||
| 98 | 三项检查(E.1 / E.2 / E.3)全部通过后: | 82 | 三项检查(E.1 / E.2 / E.3)全部通过后: |
| 99 | 83 | ||
| 100 | 1. 用 `Edit` 在 `docs/08-模块任务管理.md` 勾选 `- [ ] A1 范围锁定 — scope-lock` 顶层项。 | 84 | 1. 用 `Edit` 在 `docs/08-模块任务管理.md` 勾选 `- [ ] A1 范围锁定 — scope-lock` 顶层项。 |
| 101 | -2. 打印 A1 完成横幅并**停止**: | 85 | +2. 打印 A1 完成横幅: |
| 102 | 86 | ||
| 103 | ``` | 87 | ``` |
| 104 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | 88 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| @@ -109,15 +93,15 @@ E.1/E.2/E.3 全过后才勾 A1 顶层。 | @@ -109,15 +93,15 @@ E.1/E.2/E.3 全过后才勾 A1 顶层。 | ||
| 109 | ✓ docs/04 § 零 技术栈 + build/lint/unit/e2e 命令 | 93 | ✓ docs/04 § 零 技术栈 + build/lint/unit/e2e 命令 |
| 110 | ✓ docs/01-需求清单/index.md 模块索引 | 94 | ✓ docs/01-需求清单/index.md 模块索引 |
| 111 | ✓ docs/01-需求清单/<module>/_module.md 模块头 | 95 | ✓ docs/01-需求清单/<module>/_module.md 模块头 |
| 112 | - ✓ docs/01-需求清单/<module>/REQ-*.md 字段表已填真实数据 | ||
| 113 | - ✓ config-vars.yaml 配置字段 + secrets_ref 键名已锁(敏感真实值留待 A2 .env.local) | ||
| 114 | - | ||
| 115 | - 运行以下命令继续进入 A2: | ||
| 116 | - /erp-workflow:plan-start | 96 | + ✓ docs/01-需求清单/<module>/REQ-*.md 6 个占位已填真实值(字段表为模板示例) |
| 97 | + ✓ config-vars.yaml 配置已锁(非敏感已填;DB 凭据 / 密钥占位待人工填,plan-start 把关) | ||
| 117 | 98 | ||
| 99 | + 自动进入 A2:skeleton-gen | ||
| 118 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | 100 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| 119 | ``` | 101 | ``` |
| 120 | 102 | ||
| 103 | +3. 立即调用 `Skill(skeleton-gen)` 进入 A2。 | ||
| 104 | + | ||
| 121 | ## 参考 | 105 | ## 参考 |
| 122 | 106 | ||
| 123 | - `CLAUDE.md` | 107 | - `CLAUDE.md` |
| @@ -129,4 +113,3 @@ E.1/E.2/E.3 全过后才勾 A1 顶层。 | @@ -129,4 +113,3 @@ E.1/E.2/E.3 全过后才勾 A1 顶层。 | ||
| 129 | - `${CLAUDE_SKILL_DIR}/templates/config-vars-template.yaml` | 113 | - `${CLAUDE_SKILL_DIR}/templates/config-vars-template.yaml` |
| 130 | - `${CLAUDE_SKILL_DIR}/templates/req-card-template.md` | 114 | - `${CLAUDE_SKILL_DIR}/templates/req-card-template.md` |
| 131 | - `${CLAUDE_SKILL_DIR}/templates/_module-template.md` | 115 | - `${CLAUDE_SKILL_DIR}/templates/_module-template.md` |
| 132 | -- `${CLAUDE_PLUGIN_ROOT}/lib/render.mjs` |
skills/plan/scope-lock/templates/req-card-template.md
| @@ -5,17 +5,44 @@ req-card-template:单张 REQ 卡片骨架。两处 `TBD(A3 自动补)` / `TBD( | @@ -5,17 +5,44 @@ req-card-template:单张 REQ 卡片骨架。两处 `TBD(A3 自动补)` / `TBD( | ||
| 5 | 5 | ||
| 6 | **目标**: {{goal}} | 6 | **目标**: {{goal}} |
| 7 | 7 | ||
| 8 | -**输入字段**: | 8 | +- **输入**: 用户提交用户名(3-20 位字母数字下划线,系统内唯一)、姓名(2-50字符)、手机号(11 位数字,系统内唯一)、邮箱(标准邮箱格式,可选)、初始密码(8-20位含大小写字母和数字) |
| 9 | 9 | ||
| 10 | -| 字段名 | 类型 | 必填 | 校验规则 | 业务规则 | 示例值 | | ||
| 11 | -| --- | --- | --- | --- | --- | --- | | ||
| 12 | -| {{input_field_name}} | {{input_field_type}} | {{input_field_required}} | {{input_field_validation}} | {{input_field_business}} | {{input_field_example}} | | 10 | + - **表1**: |
| 11 | + | ||
| 12 | + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 预加载 | 默认值 | 业务规则 | | ||
| 13 | + | ---- | ---- | --- | ---- | ----- | --- | --- | ------------------- | | ||
| 14 | + | 用户名 | 文本 | 是 | 手工输入 | `职员表` | 否 | — | 3-20 位字母数字下划线;系统内唯一 | | ||
| 15 | + | 姓名 | 文本 | 是 | 下拉单选 | `职员表` | 用户操作时 | — | 2-50 个字符 | | ||
| 16 | + | 手机号 | 文本 | 是 | 手工输入 | `职员表` | 否 | — | 11 位数字;系统内唯一 | | ||
| 17 | + | 邮箱 | 文本 | 否 | 手工输入 | `职员表` | 否 | — | 标准邮箱格式 | | ||
| 18 | + | 角色 | 文本 | 是 | 下拉单选 | 普通用户/超级管理员 | 页面加载时 | 普通用户 | 至少选择 1 个 | | ||
| 19 | + | 初始密码 | 文本 | 是 | 手工输入 | — | — | — | 8-20 位;含大小写字母和数字;显示星号 | | ||
| 13 | 20 | ||
| 14 | -**输出字段**: | 21 | + - **表2**: |
| 15 | 22 | ||
| 16 | -| 字段名 | 类型 | 必填 | 校验规则 | 业务规则 | 示例值 | | ||
| 17 | -| --- | --- | --- | --- | --- | --- | | ||
| 18 | -| {{output_field_name}} | {{output_field_type}} | {{output_field_required}} | {{output_field_validation}} | {{output_field_business}} | {{output_field_example}} | | 23 | + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 预加载 | 默认值 | 业务规则 | |
| 24 | + | --- | --- | --- | --- | --- | --- | --- | --- | | ||
| 25 | + | 用户名 | 文本 | 是 | 手工输入 | `职员表` | 否 | — | 3-20 位字母数字下划线;系统内唯一 | | ||
| 26 | + | 姓名 | 文本 | 是 | 下拉单选 | `职员表` | 用户操作时 | — | 2-50 个字符 | | ||
| 27 | + | 手机号 | 文本 | 是 | 手工输入 | `职员表` | 否 | — | 11 位数字;系统内唯一 | | ||
| 28 | + | ||
| 29 | +- **输出**: 返回用户 id | ||
| 30 | + | ||
| 31 | + - **表1**: | ||
| 32 | + | ||
| 33 | + | 字段 | 类型 | 显示来源 | | ||
| 34 | + | --- | --- | --- | | ||
| 35 | + | 用户名 | 文本 | `职员表` | | ||
| 36 | + | 姓名 | 文本 | `职员表` | | ||
| 37 | + | 角色 | 文本 | `职员表` | | ||
| 38 | + | ||
| 39 | + - **表2**: | ||
| 40 | + | ||
| 41 | + | 字段 | 类型 | 显示来源 | | ||
| 42 | + | --- | --- | --- | | ||
| 43 | + | 用户名 | 文本 | `职员表` | | ||
| 44 | + | 姓名 | 文本 | `职员表` | | ||
| 45 | + | 角色 | 文本 | `职员表` | | ||
| 19 | 46 | ||
| 20 | - **跨字段规则**: {{rules}} | 47 | - **跨字段规则**: {{rules}} |
| 21 | - **边界**: {{constraints}} | 48 | - **边界**: {{constraints}} |