name: add-req description: 增量需求入口——初始 Plan 完结后追加 / 修改需求时运行。基于 lib/req-ledger.mjs 内容哈希台账识别新增 / 变更的 REQ 卡片、FE 行与原型快照(prototype/*/.html),只对增量做 A3-delta(写 V_n migration + 同步 docs/03,绝不改 V1)+ A5-delta(补 docs/05 端点 / docs/02 顺序 / docs/08 模块行),并作废变更单元已有的 req-done/milestone tag——新增单元同样复位其所属模块/前端阶段的里程碑(否则 Router 判 done 整个跳过),原型变更先按 git diff 收敛到受影响 FE、收敛不了才整体重跑前端阶段,使 coding.mjs Router 只重跑增量、不必整仓重跑。 user-invocable: true
allowed-tools: Read Write Edit Grep Glob AskUserQuestion Bash(node *) Bash(git *) Bash(ls *) Bash(mkdir *)
所有输出必须使用中文。
add-req — 增量需求识别与生成
用于初始 Plan(A0~A5)已完结之后,往项目里追加新需求或修改已有需求。不重跑整条 Plan,只处理增量;产出与 A1/A3/A5 完全一致,交由 coding.mjs Router 增量编码。
用法约定:先人工在
docs/01-需求清单/里把新 REQ 卡片写好(真实业务内容,同 A1 填法)或修改已有卡片,再运行/erp-workflow:add-req。本 skill 负责「识别 + 下游生成 + 作废过期完成标记」,不替你写业务需求本身。微改分流:若只是给已有表追加一个纯展示/录入字段(ADD COLUMN + 界面呈现,不改业务逻辑/端点),走
/erp-workflow:quick-field;若只是已有页面加个纯前端小交互(只消费既有端点,不新增页面/路由),走/erp-workflow:quick-ui。两者都保 SSoT 但不作废 tag、不重跑 coding.mjs。语义变更 / 新端点 / 新页面 / 类型变更仍走本 skill。
<root> = 项目根(含 docs/、config-vars.yaml、sql/、.git)。${CLAUDE_PLUGIN_ROOT} = 插件根。
前置:Plan 必须已完结
用 Read 读 docs/08-模块任务管理.md § 一。若 § 一存在任一 - [ ] 未勾子项 → 初始 Plan 未完结,停下并提示:
[add-req] ⛔ 初始 Plan(A0~A5)尚未完结,增量入口暂不可用。
请先运行 /erp-workflow:plan-start 完成初始规划,再用 /add-req 追加需求。
[ERP-HALT] 初始 Plan 未完结,已停下。
步骤 0:台账基线(首次启用 / 老项目迁移)
node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan <root>
解析输出 JSON 的 ledgerExists:
-
false(项目还没有.req-ledger.json)→ 这是首次启用增量台账。先建基线并提交:node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs commit <root> git -C <root> add .req-ledger.json git -C <root> commit -m "chore(req-ledger): 建立需求台账基线"(.req-ledger.json必须 git 提交——否则它是未提交的脏文件,后续coding-start起 coding.mjs 时会撞「工作树必须干净」前置。)然后打印并停下:[add-req] 已为现有 <N> 个需求单元建立台账基线(.req-ledger.json)。 首次基线无法区分存量与新增,故本次不做增量生成。 请在 docs/01 追加 / 修改需求后,再次运行 /erp-workflow:add-req。 [ERP-HALT] 基线已建立,等待人工追加需求。(理由:首跑若把存量全当新增,会重复生成已有的 docs/03/05 工件并误重跑整仓。基线建立后,后续改动才能被准确 diff。) -
true→ 直接用本次 scan 的输出进入步骤 1 解析(不再重跑 scan)。
步骤 1:检测增量
用步骤 0 已得到的 scan 输出解析 new[] / changed[] / removed[](每项 {id, kind},kind = req 后端卡片 / fe 前端功能行 / proto 原型快照——全部 prototype/**/*.html 聚成的单一单元,id 固定 __prototype__)。
原型变更(kind=proto):原型是前端布局/页面/交互的权威,但 FE 行只哈希行文字,改原型而 FE 行文字不变时旧台账检测不到。
__prototype__单元把所有原型 html 内容纳入哈希,任一原型文件改动即被识别。老项目首次升级到带原型跟踪的台账时,__prototype__会作为new出现(无历史哈希可比)——此为基线建立,步骤 5 不作废任何 tag,步骤 6 提交后才成基线;其后再改原型才会显示为changed并触发前端重跑。
-
new与changed均为空 → 打印[add-req] 无新增 / 变更需求,无需处理。[ERP-HALT]停下(不提交台账)。 -
removed非空 → 仅提示、不自动删:打印检测到台账登记但 docs 已移除的单元:<列出>。下线需求请人工同步 docs/02/03/05 并删除对应 tag,本 skill 不自动执行删除。然后继续处理 new/changed(removed 不写回台账,留待人工,下次仍会提示)。
步骤 2:校验新增 / 变更 REQ 卡真实数据(仅 kind=req)
对 new ∪ changed 里 kind=req 的每个 id(卡片路径 docs/01-需求清单/<module>/<id>.md):Read + Grep 校验无 {{ 残留、无 【人工填写(同 A1 E.1)。命中缺口 → 打印卡片路径 + 缺口行,用 AskUserQuestion 引导用户补齐后重检,直到全部为真实数据。
(kind=fe 的增量行来自 docs/08 §三 推导,不在此校验。)
步骤 3:A3-delta — schema 增量(仅当新增/变更 REQ 影响数据模型)
对 new/changed 的 REQ 卡片,判断是否需要新表或给已有表加列(依据卡片业务 + 依赖表):
-
写增量 migration(绝不改 V1 或任何已存在 V_n):
-
ls sql/migrations/V*.sql取当前最大版本号n,新文件sql/migrations/V<n+1>__<snake_case_desc>.sql(如V2__add_order_refund.sql)。 - 新表 →
CREATE TABLE;给已有表加列 →ALTER TABLE ... ADD COLUMN。追加式,套用与 A3/A4 相同的命名规范、匈牙利列前缀(i/s/t/b/d)、标准列约定(主表 15 列 / 从表 12 列 / 基础 11 列)与 DDL 默认值翻译规则(见CLAUDE.mdSchema 演化规约 + db-init 约定)。
-
-
同步 docs/03:参照
${CLAUDE_PLUGIN_ROOT}/skills/plan/db-design-gen/templates/docs-03-table-template.md,新表追加表小节 / 已有表小节增列,保持 docs/03 为 schema SSoT。 -
回填卡片:把该 REQ 卡片
依赖表:的TBD/ 占位Edit成实际表名。 -
增量 DDL 校验(fail-closed):写完 V_n + 同步 docs/03 后,对全部 migration 的累积并集校验 docs/03 一致:
node ${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs docs/03-数据库设计文档.md sql/migrations/V*.sql(validate-ddl 已支持多文件:CREATE TABLE + 各 V_n 的ALTER ... ADD并集 ↔ docs/03 累积 SSoT 做 4 维比对。)- 退出码
0→ 一致,继续。 - 退出码
1→ docs/03 与 migration 并集分叉(stderr 有 diff 明细):就地修正——通常是 docs/03 表小节/列与 V_n 不一致,或 V_n 漏写某列的 ALTER。修正后重跑校验,直到0。绝不带分叉进入步骤 4(schema 不一致会让下游 docs/05/编码全线偏)。 - 仅 ADD 追加式——校验器对
MODIFY/CHANGE/DROP/RENAME子句硬拒(exit 1),不静默放行。改类型/重命名/删列不在 add-req 覆盖范围:需人工写 V_n 并人工核对 docs/03 一致性。
- 退出码
不在此 apply 到数据库:新 schema 由 Coding 阶段冷起栈时 Flyway 自动 apply 全部
V*.sql;本步只做静态 DDL↔docs/03 一致性校验,运行时 apply 与 Seed 真跑由 Coding 阶段兜底。
步骤 4:A5-delta — 下游文档增量(每个新增 REQ)
对 new 的 kind=req:
-
docs/05 端点:参照
${CLAUDE_PLUGIN_ROOT}/skills/plan/downstream-gen/templates/docs-05-endpoint-template.md追加该 REQ 的接口小节(对齐 docs/06 实现策略的分页/鉴权/响应包络/错误码风格)。 -
docs/02 顺序:把该 REQ 按依赖拓扑插入
docs/02-开发计划.md顺序清单,同模块 REQ 保持连续;环依赖按启发式破环并在note注明。 -
回填卡片:
依赖接口:的TBD/ 占位Edit成实际 endpoint。 -
docs/08 §二:
- 该 REQ 属新模块 → 参照
${CLAUDE_PLUGIN_ROOT}/skills/plan/downstream-gen/templates/docs-08-module-row-template.md追加模块 bullet,里程碑:字段填—。 - 属已有模块 → 在该模块 bullet 下追加该 REQ 子项行。
- 该 REQ 属新模块 → 参照
对 changed 的 kind=req:若接口/字段语义变化,相应 Edit docs/05 端点小节、按需调整 docs/02(一般顺序不变)。
前端增量:若新增需求带来新前端功能,Glob prototype/**/*.html 确认有原型后,用 AskUserQuestion 与用户确认是否新增 FE 行;新增则在 docs/08 §三 「功能:」下追加 - [ ] FE-NN <功能名>(NN 取现有最大值+1)。
步骤 5:作废变更单元的完成标记(关键——否则 Router 会跳过)
对每个 changed 单元处理功能级 tag + 所属模块里程碑;对每个 new 单元只处理所属模块里程碑(新单元自身无 tag 可删,但它挂靠的模块可能已 done——不复位就会被 Router 整模块跳过):
-
kind=req(
changed):-
git -C <root> tag -l "req-done/<id>"存在 →git -C <root> tag -d req-done/<id>。 - 该 REQ 所属后端模块若已打里程碑(
git -C <root> tag -l "milestone/<module_id>"存在)→git -C <root> tag -d milestone/<module_id>,并Editdocs/08 §二该模块里程碑:字段从milestone/<module_id>复位为—。(否则 Router 判定模块 done 而整模块跳过,改动不会重跑。)
-
-
kind=req(
new):新 REQ 无req-donetag 可删,但若步骤 4 把它挂进了已有模块,必须同样复位该模块里程碑:- 从步骤 4 的 docs/08 §二 落点确定所属
<module_id>(新建模块的里程碑字段本就是—,跳过本条)。 -
git -C <root> tag -l "milestone/<module_id>"存在 →git -C <root> tag -d milestone/<module_id>,并Editdocs/08 §二该模块里程碑:字段复位为—。 -
为何必须:
routerPrompt判done = 里程碑字段匹配 且 tag 存在,且「模块已 done →reqs空数组」;coding.mjs的todo = routed.modules.filter(m => !m.done)又把 done 模块整个剔出待跑列表。漏掉这步 → 新 REQ 不报错、不 halt,就是永远不跑。
- 从步骤 4 的 docs/08 §二 落点确定所属
-
kind=fe(
changed):-
git -C <root> tag -l "req-done/<FE-NN>"存在 → 删。 - 前端阶段若已
milestone/frontend-phase→ 删该 tag,并Editdocs/08 §三整体里程碑:复位—。
-
kind=fe(
new):新 FE 行无req-donetag 可删,但前端阶段若已milestone/frontend-phase,同样要删该 tag 并把docs/08 §三整体里程碑:复位—(否则 Router 判前端阶段 done,新 FE 不跑)。只删里程碑,不动任何既有req-done/FE-*——那些 FE 没变,让它们保持 done,Router 的feItems便只含新 FE。kind=proto(
changed)(__prototype__,原型快照变更):__prototype__是把全部原型 html 聚成的单一单元,只能告诉你「原型变了」,不能告诉你变的是哪个文件、影响哪些 FE。故先把范围还原到文件级再收敛到 FE 级,收敛不了才整体重跑。
milestone/frontend-phase 无论走哪条路径都要删:git -C <root> tag -l "milestone/frontend-phase" 存在 → git -C <root> tag -d milestone/frontend-phase,并 Edit docs/08 §三 整体里程碑: 复位 —。(否则 Router 判前端阶段 done,什么都不会跑。)差别只在删哪些 req-done/FE-*:
-
取基线 commit:
git -C <root> log -1 --format=%H -- .req-ledger.json(台账由步骤 6 随增量产物一并提交,故它最后一次被改动的 commit 就是上次 add-req 的基线)。无输出(台账从未提交 / 首次建立基线)→ 跳到第 4 条整体重跑。 -
取变更原型文件:
git -C <root> diff --name-only <基线commit> -- prototype/。命令失败或结果为空 → 第 4 条整体重跑。 -
映射到 FE 行:
Read这些原型文件 +docs/08 §三FE 清单,判定每个变更文件影响哪些FE-NN,然后用AskUserQuestion把「变更文件 → 受影响 FE」的判定结果交用户确认,并始终提供「说不准,整体重跑」选项。- 用户确认了受影响 FE 集合 → 只删这些
req-done/FE-<NN>,其余 FE 保持 done。Router 的feItems于是只含受影响 FE,coding.mjs的runPrototypePreview/featureLoop/runBehaviorGate全部按feItems伸缩,前端阶段成本随之收敛。 - 用户选「说不准」→ 第 4 条。
-
纯新增原型文件(新界面,对应步骤 4 刚追加的新 FE 行)是最干净的情形:受影响集合 = 新 FE,既有
req-done/FE-*一个都不用删。
- 用户确认了受影响 FE 集合 → 只删这些
-
回退:整体重跑(保守路径,语义同本次改动之前)——删全部前端功能完成 tag:
git -C <root> tag -l "req-done/FE-*"列出后逐个git -C <root> tag -d <tag>(Router 据req-done/<FE-NN>缺失把 FE 收回frontend-phase,单删 milestone 不够)。 - (若曾开
frontendOverlap:对上面实际删掉的那些 FE,同时删对应的fe-code-done/FE-<NN>(整体重跑则git -C <root> tag -l "fe-code-done/FE-*"全删),复位 phase1 重叠状态。缺省关时无此 tag,跳过。)
收窄的是重跑范围,不是验收强度:受影响 FE 仍走完整流水线(Preview → featureLoop → Behavior 行为门 → testGate 全量回归)。未受影响的 FE 保持既有
req-done,其行为验收证据来自上一轮,且步骤末尾的testGate本就是全量回归,会兜住任何跨 FE 的连带回归。
-
kind=proto(
new):唯一例外,不作废任何 tag——__prototype__作为new出现只发生在老项目首次升级到带原型跟踪的台账时(无历史哈希可比),此为基线建立而非真实变更,见步骤 3 的说明。
逐条记录已删的 tag,供步骤 6 横幅汇总。
步骤 6:更新台账 + git 提交全部增量产物 + 完成横幅
-
把当前哈希写回
.req-ledger.json(new/changed 单元自此成为新基线):node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs commit <root> -
git 提交本次全部增量产物(关键——否则工作树脏,
coding-start起 coding.mjs 时会撞runBranchSetup/runMilestone的「工作树必须干净」前置,导致 HALT 或被误并进功能分支)。在当前分支(默认分支)提交:git -C <root> add docs/01-需求清单 docs/02-开发计划.md docs/03-数据库设计文档.md docs/05-API接口契约.md docs/08-模块任务管理.md sql/migrations .req-ledger.json git -C <root> commit -m "plan(add-req): 增量需求 <新增/变更 id 摘要>(docs/03+05+02+08 delta + V_n + 台账)"- 覆盖范围 = 步骤 2~5 实际改动的全部文件:人工新写的 REQ 卡(docs/01)、新增 migration(sql/migrations/V_n)、同步的 docs/03、补的 docs/05/02 端点与顺序、docs/08 模块行/FE 行与复位的里程碑字段、
.req-ledger.json。 - 步骤 5 的
git tag -d(删 req-done/milestone)是对 ref 的操作,不产生工作树文件,不需进本 commit。 - commit 后用
git -C <root> status --porcelain复核工作树干净(无残留);若仍有未跟踪/未提交项,排查后补提交,确保交给 coding-start 时是干净树。
- 覆盖范围 = 步骤 2~5 实际改动的全部文件:人工新写的 REQ 卡(docs/01)、新增 migration(sql/migrations/V_n)、同步的 docs/03、补的 docs/05/02 端点与顺序、docs/08 模块行/FE 行与复位的里程碑字段、
然后打印横幅并停下(不自动进编码,与「Plan 完不自动进 B」一致):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[add-req] ✅ 增量需求已处理
新增 REQ:<列出 id 或 无>
变更 REQ:<列出 id 或 无>
新增 FE :<列出 FE-NN 或 无>
原型变更:<是(前端阶段整体重跑)/ 否>
新增 migration:<V_n 文件名 或 无>
作废 tag:<列出已删的 req-done/* 与 milestone/* 或 无>
台账已更新并随全部增量产物 git 提交(工作树干净)。
运行 /erp-workflow:coding-start 增量编码(Router 只跑缺 tag 的模块/功能)。
注:增量编码的 test-gate 只跑本轮改动关联的 e2e(省时);跨功能连带回归
请在一批需求做完 / 合并前跑 /erp-workflow:full-test 兜一次全量。
[ERP-HALT] 增量处理完成,已停下(不自动进编码)。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
参考
-
${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs(台账:scan / commit) -
${CLAUDE_PLUGIN_ROOT}/lib/validate-ddl.mjs(增量 DDL↔docs/03 校验,支持多 V 文件累积并集) -
docs/01-需求清单/<module>/<req_id>.md(REQ SSoT,人工先填) -
docs/03-数据库设计文档.md+sql/migrations/V*.sql(schema 演化,追加 V_n) -
docs/05-API接口契约.md/docs/02-开发计划.md/docs/08-模块任务管理.md(下游增量) -
CLAUDE.mdSchema 演化规约(V1 永不改,增量走 V_n) - 跨 skill 模板:
${CLAUDE_PLUGIN_ROOT}/skills/plan/db-design-gen/templates/docs-03-table-template.md、${CLAUDE_PLUGIN_ROOT}/skills/plan/downstream-gen/templates/{docs-05-endpoint-template.md,docs-08-module-row-template.md}