将项目级的 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>
223 lines
8.3 KiB
Markdown
223 lines
8.3 KiB
Markdown
# 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](harness-engineering.md) 的「CLAUDE.md 约定文档格式」。
|
||
|
||
**必须包含**:
|
||
- 原因描述(为什么这是个问题)
|
||
- 一句话规则
|
||
- 正例和反例代码
|
||
- 检查命令
|
||
|
||
### Step 3: 自动化检测
|
||
|
||
创建 `scripts/check-{name}.sh` 脚本:
|
||
|
||
1. 扫描代码库查找违反约定的模式
|
||
2. 输出违规文件和行号
|
||
3. 支持 `--ci` 模式(退出码 0/1)
|
||
4. 零违规时输出 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 "..." # 约定详情文档
|
||
```
|
||
|
||
**约定详情文档内容**:
|
||
```markdown
|
||
## 约定: {名称}
|
||
|
||
| 字段 | 值 |
|
||
|------|-----|
|
||
| 来源需求 | 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 代码混在一起:
|
||
|
||
```bash
|
||
# 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 添加:
|
||
```markdown
|
||
### 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. 输出摘要:约定名称、策略、违规数、文件清单
|
||
```
|