@chenguangyao/devflow-kit 0.1.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +232 -0
- package/LICENSE +21 -0
- package/README.md +539 -0
- package/bin/devflow.js +9 -0
- package/docs/RFC-001-devflow-kit.md +617 -0
- package/docs/RFC-002-workflow-kernel.md +134 -0
- package/docs/enterprise-integration-supplement.md +274 -0
- package/docs/internal-gitlab-setup.md +426 -0
- package/docs/marketplace-skills.md +231 -0
- package/docs/migration-from-arb.md +232 -0
- package/docs/tooling-overview.md +774 -0
- package/docs/workflow-orchestration.md +695 -0
- package/docs/workflow-ui-prototype.html +271 -0
- package/package.json +52 -0
- package/schemas/config.schema.json +51 -0
- package/schemas/delta.schema.json +22 -0
- package/schemas/state.schema.json +130 -0
- package/schemas/status-surface.schema.json +197 -0
- package/schemas/workflow-confirmation-surface.schema.json +70 -0
- package/schemas/workflow-picker.schema.json +94 -0
- package/scripts/postinstall.js +101 -0
- package/scripts/render-workflow-ui-prototype.js +271 -0
- package/skills/apply/SKILL.md +313 -0
- package/skills/apply/references/discipline-checklist.md +145 -0
- package/skills/apply/references/subagent-implementer-prompt.md +113 -0
- package/skills/apply/references/subagent-orchestration.md +150 -0
- package/skills/apply/references/subagent-reviewer-prompt.md +180 -0
- package/skills/apply/references/tdd-loop.md +287 -0
- package/skills/apply/references/when-plan-is-wrong.md +279 -0
- package/skills/apply/references/worktree-swarm.md +292 -0
- package/skills/archive/SKILL.md +229 -0
- package/skills/archive/references/conflict-resolution.md +336 -0
- package/skills/archive/references/knowledge-deposit.md +381 -0
- package/skills/archive/references/spec-merge.md +365 -0
- package/skills/brainstorm/SKILL.md +123 -0
- package/skills/brainstorm/references/proposal-template.md +244 -0
- package/skills/brainstorm/references/question-catalog.md +168 -0
- package/skills/brainstorm/references/session-template.md +184 -0
- package/skills/ci-fix/SKILL.md +63 -0
- package/skills/ci-fix/references/loop.md +25 -0
- package/skills/code-review/SKILL.md +279 -0
- package/skills/code-review/references/escalation-playbook.md +192 -0
- package/skills/code-review/references/language-cheatsheets/go.md +175 -0
- package/skills/code-review/references/language-cheatsheets/java-spring-mybatis.md +246 -0
- package/skills/code-review/references/language-cheatsheets/python.md +170 -0
- package/skills/code-review/references/language-cheatsheets/vue.md +199 -0
- package/skills/code-review/references/output-template.md +275 -0
- package/skills/code-review/references/review-checklist.md +251 -0
- package/skills/complexity-grading/SKILL.md +259 -0
- package/skills/deliver/SKILL.md +271 -0
- package/skills/deliver/references/delivery-modes.md +299 -0
- package/skills/deliver/references/notify.md +359 -0
- package/skills/deliver/references/pr-description.md +319 -0
- package/skills/dependency-upgrade/SKILL.md +57 -0
- package/skills/dependency-upgrade/references/risk-matrix.md +38 -0
- package/skills/df-orchestrator/SKILL.md +407 -0
- package/skills/df-orchestrator/references/complexity-grading.md +177 -0
- package/skills/df-orchestrator/references/escalation-matrix.md +191 -0
- package/skills/df-orchestrator/references/routing-rules.md +290 -0
- package/skills/df-orchestrator/references/workflow-state-machine.md +208 -0
- package/skills/frontend-quality/SKILL.md +61 -0
- package/skills/frontend-quality/references/checklist.md +35 -0
- package/skills/handoff-resume/SKILL.md +59 -0
- package/skills/handoff-resume/references/handoff-template.md +54 -0
- package/skills/plan/SKILL.md +166 -0
- package/skills/plan/references/task-breakdown.md +207 -0
- package/skills/plan/references/task-sequencing.md +143 -0
- package/skills/plan/references/task-template.md +248 -0
- package/skills/requirement-analysis/SKILL.md +499 -0
- package/skills/requirement-analysis/references/acceptance-criteria.md +183 -0
- package/skills/requirement-analysis/references/code-recon.md +151 -0
- package/skills/requirement-analysis/references/edge-case-catalog.md +164 -0
- package/skills/requirement-analysis/references/requirement-template.md +339 -0
- package/skills/requirement-analysis/references/scope-negotiation.md +162 -0
- package/skills/security-hardening/SKILL.md +60 -0
- package/skills/security-hardening/references/checklist.md +42 -0
- package/skills/tech-spec/SKILL.md +388 -0
- package/skills/tech-spec/references/api-contract-design.md +172 -0
- package/skills/tech-spec/references/decision-records.md +110 -0
- package/skills/tech-spec/references/design-template.md +301 -0
- package/skills/tech-spec/references/rollout-and-rollback.md +203 -0
- package/skills/tech-spec/references/spec-delta-conventions.md +250 -0
- package/skills/tech-spec/references/transaction-patterns.md +212 -0
- package/skills/test-spec/SKILL.md +219 -0
- package/skills/test-spec/references/coverage-strategy.md +218 -0
- package/skills/test-spec/references/edge-case-to-test.md +143 -0
- package/skills/test-spec/references/test-case-template.md +276 -0
- package/skills/verify/SKILL.md +232 -0
- package/skills/verify/references/nfr-verification.md +292 -0
- package/skills/verify/references/report-templates.md +510 -0
- package/skills/verify/references/self-test-guide.md +240 -0
- package/skills/verify/references/verify-rollback-map.md +247 -0
- package/src/cli/commands/_helpers.js +108 -0
- package/src/cli/commands/_submit.js +718 -0
- package/src/cli/commands/apply.js +198 -0
- package/src/cli/commands/archive.js +180 -0
- package/src/cli/commands/checkpoint.js +113 -0
- package/src/cli/commands/deliver.js +377 -0
- package/src/cli/commands/deploy.js +504 -0
- package/src/cli/commands/design.js +158 -0
- package/src/cli/commands/disable.js +21 -0
- package/src/cli/commands/doctor.js +178 -0
- package/src/cli/commands/enable.js +21 -0
- package/src/cli/commands/flow.js +645 -0
- package/src/cli/commands/help.js +93 -0
- package/src/cli/commands/ingest.js +602 -0
- package/src/cli/commands/init.js +341 -0
- package/src/cli/commands/knowledge.js +523 -0
- package/src/cli/commands/logs.js +43 -0
- package/src/cli/commands/new.js +202 -0
- package/src/cli/commands/plan.js +49 -0
- package/src/cli/commands/propose.js +27 -0
- package/src/cli/commands/provider.js +698 -0
- package/src/cli/commands/report.js +143 -0
- package/src/cli/commands/requirement.js +227 -0
- package/src/cli/commands/review.js +301 -0
- package/src/cli/commands/skills.js +457 -0
- package/src/cli/commands/status.js +925 -0
- package/src/cli/commands/switch.js +27 -0
- package/src/cli/commands/sync.js +47 -0
- package/src/cli/commands/test.js +366 -0
- package/src/cli/commands/uninstall.js +32 -0
- package/src/cli/commands/update.js +74 -0
- package/src/cli/commands/verify.js +354 -0
- package/src/cli/commands/worktree.js +78 -0
- package/src/cli/index.js +72 -0
- package/src/cli/parse-args.js +102 -0
- package/src/core/autodetect.js +271 -0
- package/src/core/change.js +208 -0
- package/src/core/checkpoint.js +217 -0
- package/src/core/config.js +60 -0
- package/src/core/delta.js +290 -0
- package/src/core/markers.js +59 -0
- package/src/core/paths.js +173 -0
- package/src/core/plan-tasks.js +36 -0
- package/src/core/project-routing.js +285 -0
- package/src/core/projects.js +200 -0
- package/src/core/state.js +200 -0
- package/src/core/workflow-check.js +177 -0
- package/src/core/workflow-init.js +34 -0
- package/src/core/workflow-picker.js +154 -0
- package/src/core/workflow-policy.js +119 -0
- package/src/core/workflow-suggest.js +181 -0
- package/src/core/workflow-verify.js +88 -0
- package/src/core/workflow.js +433 -0
- package/src/core/worktree.js +241 -0
- package/src/knowledge/categories.js +107 -0
- package/src/knowledge/classify.js +125 -0
- package/src/knowledge/deposit.js +414 -0
- package/src/knowledge/migrate.js +149 -0
- package/src/knowledge/mr.js +219 -0
- package/src/knowledge/query.js +131 -0
- package/src/knowledge/registry.js +151 -0
- package/src/knowledge/sync.js +179 -0
- package/src/providers/base.js +74 -0
- package/src/providers/drivers/api-yapi.js +78 -0
- package/src/providers/drivers/ci-jenkins.js +109 -0
- package/src/providers/drivers/intake-confluence.js +544 -0
- package/src/providers/drivers/kb-git.js +549 -0
- package/src/providers/drivers/kb-weknora.js +472 -0
- package/src/providers/drivers/notify-smtp.js +515 -0
- package/src/providers/drivers/observability-oss.js +43 -0
- package/src/providers/drivers/observability-sls.js +50 -0
- package/src/providers/lifecycle.js +135 -0
- package/src/providers/loader.js +132 -0
- package/src/providers/local.js +190 -0
- package/src/providers/userconfig.js +283 -0
- package/src/reports/aggregate.js +185 -0
- package/src/reports/coverage.js +163 -0
- package/src/reports/detect.js +143 -0
- package/src/reports/parse.js +236 -0
- package/src/templates/files/ci/github.yml +38 -0
- package/src/templates/files/ci/gitlab.yml +27 -0
- package/src/templates/files/design.md +63 -0
- package/src/templates/files/ide/devflow-workflow.md +58 -0
- package/src/templates/files/ide/project-overview-reference.md +1 -0
- package/src/templates/files/ide/project-overview.md +27 -0
- package/src/templates/files/knowledge-index.json +17 -0
- package/src/templates/files/knowledge.md +28 -0
- package/src/templates/files/meta.json +8 -0
- package/src/templates/files/plan.md +38 -0
- package/src/templates/files/proposal.md +33 -0
- package/src/templates/files/reports/contract-test.md +40 -0
- package/src/templates/files/reports/e2e-test.md +30 -0
- package/src/templates/files/reports/integration-test.md +36 -0
- package/src/templates/files/reports/joint-test.md +58 -0
- package/src/templates/files/reports/perf.md +24 -0
- package/src/templates/files/reports/regression.md +20 -0
- package/src/templates/files/reports/remote-test.md +55 -0
- package/src/templates/files/reports/self-test.md +43 -0
- package/src/templates/files/reports/smoke-test.md +22 -0
- package/src/templates/files/reports/unit-test.md +36 -0
- package/src/templates/files/requirement.md +51 -0
- package/src/templates/files/review.md +38 -0
- package/src/templates/files/tests.md +36 -0
- package/src/templates/files/verify.md +32 -0
- package/src/templates/index.js +21 -0
- package/src/utils/log.js +37 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devflow-code-review
|
|
3
|
+
description: |
|
|
4
|
+
devflow-kit 流程中,当用户提及 "代码审查"、"Code Review"、"CR"、"代码检视"、"代码走查"、"review 代码"、"审一下代码",
|
|
5
|
+
或 apply 阶段产出代码后需要质量把关时,必须立刻触发本 skill。独立 reviewer 视角,基于 design.md /
|
|
6
|
+
requirement.md / tests.md(若存在) / plan.md 的测试字段逐项核对代码实现,产出结构化审查结论与 feedbackIssues 供下一轮 apply 修复。
|
|
7
|
+
若用户意图是整体开发流程,由 `devflow-df-orchestrator` 统一编排;若只需单独执行这一步,直接触发本 skill。
|
|
8
|
+
when_to_use: |
|
|
9
|
+
apply 阶段的所有任务已 done、单元测试已跑过(`devflow test unit` 产出 `reports/test-report.md#unit`)之后,
|
|
10
|
+
由 `devflow review --round` 或 `/df:review` 触发。也可以在 bugfix 轮次(iteration N>0)重复触发。
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# code-review
|
|
14
|
+
|
|
15
|
+
独立代码审查 skill。3 轮硬闭环,每轮产 structured findings;MUST > 0 → 回 apply;round 3 若仍 MUST > 0 → hard-block(需 `--force-pass --reason` 审计放行)。
|
|
16
|
+
|
|
17
|
+
## 独立审查身份(硬规则)
|
|
18
|
+
|
|
19
|
+
- 本 skill 以**独立 reviewer** 身份执行,上下文隔离于 apply 过程,模拟"换人审查"。
|
|
20
|
+
- Reviewer **不参考** coding agent 的对话历史、不认同 coder 自述的"我这么写是因为…",仅基于:
|
|
21
|
+
- `git diff <baseBranch>...HEAD` 的实际代码
|
|
22
|
+
- `design.md`(实现契约)
|
|
23
|
+
- `requirement.md`(功能与边界契约)
|
|
24
|
+
- `tests.md`(若存在)或 `plan.md` 每个 task 的 Test 字段
|
|
25
|
+
- `reports/test-report.md#unit`(自测结果,如有)
|
|
26
|
+
- 若上一轮 review 已留 findings,本轮**继承未 resolved 项**并聚焦复核。
|
|
27
|
+
|
|
28
|
+
## 前置检查(任一必需项缺失则停止并询问用户)
|
|
29
|
+
|
|
30
|
+
| 输入项 | 必需 | 缺失时行为 |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| 代码变更(git diff) | 是 | 停止并要求用户提供 baseBranch 或确认不在 git worktree |
|
|
33
|
+
| `design.md` | 是(L2/L3)/ 可选(L1) | L1 bug fix 若无 design.md 可用 `requirement.md` + diff 进行;L2/L3 缺失直接 BLOCKED |
|
|
34
|
+
| `requirement.md` | 是 | 缺失直接 BLOCKED(无法做需求覆盖度扫描) |
|
|
35
|
+
| `tests.md` | 可选 | 存在时做 TC 对照;缺失时用 plan.md 的 Test 字段和 requirement.md 的 AC 做覆盖检查 |
|
|
36
|
+
| `reports/test-report.md#unit` | 否 | 若存在,相信其 PASS 结果,只复核 FAIL 与未覆盖项 |
|
|
37
|
+
| `baseBranch` | 否 | 默认 `master` / `main`,自动探测;可由 `devflow apply` 的 worktree 元数据传入 |
|
|
38
|
+
| `iterationCount` | 否 | 由 `state.json.phases.review.rounds.length` 推导;第 1 轮起算 |
|
|
39
|
+
|
|
40
|
+
## Step 0:先跑工具(必须在 AI 审查前)
|
|
41
|
+
|
|
42
|
+
> **核心原则**:工具能自动发现的问题不让 AI 重新发现 —— AI 专注工具覆盖不到的地方。
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# 1. 获取变更列表
|
|
46
|
+
git diff --name-only <baseBranch>...HEAD
|
|
47
|
+
|
|
48
|
+
# 2. 按语言运行已有工具(用项目里现有配置,不要新装)
|
|
49
|
+
# Go
|
|
50
|
+
golangci-lint run ./... 2>&1
|
|
51
|
+
go vet ./... 2>&1
|
|
52
|
+
|
|
53
|
+
# Java
|
|
54
|
+
mvn checkstyle:check 2>&1 | tail -30 # 或 ./gradlew checkstyleMain
|
|
55
|
+
mvn compile 2>&1 | grep -E "ERROR|WARNING" | tail -20
|
|
56
|
+
|
|
57
|
+
# Node / TypeScript
|
|
58
|
+
npx eslint . --max-warnings=0 2>&1 | tail -30
|
|
59
|
+
npx tsc --noEmit 2>&1 | tail -20
|
|
60
|
+
|
|
61
|
+
# Python
|
|
62
|
+
ruff check . 2>&1 | tail -30 # 或 flake8/pylint
|
|
63
|
+
mypy . 2>&1 | tail -20
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**工具输出处理规则:**
|
|
67
|
+
- 工具报 0 错误 → 直接跳过该维度,不重复检查
|
|
68
|
+
- 工具报错误 → 列入 findings(标注 `source: tooling`),不需要 AI 再分析原因
|
|
69
|
+
- NIT 级别的 style issue,工具输出即结论,AI 不重复描述
|
|
70
|
+
|
|
71
|
+
**AI 审查只覆盖工具盲区:**
|
|
72
|
+
|
|
73
|
+
| 维度 | 工具能覆盖 | AI 额外覆盖 |
|
|
74
|
+
| --- | --- | --- |
|
|
75
|
+
| 语法 / 格式 / 命名 | ✅ linter/formatter | 仅工具未覆盖的语义命名 |
|
|
76
|
+
| 类型安全 | ✅ type-checker | 业务类型语义是否合理 |
|
|
77
|
+
| 需求覆盖度 | ❌ | **全部由 AI** |
|
|
78
|
+
| 设计 / 契约对齐 | ❌ | **全部由 AI** |
|
|
79
|
+
| 业务逻辑正确性 | ❌ | **全部由 AI** |
|
|
80
|
+
| 安全(注入 / 泄漏) | 部分 semgrep | AI 补充业务特定风险 |
|
|
81
|
+
| 并发 / 事务边界 | ❌ | **全部由 AI** |
|
|
82
|
+
|
|
83
|
+
若项目没有配置 linter,在 `review.md` 开头注明 `linting: unconfigured`,建议补配置,然后 AI 按全维度扫。
|
|
84
|
+
|
|
85
|
+
## 代码获取方式
|
|
86
|
+
|
|
87
|
+
优先通过 git diff 获取本次变更,不要读全量文件 —— review 只关注改动:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git diff --name-only <baseBranch>...HEAD # 文件列表
|
|
91
|
+
git diff <baseBranch>...HEAD # 带上下文的变更内容
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
若当前不在 git worktree(如 `--no-worktree` 模式),从 `state.json.phases.apply.tasks[].files` 读取 coder 声明的改动文件清单。
|
|
95
|
+
|
|
96
|
+
## 变更范围分类(节 token,跳过不相关步骤)
|
|
97
|
+
|
|
98
|
+
按 `git diff --name-only` 的文件列表判定变更范围,只跑相关检查:
|
|
99
|
+
|
|
100
|
+
| 变更范围 | 判定条件(示例) | 跳过的子检查 |
|
|
101
|
+
| --- | --- | --- |
|
|
102
|
+
| `data-layer` | 仅 SQL / migration / schema / ORM mapper | 跳过 UX / 前端契约 / 性能基线 |
|
|
103
|
+
| `test-only` | 仅 `*_test.*` / `test/**/*` / `spec/**` | 仅做"测试代码质量 + 断言有效性"检查 |
|
|
104
|
+
| `api-change` | 含 Controller / Handler / Route / DTO / Request / Response / OpenAPI | 执行全部维度 |
|
|
105
|
+
| `config-only` | 仅 `*.yaml` / `*.toml` / `*.env` | 只做"配置漂移 + 环境一致性"检查 |
|
|
106
|
+
| `docs-only` | 仅 `*.md` / `docs/**` | 只做"文档与代码/接口一致性"检查,不跑代码检查 |
|
|
107
|
+
| `full` | 其他(跨多层) | 执行全部维度 |
|
|
108
|
+
|
|
109
|
+
规则:按文件列表匹配,**取最宽的范围**;无法判定默认 `full`。
|
|
110
|
+
|
|
111
|
+
## 审查维度(按这 7 个维度逐项检查)
|
|
112
|
+
|
|
113
|
+
| 维度 | 关注点 | 详见 |
|
|
114
|
+
| --- | --- | --- |
|
|
115
|
+
| Correctness | 实现是否符合 design.md?业务逻辑、边界、并发 | `references/review-checklist.md` §1 |
|
|
116
|
+
| Completeness | requirement.md 的 BEHAVIOR / EDGE CASES 每条都有代码 + 测试? | `references/review-checklist.md` §2 |
|
|
117
|
+
| Security | 输入校验、鉴权、密钥、日志脱敏、资源泄漏 | `references/review-checklist.md` §3 |
|
|
118
|
+
| Performance | 明显的 N+1 / O(N²)、无界循环、不必要的同步阻塞 | `references/review-checklist.md` §4 |
|
|
119
|
+
| Maintainability | 命名、注释、魔法值、重复、职责单一、长函数 | `references/review-checklist.md` §5 |
|
|
120
|
+
| Tests | 用例 ↔ tests.md 一一对照;断言有效;Mock 合理;无 skip/only | `references/review-checklist.md` §6 |
|
|
121
|
+
| Observability / Migration | 日志 / 指标 / 告警 / DDL 可重入 / 回滚预案 | `references/review-checklist.md` §7 |
|
|
122
|
+
|
|
123
|
+
> 不要在 SKILL.md 里重复这些检查项的具体条目 —— 审查时打开 `references/review-checklist.md` 按维度逐项打勾。
|
|
124
|
+
|
|
125
|
+
## 按项目语言自动加载 cheatsheet(全语言支持)
|
|
126
|
+
|
|
127
|
+
通用 checklist 是语言无关的骨架。每门语言还有自己的踩坑习语,放在 `references/language-cheatsheets/*.md`。reviewer 必须按下面规则**挑选 1-2 份** cheatsheet 一起读(不相关的不要加载,节 token)。
|
|
128
|
+
|
|
129
|
+
### 挑选规则
|
|
130
|
+
|
|
131
|
+
1. 读 `devflow/config.json` 的 `detect.language`(由 `devflow init` 写入)拿初始语言。
|
|
132
|
+
2. 再看本次 `git diff --name-only` 的文件扩展名,若变更涉及多种语言(monorepo),每种语言各加载一份 cheatsheet。
|
|
133
|
+
3. 同一语言内再按下面"二级判定"选具体 cheatsheet 版本(框架差异大的才分叉):
|
|
134
|
+
|
|
135
|
+
| detect.language | 二级判定信号(文件 / 依赖) | 挑选 cheatsheet |
|
|
136
|
+
| --- | --- | --- |
|
|
137
|
+
| `java` | `pom.xml` 或 `build.gradle` 含 `mybatis` / `*Mapper.xml` 文件存在 | `java-spring-mybatis.md` |
|
|
138
|
+
| `java` | 含 `spring-data-jpa` / `hibernate` / `@Entity` 广泛使用 | `java-spring-jpa.md`(暂未提供 → 先用 `java-spring-mybatis.md` §1/§4/§5/§6/§7/§8,跳 §2/§3) |
|
|
139
|
+
| `go` | 任何情况 | `go.md` |
|
|
140
|
+
| `python` | 任何情况(Django / FastAPI / Flask 共用一份) | `python.md` |
|
|
141
|
+
| `node` | `package.json` 的 `dependencies` 含 `vue` | `vue.md` |
|
|
142
|
+
| `node` | 含 `react` | (暂未提供 → 仅用通用 checklist,在 findings 里标注 `cheatsheet_missing: react`) |
|
|
143
|
+
| `node` 纯后端(express / nestjs / koa) | 无前端框架依赖 | (暂未提供 → 仅用通用 checklist,标注 `cheatsheet_missing: node-backend`) |
|
|
144
|
+
| 其他 / `unknown` | — | 仅用通用 checklist;在 `review.md` 开头 note 语言未识别 |
|
|
145
|
+
|
|
146
|
+
### 多语言组合例子
|
|
147
|
+
|
|
148
|
+
- 一个 Vue 前端 + Go 后端 monorepo,本轮 diff 涉及 `src/**/*.vue` 和 `server/**/*.go`:同时加载 `vue.md` + `go.md`。
|
|
149
|
+
- 一个 Java 后端项目,本轮 diff 只改了 `*.sql` + `*Mapper.xml`:只加载 `java-spring-mybatis.md`(通用 checklist 用 `data-layer` diffScope 跳过无关维度)。
|
|
150
|
+
- 一个 FastAPI + Vue 的项目:`python.md` + `vue.md`,各自按维度报告。
|
|
151
|
+
|
|
152
|
+
### cheatsheet 缺失时
|
|
153
|
+
|
|
154
|
+
在 `review.md` 开头加一段:
|
|
155
|
+
|
|
156
|
+
```markdown
|
|
157
|
+
> [!NOTE] Language cheatsheet missing: <lang>
|
|
158
|
+
> 本次审查未找到 `<lang>` 的 cheatsheet,仅按通用 checklist 进行。
|
|
159
|
+
> 建议后续补充至 `skills/code-review/references/language-cheatsheets/<lang>.md`。
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
并在 `review.findings.json` 的 top-level 加 `cheatsheetMissing: ["<lang>"]` 字段,方便 `devflow doctor audit` 统计。
|
|
163
|
+
|
|
164
|
+
### 禁止反模式
|
|
165
|
+
|
|
166
|
+
- **把所有 cheatsheet 一起加载**:极度浪费 token;且无关语言的条目会诱导 reviewer 误报 finding。
|
|
167
|
+
- **忽略 cheatsheet 直接按通用 checklist**:会漏掉语言特有的高危坑(如 Go nil interface、Java MyBatis 全链路、Python 可变默认参数、Vue ref 漏 .value)。
|
|
168
|
+
- **自己临时"加一条规则"而不先查 cheatsheet**:reviewer 的个人习惯不应取代沉淀;如确实发现新坑,记录到下次 cheatsheet 更新。
|
|
169
|
+
|
|
170
|
+
## 严重度(MUST / SHOULD / NIT,`devflow review` 只识别这三个词)
|
|
171
|
+
|
|
172
|
+
| 级别 | 含义 | 处理要求 | fixMode |
|
|
173
|
+
| --- | --- | --- | --- |
|
|
174
|
+
| **MUST** | 阻塞:正确性 / 安全 / 数据丢失 / 契约破坏 / 需求覆盖缺失 / 状态值不一致 | 必须修复才能通过 | 通常 REVIEW |
|
|
175
|
+
| **SHOULD** | 严重:风险 / 可维护性 / 性能 / UX 降级 | 强烈建议修;本轮可以降级放行,但要写 "accepted with justification" | 常见 REVIEW,少量 AUTO-FIX |
|
|
176
|
+
| **NIT** | 一般:风格、命名、排版 | 可选修;连续 3 轮仍未修由 reviewer 决定去留 | AUTO-FIX |
|
|
177
|
+
|
|
178
|
+
判定矩阵与实例见 `references/review-checklist.md` §严重度速查。
|
|
179
|
+
|
|
180
|
+
## 3 轮闭环 CLI 契约
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
round 1 devflow review --slug=<slug> --round
|
|
184
|
+
↳ MUST > 0 → outcome=back_to_apply → phases.apply.status=in_progress,去 apply 修
|
|
185
|
+
↳ MUST = 0 → outcome=pass → phases.review.status=completed,创建 verify_start 检查点,等待用户确认
|
|
186
|
+
|
|
187
|
+
round 2 devflow review --slug=<slug> --round
|
|
188
|
+
↳ 同上逻辑,MUST 计数继承 round 1 未 resolved 项 + 本轮新发现
|
|
189
|
+
|
|
190
|
+
round 3 devflow review --slug=<slug> --round
|
|
191
|
+
↳ MUST > 0 → outcome=BLOCKED, exit 1
|
|
192
|
+
三选一:
|
|
193
|
+
a) 回 apply 修复后 `devflow review --slug=<slug> --round --continue-rounds` (审计)
|
|
194
|
+
b) `devflow review --slug=<slug> --force-pass --reason="..."` (审计)
|
|
195
|
+
c) 回 tech-spec 重设计 design.md(多半是设计缺陷,见下)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`devflow review --round` 读 `review.md`:解析 `MUST` / `SHOULD` / `NIT` 字面出现次数(大小写敏感,表格行内出现计数);也可以 headless `--must=N --should=M --nit=K` 手动给。
|
|
199
|
+
|
|
200
|
+
## 输出契约
|
|
201
|
+
|
|
202
|
+
审查产物分两个文件,不可合并:
|
|
203
|
+
|
|
204
|
+
1. **`review.md`** —— 每轮 append 一个 section(Round N),**人类可读**。模板见 `references/output-template.md` §1。
|
|
205
|
+
2. **`review.findings.json`** —— 机器可解析,`state.json` 里 `phases.review.rounds[N].findingsPath` 指向它。**下一轮 apply 用它自动定位修复位置**。Schema 见 `references/output-template.md` §2。
|
|
206
|
+
|
|
207
|
+
`devflow review --round` 保证两者同步写入,丢一个就报 inconsistency。
|
|
208
|
+
|
|
209
|
+
## 引爆路径(超出 3 轮怎么办)
|
|
210
|
+
|
|
211
|
+
**同一 MUST 跨 2 轮复现 ≠ coder 没改**,更可能是 design 本身漏了 —— 别再迭代 apply,回 tech-spec 重开一轮。
|
|
212
|
+
|
|
213
|
+
完整路径(设计缺陷 / 需求偏差 / reviewer-applier 冲突)见 `references/escalation-playbook.md`。
|
|
214
|
+
|
|
215
|
+
## 反模式(踩了直接 back_to_apply 或 BLOCKED)
|
|
216
|
+
|
|
217
|
+
- **带着未 resolved MUST 盖 `pass`**:用 `--force-pass --reason="..."` 走审计,不要作弊改 `state.json`。
|
|
218
|
+
- **只看 diff,不比对 `design.md` / `requirement.md`**:会漏掉"要求做但没做"这一类最危险的缺失。
|
|
219
|
+
- **跳过 2.6 需求覆盖度扫描**(见 `references/review-checklist.md` §2):会放过隐性遗漏。
|
|
220
|
+
- **用第 4 轮 review**:没有 `--continue-rounds` 会被 CLI 拒绝。第 4 轮意味着之前的评审没抓住要害 —— 先反省。
|
|
221
|
+
- **把 MUST/SHOULD/NIT 当叙事词写进正文**:`devflow review` 会把散文里的 "should" / "must" 也计数;只在 findings 表格的 `level` 列用它们,其他地方用小写。
|
|
222
|
+
- **在 docs-only 变更里逐行审代码**:变更范围分类就是为了避免这种无意义 token 消耗。
|
|
223
|
+
|
|
224
|
+
## 完成状态协议
|
|
225
|
+
|
|
226
|
+
执行完毕必须输出(被 df-orchestrator 解析):
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
---STATUS---
|
|
230
|
+
result: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_INPUT
|
|
231
|
+
outputs:
|
|
232
|
+
- devflow/changes/<slug>/review.md
|
|
233
|
+
- devflow/changes/<slug>/review.findings.json
|
|
234
|
+
round: N
|
|
235
|
+
mustCount: K
|
|
236
|
+
shouldCount: K
|
|
237
|
+
nitCount: K
|
|
238
|
+
outcome: pass | back_to_apply | blocked | force-pass
|
|
239
|
+
---END_STATUS---
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**下一步卡片(硬约束)**:
|
|
243
|
+
|
|
244
|
+
每一轮 review 结束,都必须在用户可见正文最后展示下一步卡片。不能只列 findings、变更和校验,不能只写 `---STATUS---`,也不能让用户猜下一步。
|
|
245
|
+
|
|
246
|
+
```markdown
|
|
247
|
+
## 下一步
|
|
248
|
+
状态:DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_INPUT
|
|
249
|
+
审查结果:pass | back_to_apply | blocked | force-pass
|
|
250
|
+
下一步:[一句话说明]
|
|
251
|
+
命令:`<nextAction command>`
|
|
252
|
+
需要你确认:[是否开始 verify / 是否回 apply 修复 / 是否接受风险放行 / 需要补充的信息]
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
按 outcome 填写:
|
|
256
|
+
|
|
257
|
+
- `pass`:说明 review 已通过,但不得自动执行 verify;状态填 `NEEDS_INPUT`,等待用户在**本轮 review 通过之后**明确确认是否允许进入验证。命令只写:`devflow checkpoint resolve --id=<checkpoint-id> --decision=start-verify`。不得把它和 `devflow verify --slug=<slug>` 串成一条命令。
|
|
258
|
+
- `back_to_apply`:列出 MUST / SHOULD 摘要,下一步回 apply 修复;命令:`devflow apply --slug=<slug> --task=<id> --resume` 或 `devflow apply --slug=<slug> --task=<id> --note="fix review findings"`。
|
|
259
|
+
- `blocked`:不要给推进命令;必须说明解除阻塞的最小动作,例如补齐 design/tests、修复无法运行的检查、回 tech-spec 重设计。
|
|
260
|
+
- `force-pass`:必须列出已接受风险和审计原因;仍然不得自动执行 verify,等待用户在 force-pass 之后重新确认;命令只写:`devflow checkpoint resolve --id=<checkpoint-id> --decision=start-verify`。不得把它和 `devflow verify --slug=<slug>` 串成一条命令。
|
|
261
|
+
|
|
262
|
+
**verify_start 确认硬规则**:
|
|
263
|
+
|
|
264
|
+
- 早前在 apply / plan / requirement 阶段说过的"继续"、"按推荐"、"剩余按推荐"、"继续吧",不能被复用为 review 通过后的 verify 确认。
|
|
265
|
+
- 用户必须在本轮 review pass / force-pass 的下一步卡片出现之后,重新明确回复"开始验证"、"确认进入 verify"、"允许 verify"或执行 checkpoint resolve 命令。
|
|
266
|
+
- 在收到上述新确认前,agent 只能展示下一步卡片或运行 `devflow status`,不得调用 `devflow verify`、`devflow test`、Jenkins、部署或任何验证动作。
|
|
267
|
+
- 即使用户回复"继续",也只能执行 `devflow checkpoint resolve --id=<checkpoint-id> --decision=start-verify`;resolve 完成后必须再次停止并提示下一条命令 `devflow verify --slug=<slug>`,不能在同一轮继续执行。
|
|
268
|
+
|
|
269
|
+
## 参考
|
|
270
|
+
|
|
271
|
+
- [`references/review-checklist.md`](references/review-checklist.md) — 7 维度逐项清单 + 正反例 + 严重度判定矩阵
|
|
272
|
+
- [`references/output-template.md`](references/output-template.md) — `review.md` 每轮模板 + `review.findings.json` schema + `code-review-report.md` 规范
|
|
273
|
+
- [`references/escalation-playbook.md`](references/escalation-playbook.md) — 超轮 / 设计缺陷 / reviewer-applier 冲突的处置流程
|
|
274
|
+
- [`references/language-cheatsheets/`](references/language-cheatsheets/) — 按语言挑选 1-2 份一起读:
|
|
275
|
+
- `java-spring-mybatis.md` — Java + Spring Boot + MyBatis(含 DDL-DO 一致性、全链路字段、@Transactional 坑、JUnit 5 + Mockito)
|
|
276
|
+
- `go.md` — Go(nil 安全、goroutine 泄漏、context、gorm/sqlc、testify)
|
|
277
|
+
- `python.md` — Python(可变默认参数、asyncio、SQLAlchemy / Django ORM、pytest、FastAPI / Django / DRF)
|
|
278
|
+
- `vue.md` — Vue 3 + TypeScript(响应性、Composition API、Pinia、路由鉴权、Vitest)
|
|
279
|
+
- 其他语言(React / Rust / Node 纯后端等)按"挑选规则"章节处置,按需补充
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# code-review / escalation-playbook
|
|
2
|
+
|
|
3
|
+
3 轮是硬上限。大部分任务在第 2 轮就该收敛。如果 MUST 还在冒出来,**问题不在 coder**,先按本文诊断根因,对应升级处置。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 什么时候走这个 playbook
|
|
8
|
+
|
|
9
|
+
下面任一信号出现,立即停下当前 review,按对应 path 走:
|
|
10
|
+
|
|
11
|
+
| 信号 | 根因分类 | 处置 path |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| round 1 MUST=0、round 2 MUST>0 又冒出一批新的 | 需求理解偏差 | path A |
|
|
14
|
+
| 同一 MUST 或等价问题跨 2 轮都没修掉 | 设计缺陷或 coder 能力/上下文不足 | path B |
|
|
15
|
+
| round 3 结束仍有 MUST | 上面两类之一的终局 | path C |
|
|
16
|
+
| reviewer 与 coder 对"是不是 MUST"反复争论 | reviewer-applier 冲突 | path D |
|
|
17
|
+
| MUST 里有 `fixMode: SPEC` 超过 1 项 | 方案问题 | path B |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Path A:需求理解偏差 —— 回 requirement.md
|
|
22
|
+
|
|
23
|
+
### 识别
|
|
24
|
+
|
|
25
|
+
- 新发现的 MUST 集中在 `dimension: completeness` 或"实现不符合 requirement.md"
|
|
26
|
+
- coder 在 `apply.md` 里说"这段是按需求 X 做的",但 requirement.md 根本没明确
|
|
27
|
+
- 代码实现的业务规则与 QA / PM 读 requirement.md 的理解不一致
|
|
28
|
+
|
|
29
|
+
### 处置步骤
|
|
30
|
+
|
|
31
|
+
1. **暂停 review**,outcome 置 `back_to_apply` 但附加 `reason: "requirement_ambiguous"`。
|
|
32
|
+
2. 在 `review.md` 当前 round 末尾加一个 `## 需求澄清请求` section,列出所有 ambiguous 的点。
|
|
33
|
+
3. 回到 intake / brainstorming 阶段:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
devflow status # 确认当前在 review
|
|
37
|
+
devflow brainstorming --from review # 把 review 里的澄清请求作为 input 重启 brainstorming
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
4. brainstorming 产出新的 `requirement.md`(增量 delta),由 df-orchestrator 决定是否需要重跑 tech-spec。
|
|
41
|
+
5. 回到 apply 继续,`iterationCount` 不自增(因为这一轮不算 coder 的问题)。
|
|
42
|
+
|
|
43
|
+
### 防御:下次避免
|
|
44
|
+
|
|
45
|
+
- requirement.md 里每条 BEHAVIOR / EDGE CASE 都要有可验证的断言(例子:"超 100 次/天 → 返回 429" 而不是"不能被刷")。
|
|
46
|
+
- brainstorming 阶段用 clarifying questions 强制暴露 ambiguous 项;arb 的 L1/L2/L3 复杂度分级就是为此,复杂度高的强制 clarification rounds ≥ 2。
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Path B:设计缺陷 —— 回 tech-spec / design.md
|
|
51
|
+
|
|
52
|
+
### 识别
|
|
53
|
+
|
|
54
|
+
- 同一 MUST 在 round 2 仍未 resolved,且 coder 在 apply.md 里写"按原设计改不过去"
|
|
55
|
+
- findings 里出现 `fixMode: SPEC` ≥ 1
|
|
56
|
+
- MUST 集中在 `dimension: correctness` 的"并发 / 事务 / 接口契约"
|
|
57
|
+
- 修一个问题引出另外两个问题(改 A 崩 B)—— 模块职责 / 依赖关系本身有问题
|
|
58
|
+
|
|
59
|
+
### 处置步骤
|
|
60
|
+
|
|
61
|
+
1. **暂停 review**,outcome 置 `blocked`,在 `review.md` 写 `## 设计回退请求`。
|
|
62
|
+
2. 收集 evidence:所有跨轮复现或 `fixMode: SPEC` 的 finding ID。
|
|
63
|
+
3. 回到 tech-spec 阶段:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
devflow tech-spec --revise --from review
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
这个命令会把当前 `design.md` 移到 `design.v1.md`(保留历史),并以 review findings 为输入重新产出 `design.md`(v2)。
|
|
70
|
+
|
|
71
|
+
4. 新设计评审通过后,回到 plan 阶段:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
devflow plan --redo # 根据 design v2 重新出 tasks.md,已完成的任务保留 done 状态
|
|
75
|
+
devflow apply # 从头跑,review 计数归零(新设计是新 review context)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
5. 归档时两个 design 版本都保留在 `archive/<slug>/` 里,作为学习素材。
|
|
79
|
+
|
|
80
|
+
### 防御
|
|
81
|
+
|
|
82
|
+
- tech-spec 产出时要强制"并发 / 事务 / 接口契约"三项的显式设计(而不是默认值)。
|
|
83
|
+
- design.md 的"决策记录"section 要写明 trade-off,避免 coder 只能猜。
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Path C:round 3 结束仍有 MUST —— hard block,3 选 1
|
|
88
|
+
|
|
89
|
+
### 处置步骤
|
|
90
|
+
|
|
91
|
+
`devflow review --round` 在 round 3 发现 MUST>0 会直接 exit 1。三种合法放行方式:
|
|
92
|
+
|
|
93
|
+
### C.1 回 apply 再修,但要用 `--continue-rounds`(审计)
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
devflow review --round --continue-rounds
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- 这会开第 4 轮及以后,**每一轮都写进 state.json 的 audit log**。
|
|
100
|
+
- 仅当 MUST 已知、范围收敛、预期一轮内能修完时用。
|
|
101
|
+
- `state.json.phases.review.audit[]` 里会多一条 `{ type: "continue-rounds", reason, operator, at }`,PR 里也会强制展示。
|
|
102
|
+
|
|
103
|
+
### C.2 接受 MUST 放行(`--force-pass --reason`)
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
devflow review --force-pass --reason="CR-102 已在 hotfix 分支单独上线,此处只做回刷"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- reason 必填且 ≥ 10 字符;
|
|
110
|
+
- 审计同上,进入 PR description 永久留档;
|
|
111
|
+
- `finalOutcome=force-pass`,下游 verify/deliver 不会再次拦截,但会在 PR 模板里自动挂 `needs-post-merge-followup` 标签。
|
|
112
|
+
|
|
113
|
+
### C.3 回 tech-spec(最保险 / 最慢)
|
|
114
|
+
|
|
115
|
+
走 Path B 流程。这条适合:不确定是设计还是实现问题、MUST 覆盖面 ≥ 3 个维度。
|
|
116
|
+
|
|
117
|
+
### 选择依据
|
|
118
|
+
|
|
119
|
+
| 情况 | 选 |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| 只剩 1-2 个 MUST,定位清晰,改法确定 | C.1 |
|
|
122
|
+
| MUST 范围失控,coder 每修一轮都引入新问题 | C.3 |
|
|
123
|
+
| 明确是边缘场景,风险低或已有 mitigation | C.2 |
|
|
124
|
+
| reviewer 与 coder 反复争论 MUST/SHOULD 边界 | Path D 先 |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Path D:reviewer-applier 冲突
|
|
129
|
+
|
|
130
|
+
### 识别
|
|
131
|
+
|
|
132
|
+
- coder 在 `apply.md` 里对 finding 反复标 `resolved: true`,reviewer 反复标回 `resolved: false`
|
|
133
|
+
- `review.md` 的"上轮问题修复情况"里,coder 与 reviewer 对同一 ID 描述完全不同
|
|
134
|
+
- 同一 finding 两轮都存在,coder 坚持"已经按建议改了",reviewer 坚持"没改或改错了"
|
|
135
|
+
|
|
136
|
+
### 处置步骤
|
|
137
|
+
|
|
138
|
+
1. **停止迭代**,不要再自动 back_to_apply。
|
|
139
|
+
2. 在 `review.md` 当前 round 写 `## 评审分歧` section,逐 ID 列:
|
|
140
|
+
- coder 的立场(引用 apply.md 原文)
|
|
141
|
+
- reviewer 的立场(引用本 skill 的 checklist 哪一条)
|
|
142
|
+
- 物证(git diff 片段 / 测试运行结果)
|
|
143
|
+
3. 触发"第三视角"复核:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
devflow review --arbitrate --finding-id=CR-xxx
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
这会以全新上下文(不带 coder 也不带上轮 reviewer 的历史)再看一次,仅基于 diff + checklist + reason。
|
|
150
|
+
|
|
151
|
+
4. arbitrate 输出三种结果之一:
|
|
152
|
+
- **uphold**:维持 reviewer 判定 → 继续 back_to_apply
|
|
153
|
+
- **overrule**:reviewer 判定错误 → 自动把该 finding 改为 resolved,reviewer 这一轮记一条"误判"
|
|
154
|
+
- **downgrade**:MUST 降级为 SHOULD → 同轮 MUST 计数减 1
|
|
155
|
+
|
|
156
|
+
5. 仲裁结果进入 `state.json.phases.review.arbitrations[]`,PR description 里展示。
|
|
157
|
+
|
|
158
|
+
### 防御
|
|
159
|
+
|
|
160
|
+
- review-checklist.md 的每个"检查点"都配了"反例 / 正例 / 判定"三栏,reviewer 要用原文引用做判定依据,而不是个人偏好。
|
|
161
|
+
- coder 在 apply 里 resolve 一个 finding 时,必须引用 `review.findings.json` 的 ID + 在 `apply.md` 里贴 diff snippet 说明"怎么改的",避免纯口头声明。
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 统计:防止陷入"review 循环消耗"
|
|
166
|
+
|
|
167
|
+
3 轮上限不是拍脑袋定的。经验数据:
|
|
168
|
+
|
|
169
|
+
| 现象 | 成因 | 解决方向 |
|
|
170
|
+
| --- | --- | --- |
|
|
171
|
+
| 持续 MUST 冒出 | 需求 / 设计问题 | Path A / B |
|
|
172
|
+
| 总 MUST 数逐轮递减但>0 | coder 能力匹配,多给 1-2 轮通常就能收敛 | C.1 |
|
|
173
|
+
| MUST 数逐轮反而递增 | 问题不在代码层 | C.3 强制 |
|
|
174
|
+
| 同一 MUST 跨轮复现 | 设计或沟通缺陷 | B / D |
|
|
175
|
+
|
|
176
|
+
**90% 以上的任务在 round 2 应该 pass**。如果你的项目 round 3 出现频率 > 20%,可能是:
|
|
177
|
+
|
|
178
|
+
- requirement / design 阶段的 clarifying 不充分 —— 调 brainstorming / tech-spec 的 L2/L3 清单;
|
|
179
|
+
- reviewer 判定尺度过严 —— 回顾 review-checklist.md 的严重度速查,把过多 "NIT 升 SHOULD" 的习惯改掉;
|
|
180
|
+
- coder 上下文给得不够 —— 在 apply 阶段把 design.md / checklist 作为 system prompt 强制注入。
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 审计 / 留档
|
|
185
|
+
|
|
186
|
+
所有 escalation 都在:
|
|
187
|
+
|
|
188
|
+
- `state.json.phases.review.audit[]` —— 结构化 log
|
|
189
|
+
- `review.md` 当前 round 的 `## 设计回退请求` / `## 需求澄清请求` / `## 评审分歧` section
|
|
190
|
+
- PR description(`devflow deliver` 自动聚合)—— reviewer 无法再通过重命名文件绕过
|
|
191
|
+
|
|
192
|
+
`devflow doctor audit` 会扫描所有 change 的 review audit log,对 "force-pass 比例 > 10%" 或 "continue-rounds 比例 > 20%" 发出警告,用于团队侧的质量回溯。
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Language Cheatsheet — Go
|
|
2
|
+
|
|
3
|
+
配套 `review-checklist.md` 使用。通用 checklist 告诉你"要找什么",本 cheatsheet 告诉你"在 Go 项目里长什么样"。
|
|
4
|
+
|
|
5
|
+
适配栈:`net/http` / `gin` / `echo`、`gorm` / `sqlc` / `sqlx`、`go-redis`、`golang/sync`、`context`、`testify` / `gomock`。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## §1 nil 安全(最常见 panic 来源)
|
|
10
|
+
|
|
11
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| nil map 写入 | `var m map[string]int; m["a"] = 1` → panic | `m := make(map[string]int)` 或字面量初始化 | **MUST** |
|
|
14
|
+
| nil slice append | 读是安全的,但 `len(s)` / `s[0]` 崩 | 字面量 / `make([]T, 0, cap)` | 下标访问 **MUST** |
|
|
15
|
+
| nil interface ≠ nil pointer | `var p *Foo; var i Foo = p; i != nil` 为 true(陷阱) | 返回 `error` 时 `return nil`,不要返回 `return myErr`(myErr 是 nil *MyError) | **MUST** |
|
|
16
|
+
| nil channel | close(nil ch) / send 到 nil ch → block/panic | 显式初始化 + close 前检查 ownership | **MUST** |
|
|
17
|
+
| 结构体指针 deref | `user.Profile.Name`(Profile 可能 nil) | 显式 nil check 或 Option 模式 | **MUST** |
|
|
18
|
+
| 错误 type assertion | `err.(*MyError).Code`(err 为 nil → panic) | `var e *MyError; if errors.As(err, &e) { ... }` | **MUST** |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## §2 goroutine 泄漏 / 生命周期(最隐蔽的生产事故源)
|
|
23
|
+
|
|
24
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| goroutine 无退出条件 | `go func() { for { work() } }()` | 带 `context.Done()` / `quit chan` | **MUST** |
|
|
27
|
+
| fire-and-forget 无 recover | `go func() { panic(x) }()` 直接干掉进程 | 顶层 `defer recover()` + log | **MUST** |
|
|
28
|
+
| `time.After` 循环使用 | `select { case <-time.After(t): ...}` 在 for 里,泄漏 timer | `timer := time.NewTimer(t); defer timer.Stop()` | 长 loop **MUST** |
|
|
29
|
+
| `sync.WaitGroup.Add` 位置 | `go func() { wg.Add(1); ... }()` 在 goroutine 内加 | 在启动 goroutine **前**调 `wg.Add(1)` | 竞态 **MUST** |
|
|
30
|
+
| channel 泄漏 | 生产者发完不 close,消费者 for-range 永远等 | producer 独占 close 权 + 显式 close | **MUST** |
|
|
31
|
+
| errgroup / singleflight | 无 | 并发调用用 `errgroup.Group` + first-error-cancel,热点 key 用 `singleflight` | 并发批量 **SHOULD**;缓存穿透场景 **MUST** |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## §3 context 传播与取消
|
|
36
|
+
|
|
37
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| context 断链 | 处理请求时起子 goroutine 传 `context.Background()` | 一直传入参 `ctx`,或派生 `context.WithTimeout(ctx, t)` | **MUST**(取消/超时失效) |
|
|
40
|
+
| context.Value 存业务数据 | `ctx.WithValue(ctx, "user", u)` 当成全局状态 | 只存 request-scoped 元数据(traceId、authUser),不存业务 | **SHOULD** |
|
|
41
|
+
| 对外调用无 timeout | `http.Client{}` 无 Timeout + 无 ctx | 每个 HTTP/DB 调用都有 `context.WithTimeout` | 对外调用无 timeout **MUST** |
|
|
42
|
+
| `ctx.Err()` 忽略 | 长 loop 只 select 业务 chan 不 select ctx.Done | `case <-ctx.Done(): return ctx.Err()` | **MUST** |
|
|
43
|
+
| cancel func 泄漏 | `ctx, _ := context.WithTimeout(...)`(忽略 cancel) | `ctx, cancel := ...; defer cancel()` | **MUST**(timer 泄漏) |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## §4 error 处理与 wrapping
|
|
48
|
+
|
|
49
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
50
|
+
| --- | --- | --- | --- |
|
|
51
|
+
| 吞错误 | `_, _ = f()` / `if err != nil { log.Print(err) }`(吞掉 + 继续) | 显式处理或 return | **MUST** |
|
|
52
|
+
| 裸返回 err | `return err` 丢上下文 | `return fmt.Errorf("fetch user %d: %w", id, err)` | 生产排障困难 **SHOULD** |
|
|
53
|
+
| `==` 比较错误 | `if err == sql.ErrNoRows`(包装后 false) | `errors.Is(err, sql.ErrNoRows)` | **MUST** |
|
|
54
|
+
| type assertion 不用 errors.As | `e, ok := err.(*MyErr)`(wrap 后 false) | `var e *MyErr; errors.As(err, &e)` | **MUST** |
|
|
55
|
+
| `panic` 作业务错 | handler 里 panic 做控制流 | 只在真·不可恢复状态 panic | **MUST** |
|
|
56
|
+
| 业务错误码 | 用字符串判 err.Error() == "not found" | 定义 sentinel `var ErrNotFound = errors.New(...)` + `errors.Is` | **SHOULD** |
|
|
57
|
+
| 错误分级 | 所有错都 log.Error | 业务可预期错 Info/Warn、系统错 Error | **NIT** |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## §5 defer / 资源关闭 / panic recover
|
|
62
|
+
|
|
63
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
64
|
+
| --- | --- | --- | --- |
|
|
65
|
+
| 忘关资源 | `rows, _ := db.Query(...)`(不 close) | `defer rows.Close()`(紧随获取) | **MUST**(连接泄漏) |
|
|
66
|
+
| loop 里 defer | `for { f, _ := os.Open(x); defer f.Close() }` defer 到函数退出才执行 | 包装成独立函数或 `func() { defer; ... }()` | **MUST**(句柄泄漏) |
|
|
67
|
+
| defer 捕获变量 | `defer log.Print(x)` x 取值在声明时 vs `defer func() { log.Print(x) }()` 在执行时 | 明确需要哪种 | 语义错 **MUST** |
|
|
68
|
+
| panic 炸 HTTP server | handler 没 recover 中间件 | `gin.Recovery()` / 自定义 recover + log + 500 | **MUST** |
|
|
69
|
+
| defer 操作 err | `defer rows.Close()` 忽略 close 错误 | 需要时聚合 err(多 return 合并) | **SHOULD** |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## §6 ORM / 数据库
|
|
74
|
+
|
|
75
|
+
### 6.1 GORM
|
|
76
|
+
|
|
77
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
78
|
+
| --- | --- | --- | --- |
|
|
79
|
+
| N+1 | `db.Find(&users)` 后 for 每人 `db.First(&profile)` | `db.Preload("Profile").Find(&users)` | 线上热点 **MUST**;低频 **SHOULD** |
|
|
80
|
+
| 软删除误开/误关 | model 带 `gorm.DeletedAt` 但预期硬删 | 明确 `Unscoped().Delete(...)` 或去 DeletedAt | 语义错 **MUST** |
|
|
81
|
+
| `Update` 零值陷阱 | `db.Model(&u).Update("age", 0)` 不生效(零值被忽略) | 用 `Select("Age").Updates(...)` 或 `UpdateColumn` | **MUST** |
|
|
82
|
+
| `Save` 全字段更新 | `db.Save(&u)` 覆盖所有字段(含零值) | 改用 `Updates` + 指定字段 | 覆盖数据 **MUST** |
|
|
83
|
+
| AutoMigrate 生产 | 生产代码跑 `AutoMigrate` | 单独 migration 工具(goose / atlas / golang-migrate) | **MUST** |
|
|
84
|
+
| 连接池 | 默认 `SetMaxOpenConns` 不配 | 按 QPS × 响应时间配置 + 监控 | **SHOULD** |
|
|
85
|
+
| `First` vs `Find` | `First(&u)` 找不到返回 `ErrRecordNotFound`,容易漏判 | 统一策略 + `errors.Is(err, gorm.ErrRecordNotFound)` | **SHOULD** |
|
|
86
|
+
|
|
87
|
+
### 6.2 sqlc / sqlx
|
|
88
|
+
|
|
89
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
90
|
+
| --- | --- | --- | --- |
|
|
91
|
+
| `db.Exec` 忽略 result | 没检查 `RowsAffected` | 关键 UPDATE/DELETE 必检查,配合事务 | **MUST** |
|
|
92
|
+
| 动态 SQL 拼接 | `fmt.Sprintf("... WHERE id=%d", id)` | 预编译 + `$1 / ?` 占位 | **MUST**(SQL 注入) |
|
|
93
|
+
| `rows.Next` 漏 `rows.Err` | 循环后不判错 | `if err := rows.Err(); err != nil { ... }` | **SHOULD** |
|
|
94
|
+
|
|
95
|
+
### 6.3 事务
|
|
96
|
+
|
|
97
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
98
|
+
| --- | --- | --- | --- |
|
|
99
|
+
| 事务中跨进程调用 | 事务内调 HTTP / 发 MQ(长事务) | 事务外做,或本地消息表 | **MUST** |
|
|
100
|
+
| 嵌套事务 | 多层 `tx.Begin()` 语义混乱 | 只在一处开事务 / savepoint | **MUST** |
|
|
101
|
+
| 事务传播 | goroutine 内重用外层 tx | tx 不要跨 goroutine 共享 | **MUST**(数据竞争) |
|
|
102
|
+
| `defer tx.Rollback()` | 忘写 defer rollback,panic 后 tx 悬挂 | 显式 `defer func() { if err != nil { tx.Rollback() } else { tx.Commit() } }()` | **MUST** |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## §7 HTTP handler / 中间件
|
|
107
|
+
|
|
108
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
109
|
+
| --- | --- | --- | --- |
|
|
110
|
+
| 参数校验 | 手写判空 + 类型转换散乱 | `binding` tag + `c.ShouldBindJSON` / `validator.v10` | **SHOULD** |
|
|
111
|
+
| 错误响应格式 | 各 handler 自定义 json | 全局 error middleware 统一格式 | **MUST**(前端对接一致性) |
|
|
112
|
+
| body size 未限制 | 接收任意大 JSON | `http.MaxBytesReader` / Gin `MaxMultipartMemory` | **MUST**(DoS) |
|
|
113
|
+
| CORS 配置 | `AllowAllOrigins = true` + 带 credentials | 显式 origin 白名单 | **MUST** |
|
|
114
|
+
| HTTP 客户端 | 全局 `http.DefaultClient`(无 timeout) | 自建 `http.Client{Timeout, Transport}` | **MUST** |
|
|
115
|
+
| keep-alive / 连接池 | 短连接每次重建 | 复用 Client 或 Transport | **SHOULD** |
|
|
116
|
+
| 请求上下文 | handler 里起 goroutine 用 `context.Background()` | 派生自 `c.Request.Context()` | **MUST**(取消失效) |
|
|
117
|
+
| graceful shutdown | 直接 `os.Exit` | `srv.Shutdown(ctx)` + 等待 in-flight | **SHOULD** |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## §8 并发原语
|
|
122
|
+
|
|
123
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
124
|
+
| --- | --- | --- | --- |
|
|
125
|
+
| race detector | 开发/CI 不跑 `go test -race` | CI 强制开 | **SHOULD** |
|
|
126
|
+
| `sync.Mutex` 拷贝 | 结构体值传递含 Mutex | 用指针或 `noCopy` | **MUST** |
|
|
127
|
+
| `atomic` vs `Mutex` | 简单计数也用 Mutex 性能差 | `atomic.Int64` | **NIT** |
|
|
128
|
+
| map 并发 | 多 goroutine 读写 `map[K]V` | `sync.Map`(读多) 或 `sync.RWMutex` 包裹 | **MUST**(fatal error) |
|
|
129
|
+
| channel direction | 函数参数 `ch chan T`(双向) | 明确 `ch <-chan T` 或 `ch chan<- T` | **SHOULD** |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## §9 单元测试(testify / gomock)
|
|
134
|
+
|
|
135
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
136
|
+
| --- | --- | --- | --- |
|
|
137
|
+
| 测试落点 | 新增黑盒 / 接口 / 回归测试散落到各业务 package 同目录 | 默认放项目根目录 `test/`;只有包内白盒测试需要访问未导出符号时才同目录 | **SHOULD** |
|
|
138
|
+
| 断言强度 | `assert.NoError(t, err)` 就结束 | + `assert.Equal(t, want, got)` 验证业务结果 | **SHOULD** |
|
|
139
|
+
| `t.Parallel` 陷阱 | 循环里 `tt := tt` 漏写(Go < 1.22) | Go < 1.22 必须 `tt := tt`;Go ≥ 1.22 自动 rebind | 竞态 **MUST** |
|
|
140
|
+
| Mock 生成 | 手写 mock 与接口不同步 | `go:generate mockgen` / `mockery` | **SHOULD** |
|
|
141
|
+
| `subtests` / 表驱动 | 多个 case 复制粘贴 | `for _, tt := range cases { t.Run(tt.name, ...) }` | **SHOULD** |
|
|
142
|
+
| `httptest` | 用真 HTTP 端口 | `httptest.NewServer` / `httptest.NewRecorder` | **SHOULD** |
|
|
143
|
+
| 时间依赖 | 直接 `time.Now()` | 注入 clock 接口 + 测试用 fake | **SHOULD** |
|
|
144
|
+
| 环境变量 | 测试依赖真 env | `t.Setenv(...)`(Go 1.17+)自动清理 | **SHOULD** |
|
|
145
|
+
| `go test` 覆盖率 | 不跑 / 不收集 | `go test -cover -coverprofile=c.out` + CI 阈值 | L2 < 60% **SHOULD**;L3 < 75% **MUST** |
|
|
146
|
+
| golden file | 硬编码期望值巨长 | `testdata/*.golden` + `-update` flag | **NIT** |
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## §10 依赖与构建
|
|
151
|
+
|
|
152
|
+
| 检查点 | 反例 | 正例 | 判定 |
|
|
153
|
+
| --- | --- | --- | --- |
|
|
154
|
+
| `go.mod` / `go.sum` | `go.sum` 未提交 / 冲突未解决 | 每次 commit 保证一致 | **MUST** |
|
|
155
|
+
| init() 副作用 | 全局 `init()` 连 DB / 读配置 | main 里显式初始化 + error 处理 | **SHOULD** |
|
|
156
|
+
| replace 指令 | `replace` 指向本地路径上了主干 | 合并前替换为 tag | **MUST** |
|
|
157
|
+
| CGO 依赖 | 无必要开 CGO | 除非必须,保持 `CGO_ENABLED=0` | **SHOULD** |
|
|
158
|
+
| Dockerfile | 跑 root + 基础镜像含 bash | distroless / scratch + USER 1000 | **SHOULD** |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 快速映射到 `review-checklist.md`
|
|
163
|
+
|
|
164
|
+
| Cheatsheet 章节 | 对应通用 checklist |
|
|
165
|
+
| --- | --- |
|
|
166
|
+
| §1 nil 安全 | §1.4 边界 + §3 null 安全 |
|
|
167
|
+
| §2 goroutine 泄漏 | §4 Performance + §1.5 并发 |
|
|
168
|
+
| §3 context 传播 | §1.5 并发 + §4 Performance |
|
|
169
|
+
| §4 error 处理 | §5 Maintainability + §1.1 正确性 |
|
|
170
|
+
| §5 defer / 资源 | §3 资源泄漏 |
|
|
171
|
+
| §6 ORM / 事务 | §1.6 事务幂等 + §7.3 全链路 |
|
|
172
|
+
| §7 HTTP handler | §1.3 接口契约 + §3 Security |
|
|
173
|
+
| §8 并发原语 | §1.5 并发 |
|
|
174
|
+
| §9 单元测试 | §6 Tests |
|
|
175
|
+
| §10 依赖构建 | §5 Maintainability + §3 Security |
|