feat(req-test-gate): 集成 Harness Engineering 工程约束方法论
将项目级的 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>
This commit is contained in:
@@ -138,10 +138,49 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-prototype-plugin",
|
||||
"source": "./skills-req/req-prototype-plugin",
|
||||
"description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-review-plugin",
|
||||
"source": "./skills-req/req-review-plugin",
|
||||
"description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-test-gate-plugin",
|
||||
"source": "./skills-req/req-test-gate-plugin",
|
||||
"description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5,含前后端联调+视觉验证)、部署级验证(Deploy Gates)、持续回归(Regression)。",
|
||||
"description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5)、部署级验证(Deploy Gates)、持续回归(Regression)、Harness Engineering 工程约束方法论(Ratchet、约定建立、门禁层级)。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-workflow-plugin",
|
||||
"source": "./skills-req/req-workflow-plugin",
|
||||
"description": "需求完整工作流。从创建到归档的完整流程、Hook 自动同步、测试环境流程。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
|
||||
@@ -808,3 +808,9 @@ fi
|
||||
4. **小步提交** - 频繁提交,每次做一件事
|
||||
5. **测试覆盖** - 核心逻辑必须有测试
|
||||
6. **文档同步** - 代码变更同步更新文档
|
||||
|
||||
## 相关技能
|
||||
|
||||
| 技能 | 用途 | 关系 |
|
||||
|------|------|------|
|
||||
| `req-test-gate` | 测试与质量门禁 + Harness Engineering | 建立项目质量门禁和约定自动检测,dev-coding 遵守其建立的 CLAUDE.md 约定 |
|
||||
|
||||
@@ -47,6 +47,7 @@ analysis → design → dev → review → testing → [待部署池] → releas
|
||||
- **操作前先确认实际 ID** — 从 URL 提取 ID(如 `/requirements/897` → ID=897)
|
||||
- **务实路线关闭也必须补全关联任务** — 每个进度条阶段需创建关联任务
|
||||
- **阶段内容门禁(防空转)** — `/req next` 时检查关键阶段任务是否有实质内容
|
||||
- **Harness 环境检测** — `/req dev` 启动开发前,快速检测项目基础设施(`.husky/` 存在?`scripts/check-*.sh` 存在?)。若两者都不存在(Level 0),输出一行提示:「项目无质量护栏,建议先运行 `/harness init`」。检测结果不阻塞开发,仅提示
|
||||
|
||||
## 禁止直接调用(必须走命令流程)
|
||||
|
||||
@@ -92,13 +93,15 @@ Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD
|
||||
6. /req next → 推进到 design/dev 阶段
|
||||
7. /req dev → 启动开发(创建【开发】任务, delivery_stage=dev)
|
||||
8. /req next → 推进到 review 阶段
|
||||
9. /req cr → 代码评审(创建【代码评审】任务)
|
||||
9. /req cr → 代码评审 + 约定检查 + bug约定建议(⭐ harness 自动)
|
||||
10. /req next → 推进到 testing 阶段
|
||||
11. /req test → 测试验收(5-Gate 流程)
|
||||
11. /req test → 测试验收(Gate 0B 约定检查 ⭐ + Gate 1-5)
|
||||
12. /req deploy → 批量部署(build-and-push.sh → Jenkins ai-proj)
|
||||
13. /req done → 归档 (archived) + git commit + push
|
||||
```
|
||||
|
||||
> ⭐ 标记的步骤是 Harness Engineering 自动嵌入的,无需手动调用。
|
||||
|
||||
**5 阶段文档**:
|
||||
|
||||
| 阶段 | 文档名 | 技能 |
|
||||
@@ -287,10 +290,19 @@ Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD
|
||||
2. `git diff` / `find` 确定变更范围(文件数、行数)
|
||||
3. 读取所有变更文件源码(非 test 文件)
|
||||
4. **五视角扫描**:逐一用攻击者/泄露者/并发者/边界者/依赖者视角审查
|
||||
5. `ai-proj task create` 创建【代码评审】任务并关联需求(linkRole=code_review)
|
||||
6. `ai-proj create-and-attach` 附加 CR 报告文档(必须含五视角扫描结果)
|
||||
7. 展示发现摘要,AskUserQuestion 确认是否创建 bug 修复任务
|
||||
8. 若有 High/Critical 发现 → `ai-proj task create` 创建关联修复任务
|
||||
5. **约定检查**:运行所有 `scripts/check-*.sh --ci`,将结果写入 CR 报告
|
||||
6. **⭐ Bug 约定建议**(bug 类需求自动触发:category=bug,或标题含 fix/修复/bug,或描述含根因/复现步骤):
|
||||
- 分析本次 bug 的根因模式
|
||||
- 判断可检测性:能写 grep 找到同类问题?(规则见 convention-flow.md「可检测性判断」)
|
||||
- 不可检测 → 仅在 CR 报告记录根因,跳过
|
||||
- 可检测 → 检查已有 `scripts/check-*.sh` 是否已覆盖 → 已覆盖则跳过
|
||||
- 扫描代码库统计同类模式数量 N
|
||||
- AskUserQuestion(N=0: 防未来复发;N>0: 防恶化+逐步清理)
|
||||
- 是 → 执行 convention flow → 产出物**单独 commit**(`chore: 建立 {name} 约定`)
|
||||
7. `ai-proj task create` 创建【代码评审】任务并关联需求(linkRole=code_review)
|
||||
8. `ai-proj create-and-attach` 附加 CR 报告文档(必须含五视角扫描结果 + 约定检查结果)
|
||||
9. 展示发现摘要,AskUserQuestion 确认是否创建 bug 修复任务
|
||||
10. 若有 High/Critical 发现 → `ai-proj task create` 创建关联修复任务
|
||||
|
||||
**`/req test [REQ-ID]`** — 测试(前置:代码评审通过),遵循 dev-test 技能的 5-Gate 流程
|
||||
|
||||
@@ -332,6 +344,7 @@ ai-proj task append-doc --id 5214 --content "# PRD: 用户认证功能\n..."
|
||||
| design | 【评审】技术设计: {需求标题} | design |
|
||||
| dev | 【开发-后端】{需求标题}、【开发-前端】{需求标题} | implementation |
|
||||
| review | 【代码评审】{需求标题} | code_review |
|
||||
| review | 【约定】{约定名称}(bug 类需求,convention flow 自动创建) | documentation |
|
||||
| testing | 【测试】集成测试: {需求标题} | test |
|
||||
| deploy | 由 `/req deploy` 批量创建 | deploy |
|
||||
|
||||
@@ -398,3 +411,4 @@ ai-proj req tasks --id <id> # 查看关联任务
|
||||
| `req-prd` | PRD 文档编写 + 评审方法论 |
|
||||
| `req-prototype` | Stitch 原型生成 + 迭代 |
|
||||
| `dev-test` | 测试 + 质量门禁 |
|
||||
| `req-test-gate` (harness) | 工程约束方法论。Gate 0-2 的约定检查由项目本地脚本定义,方法论见 `/harness` 命令 |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "req-test-gate-plugin",
|
||||
"description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5,含前后端联调+视觉验证)、部署级验证(Deploy Gates)、持续回归(Regression)。",
|
||||
"description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5)、部署级验证(Deploy Gates)、持续回归(Regression)、Harness Engineering 工程约束方法论(Ratchet、约定建立、门禁层级)。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
name: req-test-gate
|
||||
description: 测试与质量门禁制度。覆盖需求级测试(Gates 1-5,含前后端联调+视觉验证)、部署级验证(Deploy Gates)、持续回归(Regression)。
|
||||
description: 测试与质量门禁制度。覆盖需求级测试(Gates 1-5)、部署级验证(Deploy Gates)、持续回归(Regression)、Harness Engineering 工程约束方法论(Ratchet、约定建立、门禁层级)。当用户提到质量门禁、架构约束、约定检查、ratchet、harness 相关任务时自动激活。
|
||||
arguments: <subcommand> [args]
|
||||
---
|
||||
|
||||
# 测试与质量门禁制度 (req-test-gate) v2.1
|
||||
@@ -36,12 +37,13 @@ Gate 5: 回归贡献检查(按 scope 区分贡献形式)
|
||||
通过 → 允许 /req next 推进到待部署池
|
||||
```
|
||||
|
||||
## Gate 0: Scope 分级(自动)
|
||||
## Gate 0: Scope 分级 + 约定检查(自动)
|
||||
|
||||
**从 `git diff` 自动推断变更范围,决定后续 Gate 的裁剪策略。**
|
||||
**两件事**:① 从 `git diff` 推断变更范围;② 运行项目内所有约定检查脚本。
|
||||
|
||||
### 0A: Scope 分级
|
||||
|
||||
```bash
|
||||
# 自动推断逻辑
|
||||
git diff main...HEAD --name-only | classify_scope
|
||||
```
|
||||
|
||||
@@ -56,6 +58,43 @@ git diff main...HEAD --name-only | classify_scope
|
||||
|
||||
**scope 影响全部后续 Gate**,在测试报告中必须标注。
|
||||
|
||||
### 0B: 约定检查(Harness 自动执行)
|
||||
|
||||
**自动发现并运行项目内所有 `scripts/check-*.sh` 脚本。**
|
||||
|
||||
```bash
|
||||
# 自动执行逻辑
|
||||
for script in scripts/check-*.sh; do
|
||||
[ -x "$script" ] && bash "$script" --ci
|
||||
done
|
||||
```
|
||||
|
||||
| 结果 | 处理 |
|
||||
|------|------|
|
||||
| 全部 PASS | Gate 0 通过,继续 Gate 1 |
|
||||
| 有 FAIL | **阻塞**,按下方「失败处理」修复后重新 `/req test` |
|
||||
| 无 scripts/check-*.sh | 跳过(项目未建立约定检查) |
|
||||
|
||||
**失败处理**(区分脚本类型):
|
||||
|
||||
| 脚本类型 | 判断方法 | 修复方式 |
|
||||
|---------|---------|---------|
|
||||
| Hard wall(纯检测) | 脚本无 baseline 文件 | 修改代码消除违规 |
|
||||
| Ratchet(基线对比) | 脚本有 `.*-baseline.json` | 修改代码降低违规数,**或**确认是故意增加 → `./scripts/check-{name}.sh baseline` 更新基线 + AskUserQuestion 确认 |
|
||||
|
||||
> 更新基线是有意识的决策(如重构导致临时增加),不能静默执行。
|
||||
|
||||
**报告格式**:
|
||||
```
|
||||
### 约定检查 (Gate 0B)
|
||||
| 脚本 | 结果 | 详情 |
|
||||
|------|------|------|
|
||||
| check-architecture.sh | ✅ PASS | 5 rules, all within baseline |
|
||||
| check-modal-safety.sh | ✅ PASS | 0 violations |
|
||||
```
|
||||
|
||||
> 这样 Harness 建立的约定脚本会在每次 `/req test` 时自动运行,无需手动执行 `/harness report`。
|
||||
|
||||
---
|
||||
|
||||
## Gate 1: 前置条件检查
|
||||
@@ -439,7 +478,8 @@ DG6: 生产部署(不可跳过) → 健康检查+文档
|
||||
```
|
||||
v1: Gate 1 → Gate 2 → Gate 3 → Gate 4
|
||||
v2: Gate 1 → Gate 2(2A→2B→2C→2D→2E) → Gate 3 → Gate 4 → Gate 5
|
||||
v2.1: Gate 0(scope) → Gate 1 → Gate 2(2A→2B→2C→2D→2E→2F,按scope裁剪) → Gate 3 → Gate 4 → Gate 5
|
||||
v2.1: Gate 0(scope) → Gate 1 → Gate 2(2A→2B→2C→2D→2E→2F) → Gate 3 → Gate 4 → Gate 5
|
||||
v3: Gate 0A(scope) + 0B(约定检查) → Gate 1 → Gate 2(按scope裁剪) → Gate 3 → Gate 4 → Gate 5
|
||||
```
|
||||
|
||||
### `/req next` testing→staging 门禁
|
||||
@@ -449,3 +489,52 @@ v2.1: Gate 0(scope) → Gate 1 → Gate 2(2A→2B→2C→2D→2E→2F,按scope
|
||||
### `/req deploy` 部署门禁
|
||||
|
||||
在 req-deploy 流程前增加 Deploy Gates (DG1-DG6) 检查。
|
||||
|
||||
---
|
||||
|
||||
## Harness Engineering — 工程约束方法论
|
||||
|
||||
**项目级基础设施**的建立和维护方法论,与上述需求级门禁互补。
|
||||
|
||||
> 详见 [harness-engineering.md](harness-engineering.md) 完整文档。
|
||||
|
||||
### 核心理念
|
||||
|
||||
**建立自动化护栏防止新违规,同时允许渐进式清理遗留问题。**
|
||||
|
||||
三大支柱:
|
||||
1. **Ratchet** — 遗留违规数只能减不能增 → [ratchet-pattern.md](ratchet-pattern.md)
|
||||
2. **约定建立** — 每个 bug 修复后立即建立约定和检测 → [convention-flow.md](convention-flow.md)
|
||||
3. **门禁层级** — 按项目成熟度逐级引入 → [project-bootstrap.md](project-bootstrap.md)
|
||||
|
||||
### `/harness` 命令集(手动可用 + 自动嵌入)
|
||||
|
||||
| 命令 | 手动 | 自动触发 |
|
||||
|------|------|---------|
|
||||
| `/harness assess` | 随时 | 首次 `/req dev` |
|
||||
| `/harness init [level]` | 随时 | — |
|
||||
| `/harness convention [name]` | 随时 | `/req cr` + bug 类型需求 |
|
||||
| `/harness report` | 随时 | `/req test` Gate 0B |
|
||||
|
||||
### 模板
|
||||
|
||||
`templates/` 目录提供可复用的脚本模板:
|
||||
- [ratchet-script.md](templates/ratchet-script.md) — Ratchet 脚本模板(check/baseline/report 三命令)
|
||||
- [convention-script.md](templates/convention-script.md) — 约定检测脚本模板(grep 模式匹配)
|
||||
- [gates-doc.md](templates/gates-doc.md) — GATES.md 文档模板
|
||||
- [pre-commit-config.md](templates/pre-commit-config.md) — husky + lint-staged 配置(Node.js/Go/Monorepo)
|
||||
|
||||
### 与需求级门禁的关系
|
||||
|
||||
```
|
||||
Harness(项目级护栏) req-test-gate(需求级门禁)
|
||||
├── .husky/ pre-commit ├── Gate 0A: scope 分级
|
||||
├── CI lint workflow ├── Gate 0B: 运行 harness 的 check-*.sh ←─ 连接点
|
||||
├── scripts/check-*.sh ├── Gate 1: 前置条件
|
||||
├── CLAUDE.md 约定 ├── Gate 2: 测试执行
|
||||
│ ├── Gate 3: 质量验证
|
||||
│ ├── Gate 4: 文档持久化
|
||||
│ └── Gate 5: 回归贡献
|
||||
```
|
||||
|
||||
> Harness 不使用 Gate 编号。它的产出物(check-*.sh 脚本)通过 Gate 0B 接入 req-test-gate 流程。
|
||||
|
||||
222
skills-req/req-test-gate-plugin/skills/convention-flow.md
Normal file
222
skills-req/req-test-gate-plugin/skills/convention-flow.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# 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. 输出摘要:约定名称、策略、违规数、文件清单
|
||||
```
|
||||
113
skills-req/req-test-gate-plugin/skills/harness-engineering.md
Normal file
113
skills-req/req-test-gate-plugin/skills/harness-engineering.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# Harness Engineering — 工程约束方法论
|
||||
|
||||
## 概述
|
||||
|
||||
Harness Engineering 是一套**建立自动化护栏防止新违规,同时允许渐进式清理遗留问题**的工程方法论。
|
||||
|
||||
**三大支柱**:
|
||||
|
||||
| 支柱 | 核心机制 | 说明 |
|
||||
|------|---------|------|
|
||||
| **Ratchet** | 基线 + 单调递减 | 遗留违规数只能减不能增,新代码零容忍 |
|
||||
| **约定建立** | Bug → 文档 → 自动检测 | 每个 bug 修复后立即建立约定和检测脚本 |
|
||||
| **门禁层级** | Level 1-3 递进 | 按项目成熟度逐级引入基础设施 |
|
||||
|
||||
## 子文件索引
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|------|
|
||||
| [ratchet-pattern.md](ratchet-pattern.md) | Ratchet 模式详解:Ratchet vs Hard Wall、基线格式、三命令接口 |
|
||||
| [convention-flow.md](convention-flow.md) | 三步约定建立流程:修 bug → 文档化 → 自动化检测 |
|
||||
| [project-bootstrap.md](project-bootstrap.md) | `/harness assess` 检测逻辑 + `/harness init` 分级实施指南 |
|
||||
| [templates/](templates/) | 脚本模板:ratchet、约定检测、GATES.md、pre-commit 配置 |
|
||||
|
||||
## 命令集与自动触发
|
||||
|
||||
| 命令 | 手动触发 | 自动触发时机 |
|
||||
|------|---------|-------------|
|
||||
| `/harness assess` | 用户显式调用 | **`/req dev`** 启动时快速检测(`.husky/` + `scripts/check-*.sh` 都不存在 → 提示 Level 0) |
|
||||
| `/harness init [level]` | 用户显式调用 | 不自动触发(创建基础设施需用户确认) |
|
||||
| `/harness convention [name]` | 用户显式调用 | **`/req cr` + category=bug** 时自动建议(分析根因 → 建议约定 → 用户确认后执行) |
|
||||
| `/harness report` | 用户显式调用 | **`/req test` Gate 0B** 自动运行所有 `scripts/check-*.sh` |
|
||||
|
||||
### 自动触发流程图
|
||||
|
||||
```
|
||||
/req dev (每次)
|
||||
└→ 快速检测: .husky/ 存在? scripts/check-*.sh 存在?
|
||||
└→ 都不存在 → 提示「Level 0,建议 /harness init」(不阻塞)
|
||||
└→ 有任一 → 静默通过
|
||||
|
||||
/req cr (bug 类型需求)
|
||||
└→ 五视角扫描
|
||||
└→ 运行 scripts/check-*.sh → 写入 CR 报告
|
||||
└→ ⭐ 分析 bug 根因 → 可自动检测? → 建议建立约定
|
||||
└→ 用户确认 → convention flow(文档化 → 脚本 → CLAUDE.md)
|
||||
|
||||
/req test
|
||||
└→ Gate 0A: scope 分级
|
||||
└→ Gate 0B: 运行所有 scripts/check-*.sh
|
||||
└→ 有 FAIL → 阻塞,必须修复
|
||||
└→ 全 PASS → 继续 Gate 1-5
|
||||
```
|
||||
|
||||
> 手动命令仍然可用。自动触发只是让你"不用记得去跑"。
|
||||
|
||||
## 成熟度分级
|
||||
|
||||
| Level | 基础设施 | 适用场景 |
|
||||
|-------|---------|---------|
|
||||
| **0** | 无自动化检查 | 新项目/原型 |
|
||||
| **1** | husky + lint-staged + formatter | 所有活跃项目 |
|
||||
| **2** | + ratchet 脚本 + GATES.md + CLAUDE.md 质量段落 | >10k LOC 或 >1 开发者 |
|
||||
| **3** | + CI workflow + 架构强制 + 约定检测 | 有 PR 流程和受保护分支的项目 |
|
||||
|
||||
## 技术栈检测矩阵
|
||||
|
||||
| 技术栈 | 检测标志 | Level 1 工具 | Level 2+ 工具 |
|
||||
|--------|---------|-------------|--------------|
|
||||
| **Go** | `go.mod` | gofmt + go vet | golangci-lint, architecture ratchet |
|
||||
| **React/TS** | `package.json` + react 依赖 | ESLint + Prettier | tsc --noEmit, convention scripts |
|
||||
| **Vue/TS** | `package.json` + vue 依赖 | ESLint + Prettier | vite build check |
|
||||
| **Monorepo** | 多个 `package.json` / `go.mod` | 各子项目独立 lint | 统一 CI + 分模块 ratchet |
|
||||
|
||||
## CLAUDE.md 约定文档格式
|
||||
|
||||
在项目的 CLAUDE.md 中添加约定时,必须遵循以下标准格式:
|
||||
|
||||
```markdown
|
||||
### {类别}: {约定名称}
|
||||
|
||||
{原因描述 — 为什么需要这条约定}
|
||||
|
||||
**规则:{一句话规则描述}**
|
||||
|
||||
\`\`\`{语言}
|
||||
// WRONG — {错误原因}
|
||||
{错误代码示例}
|
||||
|
||||
// CORRECT — {正确做法}
|
||||
{正确代码示例}
|
||||
\`\`\`
|
||||
|
||||
**检查命令**:`./scripts/check-{name}.sh`(CI 自动运行)
|
||||
```
|
||||
|
||||
## 与其他技能的关系
|
||||
|
||||
Harness 和 req-test-gate 是**互补关系**,不要混淆两者的 Gate 编号:
|
||||
|
||||
| 维度 | Harness | req-test-gate |
|
||||
|------|---------|--------------|
|
||||
| **作用域** | 项目级(所有 PR 共享) | 需求级(每个需求独立) |
|
||||
| **触发方式** | git commit / PR / `/req test` Gate 0B | `/req test` Gate 1-5 |
|
||||
| **管什么** | pre-commit、lint、ratchet 脚本、约定检测 | 测试执行、质量验证、文档持久化、回归 |
|
||||
| **产出物** | `.husky/`、`scripts/check-*.sh`、CLAUDE.md 约定 | 测试报告、回归用例 |
|
||||
|
||||
**⚠️ 注意**:项目的 `docs/quality/GATES.md` 中有自己的 Gate 编号(Gate 0=pre-commit, Gate 1=CI lint, Gate 2=ratchet...),这是**项目文档的编号**,与 req-test-gate 的 Gate 0-5 是两套独立体系,不要混用。
|
||||
|
||||
| 技能 | 职责 |
|
||||
|------|------|
|
||||
| **harness**(本文档) | 建立和维护项目级护栏(脚本、约定、CLAUDE.md) |
|
||||
| **req-test-gate** | 需求级测试门禁(Gate 0-5),其中 Gate 0B 自动调用 harness 建立的脚本 |
|
||||
| **dev-coding** | 遵守 harness 建立的 CLAUDE.md 约定,编码时不违反 ratchet |
|
||||
194
skills-req/req-test-gate-plugin/skills/project-bootstrap.md
Normal file
194
skills-req/req-test-gate-plugin/skills/project-bootstrap.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# Project Bootstrap — 工程约束基础设施引导
|
||||
|
||||
## `/harness assess` 检测逻辑
|
||||
|
||||
扫描项目结构,自动判断成熟度等级(0-3),列出缺口和建议。
|
||||
|
||||
### 检测项清单(每项附实际执行的命令)
|
||||
|
||||
| 检测项 | 执行命令 | 判定 | Level |
|
||||
|--------|---------|------|-------|
|
||||
| 技术栈 | `Glob("package.json", "go.mod", "Podfile", "*.csproj")` | 存在即识别 | 基础 |
|
||||
| Pre-commit hooks | `Glob(".husky/pre-commit")` | 文件存在 | 1 |
|
||||
| Lint 配置 | `Glob(".eslintrc*", ".golangci.yml") + Grep("lint", "Makefile")` | 任一存在 | 1 |
|
||||
| Formatter | `Glob(".prettierrc*") + Grep("gofmt\\|prettier", ".husky/pre-commit")` | 任一存在 | 1 |
|
||||
| lint-staged | `Grep("lint-staged", "package.json") + Glob(".lintstagedrc*")` | 任一存在 | 1 |
|
||||
| 约定脚本 | `Glob("scripts/check-*.sh")` | 至少 1 个 | 2 |
|
||||
| 基线文件 | `Glob("scripts/.*-baseline.json")` | 至少 1 个 | 2 |
|
||||
| 门禁文档 | `Glob("docs/quality/GATES.md")` | 文件存在 | 2 |
|
||||
| CLAUDE.md 质量段落 | `Grep("检查命令\\|check-.*\\.sh", "CLAUDE.md")` | 有匹配 | 2 |
|
||||
| CI workflow | `Grep("check-.*\\.sh", ".gitea/workflows/*.yml", ".github/workflows/*.yml")` | 有匹配 | 3 |
|
||||
|
||||
### 等级判定
|
||||
|
||||
```
|
||||
Level 0: 无上述任何基础设施
|
||||
Level 1: 有 pre-commit hooks + lint + formatter
|
||||
Level 2: Level 1 + 有 ratchet/约定脚本 + GATES.md
|
||||
Level 3: Level 2 + CI 自动运行 + 受保护分支
|
||||
```
|
||||
|
||||
### 输出格式
|
||||
|
||||
```markdown
|
||||
## Harness Assessment: {项目名}
|
||||
|
||||
**技术栈**: Go + React (monorepo)
|
||||
**当前等级**: Level 2
|
||||
|
||||
### 已有基础设施
|
||||
- [x] husky pre-commit hooks
|
||||
- [x] ESLint + Prettier (frontend)
|
||||
- [x] gofmt + go vet (backend)
|
||||
- [x] check-architecture.sh (ratchet, 5 rules)
|
||||
- [x] check-modal-safety.sh (hard wall)
|
||||
- [x] GATES.md
|
||||
|
||||
### 缺口(升至 Level 3)
|
||||
- [ ] CI workflow 未调用 check-architecture.sh
|
||||
- [ ] CI workflow 未调用 check-modal-safety.sh
|
||||
|
||||
### 建议
|
||||
1. 在 .gitea/workflows/quality-gates.yaml 中添加 check-architecture.sh check
|
||||
2. 在 .gitea/workflows/quality-gates.yaml 中添加 check-modal-safety.sh --ci
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `/harness init [level]` 分级实施
|
||||
|
||||
### Level 1: 基础代码格式化
|
||||
|
||||
**适用**:所有活跃项目。
|
||||
|
||||
#### Node.js 项目
|
||||
|
||||
```bash
|
||||
# 1. 安装 husky + lint-staged
|
||||
npm install -D husky lint-staged
|
||||
npx husky init
|
||||
|
||||
# 2. 配置 lint-staged(package.json)
|
||||
# 参见 templates/pre-commit-config.md — Node.js 变体
|
||||
|
||||
# 3. 配置 pre-commit hook
|
||||
echo "npx lint-staged" > .husky/pre-commit
|
||||
```
|
||||
|
||||
#### Go 项目
|
||||
|
||||
```bash
|
||||
# 1. 安装 husky(需要 package.json)
|
||||
npm init -y
|
||||
npm install -D husky lint-staged
|
||||
npx husky init
|
||||
|
||||
# 2. 配置 lint-staged(package.json)
|
||||
# 参见 templates/pre-commit-config.md — Go 变体
|
||||
|
||||
# 3. 配置 pre-commit hook
|
||||
echo "npx lint-staged" > .husky/pre-commit
|
||||
```
|
||||
|
||||
#### Monorepo
|
||||
|
||||
```bash
|
||||
# 根目录安装 husky,各子项目配置 lint-staged
|
||||
# 参见 templates/pre-commit-config.md — Monorepo 变体
|
||||
```
|
||||
|
||||
### Level 2: 约定与 Ratchet
|
||||
|
||||
**前置**:Level 1 已完成。
|
||||
|
||||
#### Step 1: 创建目录结构
|
||||
|
||||
```bash
|
||||
mkdir -p scripts docs/quality
|
||||
```
|
||||
|
||||
#### Step 2: 创建 GATES.md
|
||||
|
||||
参见 [templates/gates-doc.md](templates/gates-doc.md),填入项目实际的 lint 工具和 CI 系统。
|
||||
|
||||
#### Step 3: 约束发现(关键步骤)
|
||||
|
||||
AI 必须探索项目代码库,按以下清单逐项检查,找出适合建 ratchet 的约束:
|
||||
|
||||
| 检查项 | 检测方法 | 发现约束时 |
|
||||
|--------|---------|-----------|
|
||||
| **分层架构** | 读 `go.mod` / 目录结构,判断是否有 handler/service/repository 分层 | 检查跨层 import → ratchet |
|
||||
| **禁止 import** | `grep -r "import" --include="*.go"` 找不应出现的包引用 | 统计违规数 → ratchet 或 wall |
|
||||
| **前端 API 调用规范** | `grep -r "fetch\|axios" --include="*.tsx"` 看是否有直接调用(应走 service 层) | 统计违规数 → ratchet |
|
||||
| **console.log 残留** | `grep -r "console.log" --include="*.tsx" --include="*.ts"` | 统计数量 → ratchet |
|
||||
| **硬编码配置** | `grep -rn "localhost\|127.0.0.1\|:3000\|:8080" --include="*.ts" --include="*.go"` 排除测试和配置文件 | 统计数量 → ratchet |
|
||||
| **TODO/FIXME** | `grep -rn "TODO\|FIXME" --include="*.go" --include="*.ts"` | 统计数量 → ratchet(仅追踪,不阻塞) |
|
||||
|
||||
**执行流程**:
|
||||
```
|
||||
1. 读取项目目录结构(ls -R 前两层)
|
||||
2. 识别技术栈和架构风格
|
||||
3. 按上表逐项 grep 扫描
|
||||
4. 筛选:违规数 > 0 的项列为候选规则
|
||||
5. AskUserQuestion:展示候选规则表,让用户勾选要建哪些
|
||||
6. 对每条选中的规则:
|
||||
a. 用 ratchet-script 模板生成 scripts/check-{name}.sh
|
||||
b. 运行 baseline 记录初始值
|
||||
c. 在 CLAUDE.md 添加约定段落
|
||||
```
|
||||
|
||||
> 如果扫描后没有发现任何候选规则(代码量很小或结构简单),Level 2 只创建 GATES.md + CLAUDE.md 质量段落,不创建 ratchet 脚本。后续通过 convention flow(修 bug 时)逐步积累。
|
||||
|
||||
#### Step 4: CLAUDE.md 质量段落
|
||||
|
||||
参见 [harness-engineering.md](harness-engineering.md) 的「CLAUDE.md 约定文档格式」。
|
||||
|
||||
#### Step 5: 提交
|
||||
|
||||
```bash
|
||||
./scripts/check-{name}.sh baseline # 每个新脚本都要 baseline
|
||||
git add scripts/ docs/quality/ CLAUDE.md
|
||||
git commit -m "chore: establish harness engineering Level 2"
|
||||
```
|
||||
|
||||
### Level 3: CI 强制
|
||||
|
||||
**前置**:Level 2 已完成 + 项目有 CI 和受保护分支。
|
||||
|
||||
```yaml
|
||||
# .gitea/workflows/quality-gates.yaml 示例
|
||||
name: Quality Gates
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
quality:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Architecture Check
|
||||
run: ./scripts/check-architecture.sh check
|
||||
- name: Convention Checks
|
||||
run: |
|
||||
for script in scripts/check-*.sh; do
|
||||
[ "$script" = "scripts/check-architecture.sh" ] && continue
|
||||
bash "$script" --ci
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `/harness init` 执行流程
|
||||
|
||||
```
|
||||
1. 运行 /harness assess 确定当前等级
|
||||
2. 确定目标等级(用户指定或默认 Level 1)
|
||||
3. 如果当前等级 ≥ 目标等级,提示"已满足"
|
||||
4. 按目标等级模板生成文件:
|
||||
- Level 1: .husky/ + package.json lint-staged
|
||||
- Level 2: scripts/ + docs/quality/ + CLAUDE.md 段落
|
||||
- Level 3: CI workflow
|
||||
5. 运行验证(husky hook 是否生效、脚本是否可执行)
|
||||
6. 输出文件清单和下一步建议
|
||||
```
|
||||
96
skills-req/req-test-gate-plugin/skills/ratchet-pattern.md
Normal file
96
skills-req/req-test-gate-plugin/skills/ratchet-pattern.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Ratchet Pattern — 渐进式违规清理
|
||||
|
||||
## Ratchet vs Hard Wall
|
||||
|
||||
| 策略 | 适用场景 | 基线值 | CI 行为 |
|
||||
|------|---------|--------|---------|
|
||||
| **Ratchet** | 有遗留违规(>0) | 当前违规数 | 新值 > 基线 → FAIL |
|
||||
| **Hard Wall** | 必须为零 | 固定 = 0 | 值 ≠ 0 → FAIL |
|
||||
|
||||
**选择依据**:
|
||||
- 遗留违规 = 0 → Hard Wall(绝对禁止)
|
||||
- 遗留违规 > 0 → Ratchet(允许存在但不能增加)
|
||||
|
||||
## 基线文件格式
|
||||
|
||||
基线以 JSON 格式存储,提交到 git:
|
||||
|
||||
```json
|
||||
{
|
||||
"rule_name_1": 108,
|
||||
"rule_name_2": 7,
|
||||
"rule_name_3": 0
|
||||
}
|
||||
```
|
||||
|
||||
**位置约定**:`scripts/.{检测名}-baseline.json`(如 `scripts/.architecture-baseline.json`)
|
||||
|
||||
## 三命令接口
|
||||
|
||||
每个 ratchet 脚本必须实现三个子命令:
|
||||
|
||||
| 命令 | 用途 | CI 使用 |
|
||||
|------|------|---------|
|
||||
| `check` | 比较当前值与基线,增加则失败 | PR 门禁 |
|
||||
| `baseline` | 记录当前值为新基线 | 修复违规后手动执行 |
|
||||
| `report` | 打印当前值 vs 基线的对比表 | 人工审查 |
|
||||
|
||||
```bash
|
||||
./scripts/check-{name}.sh check # CI: fail if violations increased
|
||||
./scripts/check-{name}.sh baseline # After fix: record new lower baseline
|
||||
./scripts/check-{name}.sh report # Human: see current vs baseline
|
||||
```
|
||||
|
||||
## 何时降低基线
|
||||
|
||||
```
|
||||
1. 修复一个或多个违规
|
||||
2. 运行 check → PASS(因为当前值 ≤ 旧基线)
|
||||
3. 运行 baseline → 记录更低的基线
|
||||
4. git commit 新的基线文件
|
||||
5. 后续 PR 使用更低的基线
|
||||
```
|
||||
|
||||
**关键**:修复后一定要 `baseline` + commit,否则下次有人新增违规会被允许(因为基线还是旧的高值)。
|
||||
|
||||
## 多规则 Ratchet
|
||||
|
||||
一个脚本可以管理多条规则,每条规则有独立的基线值和类型(ratchet/wall)。
|
||||
|
||||
```bash
|
||||
# rules 数组定义规则名
|
||||
rules=("handlers_import_database" "routes_import_database" "models_import_upper")
|
||||
# types 数组定义策略
|
||||
types=("ratchet" "ratchet" "wall")
|
||||
|
||||
# 循环检查每条规则
|
||||
for i in "${!rules[@]}"; do
|
||||
rule="${rules[$i]}"
|
||||
type="${types[$i]}"
|
||||
# ...
|
||||
done
|
||||
```
|
||||
|
||||
## 参考实现
|
||||
|
||||
**new-ai-proj** 项目的架构 ratchet:
|
||||
- 脚本:`scripts/check-architecture.sh`
|
||||
- 基线:`scripts/.architecture-baseline.json`
|
||||
- 规则文档:`docs/architecture/LAYER_RULES.md`
|
||||
- 门禁文档:`docs/quality/GATES.md`
|
||||
|
||||
五条规则:
|
||||
| 规则 | 类型 | 含义 |
|
||||
|------|------|------|
|
||||
| `handlers_import_database` | ratchet | Handler 不应直接访问数据库层 |
|
||||
| `routes_import_database` | ratchet | 路由不应直接访问数据库层 |
|
||||
| `routes_import_services` | ratchet | 路由应通过 handler 委托 |
|
||||
| `models_import_upper` | hard wall | 模型层禁止反向依赖 |
|
||||
| `services_import_handlers` | hard wall | 服务层禁止反向依赖 |
|
||||
|
||||
## 设计 Ratchet 规则的原则
|
||||
|
||||
1. **可计数** — 规则违规必须能通过 grep/AST 精确计数
|
||||
2. **无歧义** — 一个文件/行要么违规要么不违规,不能有灰色地带
|
||||
3. **可修复** — 开发者必须知道怎么把违规改正确
|
||||
4. **有文档** — 每条规则配 LAYER_RULES.md 或 CLAUDE.md 中的正反示例
|
||||
@@ -0,0 +1,120 @@
|
||||
# Convention Detection Script Template
|
||||
|
||||
泛化的约定检测脚本模板,基于 new-ai-proj `check-modal-safety.sh` 提取。用于检测代码中违反编码约定的模式。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 复制下方脚本到 `scripts/check-{NAME}.sh`
|
||||
2. 替换所有 `{PLACEHOLDER}` 为项目特定值
|
||||
3. 运行 `chmod +x scripts/check-{NAME}.sh`
|
||||
4. 验证:`./scripts/check-{NAME}.sh` 输出 PASSED
|
||||
|
||||
## 脚本模板
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# {CONVENTION_NAME} Check — detects {WHAT_IT_DETECTS} in {TARGET_SCOPE}.
|
||||
#
|
||||
# {PROBLEM_DESCRIPTION}
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/check-{NAME}.sh # Check and report
|
||||
# ./scripts/check-{NAME}.sh --ci # Exit code 1 on violations
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
TARGET_DIR="$(cd "$(dirname "$0")/../{TARGET_DIRECTORY}" && pwd)"
|
||||
CI_MODE=false
|
||||
[[ "${1:-}" == "--ci" ]] && CI_MODE=true
|
||||
|
||||
violations=0
|
||||
|
||||
# ── detection logic ─────────────────────────────────────────────────
|
||||
|
||||
# Strategy A: Simple grep pattern (file-level)
|
||||
# Find files matching a bad pattern, optionally excluding false positives.
|
||||
#
|
||||
# while IFS= read -r file; do
|
||||
# rel_path="${file#"$TARGET_DIR"/}"
|
||||
# echo "WARNING: $rel_path — {VIOLATION_MESSAGE}"
|
||||
# violations=$((violations + 1))
|
||||
# done < <(grep -rl '{BAD_PATTERN}' "$TARGET_DIR" --include='{FILE_GLOB}' 2>/dev/null \
|
||||
# | while read f; do grep -L '{FALSE_POSITIVE_PATTERN}' "$f" 2>/dev/null; done)
|
||||
|
||||
# Strategy B: Line-level with context (multi-condition)
|
||||
# Find a primary pattern, check nearby lines for secondary pattern.
|
||||
#
|
||||
# while IFS= read -r file; do
|
||||
# while IFS= read -r line_num; do
|
||||
# # Check context around the match
|
||||
# has_mitigation=$(sed -n "${line_num},$((line_num + {CONTEXT_LINES}))p" "$file" \
|
||||
# | grep -c '{MITIGATION_PATTERN}' || true)
|
||||
# if [[ "$has_mitigation" -eq 0 ]]; then
|
||||
# # Additional condition: check if problematic follow-up exists
|
||||
# after_end=$((line_num + {LOOKAHEAD_LINES}))
|
||||
# has_problem=$(sed -n "$((line_num + 1)),${after_end}p" "$file" \
|
||||
# | grep -cE '{FOLLOW_UP_BAD_PATTERN}' || true)
|
||||
# if [[ "$has_problem" -gt 0 ]]; then
|
||||
# rel_path="${file#"$TARGET_DIR"/}"
|
||||
# echo "WARNING: $rel_path:$line_num — {VIOLATION_MESSAGE}"
|
||||
# violations=$((violations + 1))
|
||||
# fi
|
||||
# fi
|
||||
# done < <(grep -n '{PRIMARY_PATTERN}' "$file" | cut -d: -f1)
|
||||
# done < <(grep -rl '{PRIMARY_PATTERN}' "$TARGET_DIR" --include='{FILE_GLOB}' 2>/dev/null)
|
||||
|
||||
# ── results ─────────────────────────────────────────────────────────
|
||||
|
||||
if [[ "$violations" -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "Found $violations {CONVENTION_NAME} violation(s)."
|
||||
echo "Fix: {FIX_GUIDANCE}"
|
||||
echo "Docs: see CLAUDE.md '{CLAUDE_MD_SECTION}'"
|
||||
$CI_MODE && exit 1
|
||||
else
|
||||
echo "{CONVENTION_NAME} check PASSED."
|
||||
fi
|
||||
```
|
||||
|
||||
## Placeholder 说明
|
||||
|
||||
| Placeholder | 含义 | 示例 |
|
||||
|-------------|------|------|
|
||||
| `{NAME}` | 脚本短名 | `modal-safety`, `sql-injection` |
|
||||
| `{CONVENTION_NAME}` | 约定显示名 | `Modal safety`, `SQL injection prevention` |
|
||||
| `{WHAT_IT_DETECTS}` | 检测内容 | `potential modal overlap patterns` |
|
||||
| `{TARGET_SCOPE}` | 目标范围描述 | `frontend code`, `Go handlers` |
|
||||
| `{TARGET_DIRECTORY}` | 扫描目录 | `frontend/src`, `backend` |
|
||||
| `{PROBLEM_DESCRIPTION}` | 问题描述 | `Ant Design Modal.success is non-blocking...` |
|
||||
| `{FILE_GLOB}` | 文件匹配 | `*.tsx`, `*.go` |
|
||||
| `{PRIMARY_PATTERN}` | 主匹配模式 | `Modal\.\(success\|info\)` |
|
||||
| `{MITIGATION_PATTERN}` | 缓解模式(有则排除) | `onOk` |
|
||||
| `{FOLLOW_UP_BAD_PATTERN}` | 后续违规模式 | `set\w*Open\(true\)` |
|
||||
| `{CONTEXT_LINES}` | 上下文行数 | `25` |
|
||||
| `{LOOKAHEAD_LINES}` | 前瞻行数 | `20` |
|
||||
| `{BAD_PATTERN}` | Strategy A 主匹配模式 | `console\.log` |
|
||||
| `{FALSE_POSITIVE_PATTERN}` | Strategy A 排除模式(匹配到则非违规) | `// eslint-disable` |
|
||||
| `{VIOLATION_MESSAGE}` | 违规消息 | `Modal without onOk followed by setState` |
|
||||
| `{FIX_GUIDANCE}` | 修复指导 | `add onOk callback to Modal` |
|
||||
| `{CLAUDE_MD_SECTION}` | CLAUDE.md 章节名 | `Frontend: Modal 安全规则` |
|
||||
|
||||
## 两种检测策略
|
||||
|
||||
### Strategy A: 文件级检测
|
||||
|
||||
适用于:整个文件不应出现某模式(或出现即违规)。
|
||||
|
||||
例子:
|
||||
- `console.log` 在生产代码中
|
||||
- `TODO` / `FIXME` 计数
|
||||
- 缺少 license header
|
||||
|
||||
### Strategy B: 行级 + 上下文检测
|
||||
|
||||
适用于:模式本身不违规,需要检查周围上下文。
|
||||
|
||||
例子:
|
||||
- `Modal.success()` 不违规,但后面紧跟 `setState` 才违规
|
||||
- `db.Exec()` 不违规,但参数用字符串拼接才违规
|
||||
- `fmt.Println()` 不违规,但在 handler 中输出敏感数据才违规
|
||||
102
skills-req/req-test-gate-plugin/skills/templates/gates-doc.md
Normal file
102
skills-req/req-test-gate-plugin/skills/templates/gates-doc.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# GATES.md Template
|
||||
|
||||
项目质量门禁文档模板。放置于 `docs/quality/GATES.md`。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 复制下方模板到项目的 `docs/quality/GATES.md`
|
||||
2. 替换 `{PLACEHOLDER}` 为项目特定值
|
||||
3. 根据项目实际情况增删 Gate
|
||||
|
||||
## 模板
|
||||
|
||||
```markdown
|
||||
# Quality Gates
|
||||
|
||||
Quality gates are automated checks that code must pass before it can be merged or deployed.
|
||||
|
||||
## Gate Overview
|
||||
|
||||
| Gate | Name | Where | What it catches |
|
||||
|------|------|-------|-----------------|
|
||||
| 0 | Pre-commit | Local (husky) | Formatting, lint errors |
|
||||
| 1 | CI Lint | {CI_SYSTEM} | {LINT_TOOLS} |
|
||||
| 2 | Convention & Architecture | {CI_SYSTEM} | New violations of established rules |
|
||||
| 3 | Unit Tests | CI / local | Logic bugs, regressions |
|
||||
| 4 | Security Scan | CI | Dependency vulnerabilities |
|
||||
| 5 | Build | CI | Compilation errors |
|
||||
|
||||
## Gate 0: Pre-commit (Local)
|
||||
|
||||
Runs automatically on every `git commit` via husky + lint-staged.
|
||||
|
||||
{FRONTEND_SECTION — include if applicable}
|
||||
**Frontend** (`{FRONTEND_GLOBS}`):
|
||||
- {LINT_TOOL} with {LINT_FLAGS}
|
||||
- {FORMATTER}
|
||||
|
||||
{BACKEND_SECTION — include if applicable}
|
||||
**Backend** (`{BACKEND_GLOBS}`):
|
||||
- {FORMAT_TOOL} (auto-format)
|
||||
- {ANALYSIS_TOOL} (static analysis)
|
||||
|
||||
**Bypass** (emergency only): `git commit --no-verify`
|
||||
|
||||
## Gate 1: CI Lint
|
||||
|
||||
Runs on pull requests via {CI_SYSTEM}.
|
||||
|
||||
- **Backend**: {BACKEND_LINT_COMMANDS}
|
||||
- **Frontend**: {FRONTEND_LINT_COMMANDS}
|
||||
|
||||
## Gate 2: Convention & Architecture Checks
|
||||
|
||||
Runs on pull requests via {CI_SYSTEM}.
|
||||
|
||||
{LIST_EACH_CHECK_SCRIPT}
|
||||
- `./scripts/check-{name}.sh check` — {description}
|
||||
|
||||
See project CLAUDE.md and docs/architecture/ for rule details.
|
||||
|
||||
## Gates 3-5: Testing, Security, Build
|
||||
|
||||
These gates are enforced via the `/req test` workflow:
|
||||
|
||||
1. **Gate 3**: Unit test generation and execution
|
||||
2. **Gate 4**: Security regression scan
|
||||
3. **Gate 5**: E2E smoke test + final report
|
||||
|
||||
See the dev-test skill documentation for details.
|
||||
|
||||
## Local Commands
|
||||
|
||||
\`\`\`bash
|
||||
# Gate 0: Format & Lint
|
||||
{LOCAL_LINT_COMMANDS}
|
||||
|
||||
# Gate 2: Convention checks
|
||||
{LOCAL_CHECK_COMMANDS}
|
||||
|
||||
# Gate 3: Unit tests
|
||||
{LOCAL_TEST_COMMANDS}
|
||||
\`\`\`
|
||||
```
|
||||
|
||||
## Placeholder 说明
|
||||
|
||||
| Placeholder | 含义 | 示例 |
|
||||
|-------------|------|------|
|
||||
| `{CI_SYSTEM}` | CI 系统名称 | `Gitea Actions`, `GitHub Actions` |
|
||||
| `{LINT_TOOLS}` | lint 工具列表 | `golangci-lint, ESLint, TypeScript errors` |
|
||||
| `{FRONTEND_GLOBS}` | 前端文件 glob | `*.ts, *.tsx`, `*.vue` |
|
||||
| `{BACKEND_GLOBS}` | 后端文件 glob | `*.go` |
|
||||
| `{LINT_TOOL}` | lint 工具 | `ESLint` |
|
||||
| `{LINT_FLAGS}` | lint 参数 | `--fix --max-warnings 0` |
|
||||
| `{FORMATTER}` | 格式化工具 | `Prettier`, `gofmt` |
|
||||
|
||||
## 注意事项
|
||||
|
||||
- **此文档的 Gate 编号是项目级的**(描述项目基础设施层级),与 req-test-gate 技能的 Gate 0-5(需求级测试门禁)是两套独立体系
|
||||
- Gate 0-2 由 harness engineering 方法论管理(pre-commit → CI lint → ratchet/约定检测)
|
||||
- Gate 3-5 由 `/req test` 流程管理(单元测试 → 安全扫描 → 构建验证)
|
||||
- 两者互补,不要混淆编号
|
||||
@@ -0,0 +1,135 @@
|
||||
# Pre-commit Configuration Template
|
||||
|
||||
husky + lint-staged 配置模板,三种变体:Node.js 项目、Go 项目、Monorepo。
|
||||
|
||||
---
|
||||
|
||||
## 变体 1: Node.js 项目(React / Vue / 纯 TS)
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
npm install -D husky lint-staged prettier eslint
|
||||
npx husky init
|
||||
echo "npx lint-staged" > .husky/pre-commit
|
||||
```
|
||||
|
||||
### package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx}": [
|
||||
"eslint --fix --max-warnings 0",
|
||||
"prettier --write"
|
||||
],
|
||||
"*.{css,less,scss}": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.{json,md}": [
|
||||
"prettier --write"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 变体 2: Go 项目
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# Go 项目需要 package.json 来驱动 husky
|
||||
npm init -y
|
||||
npm install -D husky lint-staged
|
||||
npx husky init
|
||||
echo "npx lint-staged" > .husky/pre-commit
|
||||
```
|
||||
|
||||
### package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"*.go": [
|
||||
"gofmt -s -w",
|
||||
"bash -c 'go vet ./...'"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 可选:golangci-lint(更严格)
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"*.go": [
|
||||
"gofmt -s -w",
|
||||
"bash -c 'go vet ./...'",
|
||||
"bash -c 'golangci-lint run --fix'"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 变体 3: Monorepo(Go + Node.js)
|
||||
|
||||
### 安装(根目录)
|
||||
|
||||
```bash
|
||||
npm install -D husky lint-staged
|
||||
npx husky init
|
||||
echo "npx lint-staged" > .husky/pre-commit
|
||||
```
|
||||
|
||||
### package.json(根目录)
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"frontend/**/*.{ts,tsx}": [
|
||||
"bash -c 'cd frontend && npx eslint --fix --max-warnings 0'",
|
||||
"bash -c 'cd frontend && npx prettier --write'"
|
||||
],
|
||||
"frontend/**/*.{css,less,json}": [
|
||||
"bash -c 'cd frontend && npx prettier --write'"
|
||||
],
|
||||
"backend/**/*.go": [
|
||||
"gofmt -s -w",
|
||||
"bash -c 'cd backend && go vet ./...'"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
|
||||
- `bash -c 'cd xxx && ...'` 确保命令在正确的子目录中执行
|
||||
- lint-staged 传递的文件路径是相对于根目录的,部分工具(如 `go vet`)需要在子目录执行
|
||||
- 如果前端和后端各自有 `package.json`,lint-staged 仍然在根目录配置
|
||||
|
||||
---
|
||||
|
||||
## 验证配置
|
||||
|
||||
```bash
|
||||
# 修改一个文件后测试 pre-commit hook
|
||||
echo "// test" >> some-file.ts
|
||||
git add some-file.ts
|
||||
git commit -m "test: verify pre-commit hook"
|
||||
# 应该看到 lint-staged 执行 ESLint + Prettier
|
||||
# 如果有 lint 错误,commit 会被阻止
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 问题 | 原因 | 解决 |
|
||||
|------|------|------|
|
||||
| lint-staged 不执行 | `.husky/pre-commit` 内容不对 | 确认内容为 `npx lint-staged` |
|
||||
| ESLint 报错太多 | 旧项目首次启用 | 先 `npx eslint --fix` 全量修复,再启用 hook |
|
||||
| gofmt 修改后 commit 内容不一致 | lint-staged 自动 format 后需要 re-stage | lint-staged 自动处理,无需手动 |
|
||||
| Monorepo 路径错误 | lint-staged 传递根目录相对路径 | 使用 `bash -c 'cd sub && ...'` 包装 |
|
||||
@@ -0,0 +1,189 @@
|
||||
# Ratchet Script Template
|
||||
|
||||
泛化的 ratchet 脚本模板,基于 new-ai-proj `check-architecture.sh` 提取。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 复制下方脚本到 `scripts/check-{NAME}.sh`
|
||||
2. 替换所有 `{PLACEHOLDER}` 为项目特定值
|
||||
3. 运行 `chmod +x scripts/check-{NAME}.sh`
|
||||
4. 运行 `./scripts/check-{NAME}.sh baseline` 记录首次基线
|
||||
5. 提交脚本和基线文件
|
||||
|
||||
## 脚本模板
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# {DESCRIPTION} Ratchet — ensures new code doesn't increase {WHAT} violations.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/check-{NAME}.sh check # CI / pre-push: fail if violations increased
|
||||
# ./scripts/check-{NAME}.sh baseline # Record current counts (commit the result)
|
||||
# ./scripts/check-{NAME}.sh report # Pretty-print current vs baseline
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
BASELINE_FILE="$SCRIPT_DIR/.{NAME}-baseline.json"
|
||||
TARGET_DIR="$SCRIPT_DIR/../{TARGET_DIRECTORY}"
|
||||
|
||||
# ── rule definitions ────────────────────────────────────────────────
|
||||
# Add/remove rules as needed. Each rule has:
|
||||
# - A name (used as JSON key)
|
||||
# - A type: "ratchet" (baseline can decrease) or "wall" (must be 0)
|
||||
# - A count function
|
||||
|
||||
RULES=({RULE_NAMES}) # e.g. ("rule_one" "rule_two" "rule_three")
|
||||
TYPES=({RULE_TYPES}) # e.g. ("ratchet" "ratchet" "wall")
|
||||
|
||||
# ── counting functions ──────────────────────────────────────────────
|
||||
|
||||
count_rule() {
|
||||
local rule="$1"
|
||||
case "$rule" in
|
||||
{RULE_NAME_1})
|
||||
# Example: count files in {DIR} that import {PACKAGE}
|
||||
grep -rl '{PATTERN_1}' "$TARGET_DIR/{SUBDIR_1}/" 2>/dev/null | wc -l | tr -d ' '
|
||||
;;
|
||||
{RULE_NAME_2})
|
||||
grep -rl '{PATTERN_2}' "$TARGET_DIR/{SUBDIR_2}/" 2>/dev/null | wc -l | tr -d ' '
|
||||
;;
|
||||
# Add more rules...
|
||||
*)
|
||||
echo "0"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ── helpers ─────────────────────────────────────────────────────────
|
||||
|
||||
current_counts() {
|
||||
echo "{"
|
||||
local first=true
|
||||
for rule in "${RULES[@]}"; do
|
||||
local count
|
||||
count=$(count_rule "$rule")
|
||||
$first || echo ","
|
||||
printf ' "%s": %s' "$rule" "${count:-0}"
|
||||
first=false
|
||||
done
|
||||
echo ""
|
||||
echo "}"
|
||||
}
|
||||
|
||||
json_val() {
|
||||
local key="$1" file="$2"
|
||||
grep "\"${key}\"" "$file" | head -1 | sed 's/[^0-9]//g'
|
||||
}
|
||||
|
||||
json_val_str() {
|
||||
local key="$1" json="$2"
|
||||
echo "$json" | grep "\"${key}\"" | head -1 | sed 's/[^0-9]//g'
|
||||
}
|
||||
|
||||
# ── commands ────────────────────────────────────────────────────────
|
||||
|
||||
cmd_baseline() {
|
||||
echo "Recording {NAME} baseline..."
|
||||
current_counts > "$BASELINE_FILE"
|
||||
echo "Baseline written to $BASELINE_FILE"
|
||||
cat "$BASELINE_FILE"
|
||||
}
|
||||
|
||||
cmd_report() {
|
||||
if [[ ! -f "$BASELINE_FILE" ]]; then
|
||||
echo "No baseline found. Run: $0 baseline"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local current
|
||||
current=$(current_counts)
|
||||
|
||||
printf "\n%-35s %10s %10s %8s\n" "Rule" "Baseline" "Current" "Status"
|
||||
printf "%-35s %10s %10s %8s\n" "---" "---" "---" "---"
|
||||
|
||||
for i in "${!RULES[@]}"; do
|
||||
local rule="${RULES[$i]}"
|
||||
local type="${TYPES[$i]}"
|
||||
local base cur status
|
||||
|
||||
base=$(json_val "$rule" "$BASELINE_FILE")
|
||||
cur=$(json_val_str "$rule" "$current")
|
||||
|
||||
if [[ "$type" == "wall" ]]; then
|
||||
[[ "$cur" -eq 0 ]] && status="PASS" || status="FAIL"
|
||||
else
|
||||
[[ "$cur" -le "$base" ]] && status="PASS" || status="FAIL"
|
||||
fi
|
||||
|
||||
printf "%-35s %10d %10d %8s\n" "$rule" "$base" "$cur" "$status"
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
cmd_check() {
|
||||
if [[ ! -f "$BASELINE_FILE" ]]; then
|
||||
echo "ERROR: No baseline found. Run: $0 baseline"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local current
|
||||
current=$(current_counts)
|
||||
local failed=0
|
||||
|
||||
for i in "${!RULES[@]}"; do
|
||||
local rule="${RULES[$i]}"
|
||||
local type="${TYPES[$i]}"
|
||||
local base cur
|
||||
|
||||
base=$(json_val "$rule" "$BASELINE_FILE")
|
||||
cur=$(json_val_str "$rule" "$current")
|
||||
|
||||
if [[ "$type" == "wall" ]]; then
|
||||
if [[ "$cur" -ne 0 ]]; then
|
||||
echo "FAIL [hard wall] $rule: expected 0, got $cur"
|
||||
failed=1
|
||||
fi
|
||||
else
|
||||
if [[ "$cur" -gt "$base" ]]; then
|
||||
echo "FAIL [ratchet] $rule: baseline=$base, current=$cur (+$((cur - base)))"
|
||||
failed=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$failed" -eq 1 ]]; then
|
||||
echo ""
|
||||
echo "{NAME} check FAILED. New violations detected."
|
||||
echo "If this is intentional, update the baseline: $0 baseline"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "{NAME} check PASSED."
|
||||
}
|
||||
|
||||
# ── main ────────────────────────────────────────────────────────────
|
||||
|
||||
case "${1:-check}" in
|
||||
baseline) cmd_baseline ;;
|
||||
report) cmd_report ;;
|
||||
check) cmd_check ;;
|
||||
*)
|
||||
echo "Usage: $0 {check|baseline|report}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
## Placeholder 说明
|
||||
|
||||
| Placeholder | 含义 | 示例 |
|
||||
|-------------|------|------|
|
||||
| `{NAME}` | 脚本短名 | `architecture`, `import-rules` |
|
||||
| `{DESCRIPTION}` | 一句话描述 | `Architecture`, `Import Boundary` |
|
||||
| `{TARGET_DIRECTORY}` | 扫描目标目录(相对于 scripts/) | `backend`, `frontend/src` |
|
||||
| `{RULE_NAMES}` | Bash 数组,规则名列表 | `"handler_db" "route_db"` |
|
||||
| `{RULE_TYPES}` | Bash 数组,规则类型列表 | `"ratchet" "wall"` |
|
||||
| `{PATTERN_N}` | grep 匹配模式 | `"my-pkg/database"` |
|
||||
| `{SUBDIR_N}` | 目标子目录 | `handlers/`, `routes/` |
|
||||
Reference in New Issue
Block a user