将项目级的 Ratchet/约定检测方法论融入 req-test-gate 技能, 通过 /req 流程三个节点自动触发(dev 环境检测、cr 约定建议、test Gate 0B), 无需手动记忆执行。 新增文档:harness-engineering.md、ratchet-pattern.md、convention-flow.md、 project-bootstrap.md 及 4 个模板(ratchet/convention 脚本、GATES.md、pre-commit)。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.3 KiB
Convention Flow — 约定建立流程
核心理念
每个 bug 都是一个建立约定的机会。 修复 bug 后,立即将教训固化为自动化检测,防止同类问题再次出现。
流程总览
Step 1: 修 Bug → 标准修复,代码层面解决问题
↓
Step 2: 文档化约定 → 写入 CLAUDE.md(让 AI 和人都知道这条规则)
↓
Step 3: 自动化检测 → 创建 scripts/check-*.sh(让 CI 自动阻止违规)
↓
Step 4: 记录追踪 → 创建【约定】任务关联需求(仅 /req cr 自动触发时)
Step 1-3 是核心流程(手动和自动都执行)。Step 4 仅在
/req cr自动触发时执行,用于在 ai-proj 中留痕。
Step 1: 修 Bug
标准的 bug 修复流程。此步骤无特殊要求。
Step 2: 文档化约定
在项目的 CLAUDE.md 中添加约定段落,格式参见 harness-engineering.md 的「CLAUDE.md 约定文档格式」。
必须包含:
- 原因描述(为什么这是个问题)
- 一句话规则
- 正例和反例代码
- 检查命令
Step 3: 自动化检测
创建 scripts/check-{name}.sh 脚本:
- 扫描代码库查找违反约定的模式
- 输出违规文件和行号
- 支持
--ci模式(退出码 0/1) - 零违规时输出 PASSED 消息
Step 4: 记录追踪(自动触发时)
当 convention flow 由 /req cr 自动触发时,产出物必须关联到当前需求:
ai-proj task create --title "【约定】{约定名称}"
ai-proj req link --id <req_id> --task-ids <task_id> # linkRole=documentation
ai-proj create-and-attach --id <task_id> --content "..." # 约定详情文档
约定详情文档内容:
## 约定: {名称}
| 字段 | 值 |
|------|-----|
| 来源需求 | REQ-XXXX |
| 触发 bug | {bug 描述} |
| 根因模式 | {代码模式} |
| 策略 | {hard wall / ratchet(N)} |
| 现有违规 | {N} 处 |
### 产出物
- CLAUDE.md 约定段落: ✅ 已添加
- 检测脚本: `scripts/check-{name}.sh` ✅ 已创建
- 首次运行结果: PASS
### 约定规则
{规则内容,与 CLAUDE.md 中一致}
这样在需求归档时能看到:这个 bug 不仅被修了,还产出了一条防止复发的约定。
Commit 策略
Convention flow 的产出物(CLAUDE.md 修改 + scripts/check-*.sh 新脚本)必须单独提交,不与 bug fix 代码混在一起:
# 1. Bug fix 已经提交
git add src/...
git commit -m "fix: 修复 Modal 重叠导致弹窗无法关闭"
# 2. Convention 产出物单独提交
git add CLAUDE.md scripts/check-modal-safety.sh
git commit -m "chore: 建立 Modal 安全约定和自动检测"
原因:
- bug fix 可能需要 cherry-pick 到其他分支,约定脚本不应跟着走
- 约定提交的 review 焦点不同(规则是否合理 vs 代码是否正确)
git log --oneline scripts/可以快速看到所有约定建立历史
可检测性判断
/req cr 自动触发时,AI 必须先判断 bug 根因是否能自动检测。判断标准:
可检测(建议约定) — 根因是一个代码模式,能用 grep/regex 在源码中匹配:
| 模式类别 | 示例 | grep 可行性 |
|---|---|---|
| API 误用 | Modal.success() 后直接 setState |
grep Modal.success + 上下文检查 |
| 禁止导入 | handler 直接 import database 层 | grep import 路径 |
| 缺失守卫 | SQL 拼接而非参数化查询 | grep 字符串拼接模式 |
| 遗漏回调 | Promise 无 .catch() |
grep .then( 无配对 .catch |
| 硬编码 | 密钥/密码直接写在代码中 | grep 常见密钥模式 |
不可检测(仅记录根因) — 根因是逻辑/设计问题,代码形态上看不出来:
| 模式类别 | 示例 | 为什么不行 |
|---|---|---|
| 算法错误 | 排序方向反了、边界条件漏了 | 代码语法正确,逻辑错误 |
| 业务规则遗漏 | 退款应该校验订单状态但没校验 | 缺失的代码无法被 grep |
| 竞态条件 | 两个请求并发修改同一资源 | 需要运行时才能暴露 |
| 配置错误 | 环境变量填错、超时值设太小 | 值的正确性取决于上下文 |
快速判断法:问自己「能不能写一条 grep 命令找到所有同类问题?」能 → 可检测,不能 → 不可检测。
选择策略
修完 bug 后,根据当前违规数量选择不同策略:
| 现有违规数 | 策略 | 脚本类型 | 说明 |
|---|---|---|---|
| 0 | Hard wall | 纯检测脚本(有 → FAIL) | 刚修完最后一个违规,或首次建立 |
| 1-10 | Ratchet + 排期清理 | Ratchet 脚本 + 基线 | 创建任务逐一清理遗留 |
| >10 | Ratchet only | Ratchet 脚本 + 基线 | 不立即清理,仅防止恶化 |
| 不可计数 | 仅检测/告警 | 告警脚本(exit 0) | 如"代码风格"类软约定 |
实例 1: Modal 安全规则
Bug:Ant Design Modal.success() 非阻塞,后续 setState 立即执行导致两个 modal 重叠,第一个无法关闭。
Step 1 — 修 Bug:
将 setNextModalOpen(true) 移入 onOk 回调。
Step 2 — 文档化: 在 CLAUDE.md 添加:
### Frontend: Modal 安全规则
Ant Design 的 `Modal.success()` / `Modal.info()` 是**非阻塞**调用。
**规则:`Modal.success/info/warning/error` 之后如果还有 UI 操作,必须放在 `onOk` 回调中。**
// WRONG — 两个 modal 同时弹出
Modal.success({ title: '成功' });
setNextModalOpen(true);
// CORRECT — 等用户确认后再打开
Modal.success({ title: '成功', onOk: () => setNextModalOpen(true) });
**检查命令**:`./scripts/check-modal-safety.sh`
Step 3 — 自动化:
创建 scripts/check-modal-safety.sh:
- 扫描
.tsx文件中的Modal.success/info/warning/error调用 - 检查 25 行内是否有
onOk回调 - 如果没有且后续 20 行内有
set*Open(true),标记为违规 - 策略:现有违规 = 0 → Hard wall
实例 2: 架构层级约束
问题:Handler 直接调用 database 层,绕过 service 层导致业务逻辑散落。
Step 1 — 识别问题: 发现 108 个 handler 直接 import database 的文件。
Step 2 — 文档化:
在 CLAUDE.md 和 docs/architecture/LAYER_RULES.md 中描述依赖矩阵和正反示例。
Step 3 — 自动化:
创建 scripts/check-architecture.sh(ratchet 脚本):
- 5 条规则,3 个 ratchet + 2 个 hard wall
- 基线记录各规则的当前违规数
- 策略:遗留 108 个 → Ratchet(只能减不能增)
执行流程
自动触发(/req cr + bug 类需求)
触发条件(满足任一):
category == bug- category 为空但标题含
fix、修复、bug、问题、缺陷 - category 为空但 description 含
根因、复现步骤
1. /req cr 五视角扫描完成后
2. 检测是否为 bug 类需求(按上述条件判断)
3. 分析本次 bug 的根因模式(从 git diff 提取)
4. 判断:根因是否可自动检测?(判断规则见上方「可检测性判断」)
- 不可检测 → 仅在 CR 报告记录根因,不建议约定 → 结束
- 可检测 → 继续下一步
5. 检查是否已有覆盖此模式的脚本:
- ls scripts/check-*.sh,读取每个脚本的注释头(# ... detects ...)
- 已有覆盖 → CR 报告记录「已有约定: check-{name}.sh」→ 结束
- 无覆盖 → 继续下一步
6. 扫描代码库统计同类模式的现有数量(N)
7. AskUserQuestion(按 N 值调整措辞):
- N=0: 「此 bug 模式已修复,当前代码无同类问题。建立约定可防止未来复发,是否建立?」
- N>0: 「代码库中还有 {N} 处同类模式。建立约定可防止恶化 + 逐步清理,是否建立?」
- 否 → 记录到 CR 报告「约定建议:用户跳过」
- 是 → 执行 convention flow(Step 2 + Step 3 + Step 4)
8. 约定产出物关联到当前需求(Step 4)
9. 约定检查结果写入 CR 报告
手动触发(/harness convention [name])
1. 询问约定名称和类别(如果未提供)
2. 分析刚修复的 bug,提取约定规则
3. 扫描代码库统计现有违规数量
4. 根据违规数量选择策略
5. 生成 CLAUDE.md 约定段落
6. 生成 scripts/check-{name}.sh 脚本
7. 运行脚本验证(应该 PASS)
8. 输出摘要:约定名称、策略、违规数、文件清单