diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 6033e05..5d78702 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -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": [ diff --git a/skills-dev/dev-coding-plugin/skills/SKILL.md b/skills-dev/dev-coding-plugin/skills/SKILL.md index 7c9ba06..c8f5d54 100644 --- a/skills-dev/dev-coding-plugin/skills/SKILL.md +++ b/skills-dev/dev-coding-plugin/skills/SKILL.md @@ -808,3 +808,9 @@ fi 4. **小步提交** - 频繁提交,每次做一件事 5. **测试覆盖** - 核心逻辑必须有测试 6. **文档同步** - 代码变更同步更新文档 + +## 相关技能 + +| 技能 | 用途 | 关系 | +|------|------|------| +| `req-test-gate` | 测试与质量门禁 + Harness Engineering | 建立项目质量门禁和约定自动检测,dev-coding 遵守其建立的 CLAUDE.md 约定 | diff --git a/skills-req/req-plugin/skills/SKILL.md b/skills-req/req-plugin/skills/SKILL.md index 5ad1571..98a34c3 100644 --- a/skills-req/req-plugin/skills/SKILL.md +++ b/skills-req/req-plugin/skills/SKILL.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 # 查看关联任务 | `req-prd` | PRD 文档编写 + 评审方法论 | | `req-prototype` | Stitch 原型生成 + 迭代 | | `dev-test` | 测试 + 质量门禁 | +| `req-test-gate` (harness) | 工程约束方法论。Gate 0-2 的约定检查由项目本地脚本定义,方法论见 `/harness` 命令 | diff --git a/skills-req/req-test-gate-plugin/.claude-plugin/plugin.json b/skills-req/req-test-gate-plugin/.claude-plugin/plugin.json index 2d9641e..f567169 100644 --- a/skills-req/req-test-gate-plugin/.claude-plugin/plugin.json +++ b/skills-req/req-test-gate-plugin/.claude-plugin/plugin.json @@ -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" diff --git a/skills-req/req-test-gate-plugin/skills/SKILL.md b/skills-req/req-test-gate-plugin/skills/SKILL.md index 7562a7b..6043989 100644 --- a/skills-req/req-test-gate-plugin/skills/SKILL.md +++ b/skills-req/req-test-gate-plugin/skills/SKILL.md @@ -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: [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: 前置条件检查 @@ -437,9 +476,10 @@ DG6: 生产部署(不可跳过) → 健康检查+文档 ### `/req test` 增强 ``` -v1: Gate 1 → Gate 2 → Gate 3 → Gate 4 +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 流程。 diff --git a/skills-req/req-test-gate-plugin/skills/convention-flow.md b/skills-req/req-test-gate-plugin/skills/convention-flow.md new file mode 100644 index 0000000..15be238 --- /dev/null +++ b/skills-req/req-test-gate-plugin/skills/convention-flow.md @@ -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 --task-ids # linkRole=documentation +ai-proj create-and-attach --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. 输出摘要:约定名称、策略、违规数、文件清单 +``` diff --git a/skills-req/req-test-gate-plugin/skills/harness-engineering.md b/skills-req/req-test-gate-plugin/skills/harness-engineering.md new file mode 100644 index 0000000..ff30e93 --- /dev/null +++ b/skills-req/req-test-gate-plugin/skills/harness-engineering.md @@ -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 | diff --git a/skills-req/req-test-gate-plugin/skills/project-bootstrap.md b/skills-req/req-test-gate-plugin/skills/project-bootstrap.md new file mode 100644 index 0000000..58e5e98 --- /dev/null +++ b/skills-req/req-test-gate-plugin/skills/project-bootstrap.md @@ -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. 输出文件清单和下一步建议 +``` diff --git a/skills-req/req-test-gate-plugin/skills/ratchet-pattern.md b/skills-req/req-test-gate-plugin/skills/ratchet-pattern.md new file mode 100644 index 0000000..8cccecd --- /dev/null +++ b/skills-req/req-test-gate-plugin/skills/ratchet-pattern.md @@ -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 中的正反示例 diff --git a/skills-req/req-test-gate-plugin/skills/templates/convention-script.md b/skills-req/req-test-gate-plugin/skills/templates/convention-script.md new file mode 100644 index 0000000..5db8843 --- /dev/null +++ b/skills-req/req-test-gate-plugin/skills/templates/convention-script.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 中输出敏感数据才违规 diff --git a/skills-req/req-test-gate-plugin/skills/templates/gates-doc.md b/skills-req/req-test-gate-plugin/skills/templates/gates-doc.md new file mode 100644 index 0000000..c662f63 --- /dev/null +++ b/skills-req/req-test-gate-plugin/skills/templates/gates-doc.md @@ -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` 流程管理(单元测试 → 安全扫描 → 构建验证) +- 两者互补,不要混淆编号 diff --git a/skills-req/req-test-gate-plugin/skills/templates/pre-commit-config.md b/skills-req/req-test-gate-plugin/skills/templates/pre-commit-config.md new file mode 100644 index 0000000..7b2a922 --- /dev/null +++ b/skills-req/req-test-gate-plugin/skills/templates/pre-commit-config.md @@ -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 && ...'` 包装 | diff --git a/skills-req/req-test-gate-plugin/skills/templates/ratchet-script.md b/skills-req/req-test-gate-plugin/skills/templates/ratchet-script.md new file mode 100644 index 0000000..0d0671b --- /dev/null +++ b/skills-req/req-test-gate-plugin/skills/templates/ratchet-script.md @@ -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/` |