@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,240 @@
|
|
|
1
|
+
# verify / self-test-guide
|
|
2
|
+
|
|
3
|
+
self-test 的 AC 证据书写规则、L1/L2/L3 深度要求、反模式。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 什么是 self-test
|
|
8
|
+
|
|
9
|
+
> **自测**:由**实现者**(或 QA / tester)按 requirement.md 的 F-ID + tests.md 的 AC,**逐项手工验证**并留证据,证明"声明实现的功能真的按验收标准工作"。
|
|
10
|
+
|
|
11
|
+
self-test 和自动化单元 / 集成测试**不等价**:
|
|
12
|
+
|
|
13
|
+
| 维度 | 自动化测试 | self-test |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| 目标 | 防回归 | 证明 AC 被实现 |
|
|
16
|
+
| 颗粒度 | 细(方法级) | 粗(用户可见的业务层) |
|
|
17
|
+
| 频率 | CI 每次跑 | 每次 change 跑一次 |
|
|
18
|
+
| 运行方 | 机器 | 人 |
|
|
19
|
+
| 输出 | 绿 / 红 | AC 证据清单 |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 什么时候 self-test 必须写
|
|
24
|
+
|
|
25
|
+
| level | self-test 必须? | 深度要求 |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| L1 | 可选(简单 bug fix 可跳过) | 最少 1 条 AC 证据 |
|
|
28
|
+
| L2 | **必须** | 每个 F-ID 至少核验 1 条关键 AC;全部 AC 至少 80% 留证据 |
|
|
29
|
+
| L3 | **必须** | 每条 AC 独立核验,100% 留证据 |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## self-test 的结构
|
|
34
|
+
|
|
35
|
+
见 [`report-templates.md`](report-templates.md) 的 self-test 模板。核心是 **每条 AC 一个 section**:
|
|
36
|
+
|
|
37
|
+
```markdown
|
|
38
|
+
## F-<ID>: <功能名>
|
|
39
|
+
|
|
40
|
+
### AC<n>: <原 AC 文字>
|
|
41
|
+
|
|
42
|
+
- **执行方式**: <手段>
|
|
43
|
+
- **执行时间**: <ISO>
|
|
44
|
+
- **输入**: <链接 / 内联>
|
|
45
|
+
- **期望**: <复述期望>
|
|
46
|
+
- **实际**: <实际观察> ✅ | ❌
|
|
47
|
+
- **证据**: <截图 / 日志 / 数据链接>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 每个字段的填写规则
|
|
53
|
+
|
|
54
|
+
### 执行方式
|
|
55
|
+
|
|
56
|
+
不要只写"postman"。写:
|
|
57
|
+
|
|
58
|
+
- 工具(postman / curl / 浏览器 / 脚本 / 其他)
|
|
59
|
+
- 路径("登录 → 后台 → 活动管理 → 发放")
|
|
60
|
+
- 关键参数("并发 10 / 批量 1000 / 特殊用户 X")
|
|
61
|
+
|
|
62
|
+
好例:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
postman 批量调用 /api/v1/coupons/batch-grant,body 使用 reports/evidence/input-1k.json;
|
|
66
|
+
并发 10(postman runner),连续 5 轮
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
坏例:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
按规格执行
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 输入
|
|
76
|
+
|
|
77
|
+
不要描述,链接:
|
|
78
|
+
|
|
79
|
+
- 文件附件:`reports/evidence/F-01-AC1-input.json`
|
|
80
|
+
- 截图:`reports/evidence/F-01-AC1-input.png`
|
|
81
|
+
- 如果是 DB 数据:贴建表 SQL / INSERT / 以及数据快照
|
|
82
|
+
|
|
83
|
+
如果输入有敏感信息(真实用户数据)→ 脱敏后留证据,原始数据不进 repo。
|
|
84
|
+
|
|
85
|
+
### 期望
|
|
86
|
+
|
|
87
|
+
复述 AC 原文,不改意思。若 AC 是 GWT 格式,这里写 Then。
|
|
88
|
+
|
|
89
|
+
### 实际
|
|
90
|
+
|
|
91
|
+
**实打实写观察到什么**,不要"pass" / "OK"一笔带过。
|
|
92
|
+
|
|
93
|
+
好例:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
response.status = 200
|
|
97
|
+
response.body.grantedCount = 1000
|
|
98
|
+
response.body.failedCount = 0
|
|
99
|
+
response.body.batchId = "b_20260424_14321"
|
|
100
|
+
duration = 3.2s
|
|
101
|
+
DB `coupon_log` 查询:select count(*) where batch_id = 'b_20260424_14321' → 1000
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
坏例:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
pass ✅
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 证据
|
|
111
|
+
|
|
112
|
+
至少一份,可以是:
|
|
113
|
+
|
|
114
|
+
- 屏幕截图(`reports/screenshots/`)
|
|
115
|
+
- 响应体 JSON(`reports/evidence/`)
|
|
116
|
+
- 日志 snippet(`reports/logs/`)
|
|
117
|
+
- DB 查询结果(导出 CSV / 截图)
|
|
118
|
+
- 录屏(`reports/videos/`,不进 repo 但留外部链接)
|
|
119
|
+
|
|
120
|
+
**不要**嵌入超 1MB 图片到 md,用链接。
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## AC 不满足怎么办
|
|
125
|
+
|
|
126
|
+
### 完全不满足
|
|
127
|
+
|
|
128
|
+
- 填 "**实际**" 为实际差距,标 ❌
|
|
129
|
+
- 标题改 `### AC<n>: ... ❌ FAIL`
|
|
130
|
+
- `reports/test-report.md#self-test` section status → partial 或 fail
|
|
131
|
+
- finalize 会拒绝,回退 apply
|
|
132
|
+
|
|
133
|
+
### 部分满足(功能可用但边缘 case 漏)
|
|
134
|
+
|
|
135
|
+
- 证据里写清"满足 A / B / C 三条 sub-AC,遗漏 D"
|
|
136
|
+
- frontmatter status = partial
|
|
137
|
+
- 产出 concern,orchestrator 决策:是否降级 scope / 回退 apply / 接受
|
|
138
|
+
|
|
139
|
+
### 满足但非精确一致
|
|
140
|
+
|
|
141
|
+
- 实际 response.grantedCount = 1000,但 granted_at 字段没写时间戳
|
|
142
|
+
- 这种"附加字段"问题:标 ✅ WITH CONCERN,在 concerns 里独立列出
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## L1 / L2 / L3 的深度
|
|
147
|
+
|
|
148
|
+
### L1 (简单 bug fix)
|
|
149
|
+
|
|
150
|
+
样例 change: 修复金额计算浮点数精度问题。
|
|
151
|
+
|
|
152
|
+
self-test 只要核心 AC:
|
|
153
|
+
|
|
154
|
+
```markdown
|
|
155
|
+
## 修复:金额 19.99 + 19.99 = 39.98(原 39.979999...)
|
|
156
|
+
|
|
157
|
+
- **执行方式**:执行脚本 `node test-amount.js`
|
|
158
|
+
- **输入**:多组金额
|
|
159
|
+
- **期望**:所有组都精确到 2 位小数
|
|
160
|
+
- **实际**:39.98,4.21,100.00(10 组全对)
|
|
161
|
+
- **证据**:`reports/evidence/l1-fix.log`
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### L2 (新功能 / 中型修改)
|
|
165
|
+
|
|
166
|
+
每个 F-ID 至少核验 1 条关键 AC,异常分支抽样核验(不要求每条 AC 都有独立 section,但关键的都要有)。
|
|
167
|
+
|
|
168
|
+
### L3 (大改 / 系统级)
|
|
169
|
+
|
|
170
|
+
**每条 AC 独立 section**,全覆盖。包括:
|
|
171
|
+
|
|
172
|
+
- Happy path
|
|
173
|
+
- 每个已定义的异常分支
|
|
174
|
+
- 每个 NFR(性能 / 并发 / 可用性)都有对应测试
|
|
175
|
+
- 跨系统集成场景
|
|
176
|
+
|
|
177
|
+
L3 的 self-test 经常 30-60 个 AC,要 1-2 天跑完,这是正常的。
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 协同 vs 独跑
|
|
182
|
+
|
|
183
|
+
- **实现者自跑**:最基础,覆盖所有 AC
|
|
184
|
+
- **第二人复跑**(L3 推荐):另一工程师或 QA 按同样的 self-test 章节独立跑一次,填独立证据
|
|
185
|
+
- **QA 结构化测试**(L3 强推):QA 按 tests.md 设计更完整的 case(超出 AC),self-test 引用 QA 报告链接即可
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 反模式
|
|
190
|
+
|
|
191
|
+
### "通过了"式 self-test
|
|
192
|
+
|
|
193
|
+
```markdown
|
|
194
|
+
## F-01
|
|
195
|
+
- AC1: pass ✅
|
|
196
|
+
- AC2: pass ✅
|
|
197
|
+
- AC3: pass ✅
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
finalize 会拒绝。证据不足等于没做。
|
|
201
|
+
|
|
202
|
+
### 时间戳造假
|
|
203
|
+
|
|
204
|
+
verify 开始时间戳(frontmatter `ts`)明显晚于最后一次代码 commit 才可信。用"测试执行时间"补:"**执行时间**"字段不能早于 commit。
|
|
205
|
+
|
|
206
|
+
### 截图造假
|
|
207
|
+
|
|
208
|
+
用 OS 自带截图工具 + 窗口时间戳,或用 dev tool / postman 截图(有明确时间)。过于裁剪的截图不可信。
|
|
209
|
+
|
|
210
|
+
### 只测 Happy Path
|
|
211
|
+
|
|
212
|
+
edge-case-catalog 里的 8 个维度至少扫到 3-4 个(L2)/ 8 个(L3)。
|
|
213
|
+
|
|
214
|
+
### 用单测跑通就写 self-test pass
|
|
215
|
+
|
|
216
|
+
单测证明"代码路径正确",不等于"业务 AC 满足"。self-test 必须在集成环境、真实数据、端到端路径上跑。
|
|
217
|
+
|
|
218
|
+
### AC 没满足也标 pass
|
|
219
|
+
|
|
220
|
+
- 测出 bug → 先回退 apply 修,再重跑 self-test
|
|
221
|
+
- 不能"pass 先过,bug 后修" → 这就是典型 review 拦不住、上线炸的原因
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 和 tests.md 的关系
|
|
226
|
+
|
|
227
|
+
- tests.md 是**独立的测试设计**,可以比 AC 多(为了覆盖率)
|
|
228
|
+
- self-test 只需覆盖 AC 这一核心子集;tests.md 里"衍生场景"的 TC 不必都跑 self-test,但要有自动化 / 集成测试覆盖
|
|
229
|
+
- finalize 时会 cross-check:self-test 里声明 pass 的 AC 必须真在 tests.md 里对应上
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 工具建议
|
|
234
|
+
|
|
235
|
+
- 截图:原生 OS 工具 + 时间戳水印
|
|
236
|
+
- API 验证:Postman / Hoppscotch / curl + jq
|
|
237
|
+
- DB 验证:DBeaver / TablePlus 查询结果截图 + SQL 原文
|
|
238
|
+
- 前端 UX 验证:DevTools Network + Console + Screenshot
|
|
239
|
+
|
|
240
|
+
所有工具产出**导出到 `reports/evidence/`**,不依赖"我本地有截图"。
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# verify / verify-rollback-map
|
|
2
|
+
|
|
3
|
+
verify 失败时回退到哪个 phase,及审计格式。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 核心原则
|
|
8
|
+
|
|
9
|
+
verify 拦到的是**事实问题**(测试 fail、NFR 不达、AC 未满足):
|
|
10
|
+
|
|
11
|
+
- 不在 verify 阶段"修",回退到有能力修的 phase
|
|
12
|
+
- 每次回退留审计(iterations[] 加一条)
|
|
13
|
+
- 修复后必须重回 verify 重跑全部必需 report
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 回退决策表
|
|
18
|
+
|
|
19
|
+
| 失败类型 | 根因层次 | 回退到 |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| 单元测试红 | 代码 bug | apply |
|
|
22
|
+
| 集成测试红(组件间契约问题) | 代码 bug(常)/ 设计误区(偶) | apply(首先)→ 如几轮修不好回 tech-spec |
|
|
23
|
+
| E2E 红(整条链路问题) | 代码 / 配置 / 部署 | apply(先排) |
|
|
24
|
+
| Smoke 红(核心用户路径) | 代码 / UX | apply |
|
|
25
|
+
| Self-test AC 未满足 | 代码未实现 / 实现跑偏 | apply |
|
|
26
|
+
| Self-test 发现 AC 本身含糊 | 需求问题 | requirement-analysis |
|
|
27
|
+
| perf 不达 NFR,代码可优化 | 代码性能 | apply |
|
|
28
|
+
| perf 不达 NFR,架构瓶颈 | 架构设计 | tech-spec |
|
|
29
|
+
| perf 不达 NFR,NFR 定得过严 | 需求层面 | requirement-analysis(调 NFR) |
|
|
30
|
+
| Regression 红(本次无关) | 历史遗留 | 不阻塞,但记 ISSUE 和 concern |
|
|
31
|
+
| 安全 / 合规扫描红 | 代码 / 设计 / 依赖 | 看具体条目 |
|
|
32
|
+
| Flaky test | 测试本身 / 环境 | test-spec 修测试,或本次审计跳过 |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 决策细则
|
|
37
|
+
|
|
38
|
+
### "测试红,代码 bug" → apply
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
devflow verify --state fail --reason="unit-test T-12 失败:null pointer"
|
|
42
|
+
devflow apply --task 12 --resume # or 新 task 修
|
|
43
|
+
# 修完后
|
|
44
|
+
devflow verify # 重新运行,或只跑 devflow test unit
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
iterations[] 加一条:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"id": 2,
|
|
52
|
+
"triggeredAt": "verify:unit-test",
|
|
53
|
+
"rollbackTo": "apply",
|
|
54
|
+
"reason": "unit-test T-12 nullpointer 异常分支未处理",
|
|
55
|
+
"affectedTasks": ["T-12"],
|
|
56
|
+
"durationMinutes": 45
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### "perf 不达标,架构问题" → tech-spec
|
|
61
|
+
|
|
62
|
+
**判定"架构问题 vs 代码问题"**:
|
|
63
|
+
|
|
64
|
+
- 代码问题:profiler 能定位到 hot spot,优化算法 / 数据结构 / 连接池能解
|
|
65
|
+
- 架构问题:单机瓶颈、需要拆分、需要缓存 / 队列、需要分片
|
|
66
|
+
|
|
67
|
+
架构问题 → 回退 tech-spec:
|
|
68
|
+
|
|
69
|
+
- 更新 design.md 的"技术方案"和"关键决策"
|
|
70
|
+
- 加一个 ADR 记"为什么原设计不够"
|
|
71
|
+
- 重新 plan / apply / verify
|
|
72
|
+
|
|
73
|
+
### "AC 含糊 / 原 NFR 定得不切实际" → requirement-analysis
|
|
74
|
+
|
|
75
|
+
verify 执行时发现:
|
|
76
|
+
|
|
77
|
+
- AC 某条执行时才发现两种可能的解读(因歧义)
|
|
78
|
+
- 压测发现 P99 ≤ 50ms 根本不可能(理论下界都 100ms),NFR 定得不切实际
|
|
79
|
+
|
|
80
|
+
这属于需求问题:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
devflow verify --state fail --reason="NFR P99≤50ms 不可达,技术下界 80ms"
|
|
84
|
+
devflow requirement-analysis --round-3 --reason="调 NFR"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
新一轮 Q&A 后,NFR 修改为"P99 ≤ 150ms"(或增加资源预算换低延迟)。
|
|
88
|
+
|
|
89
|
+
### "回归测试红,和本次无关" → 审计跳过
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# 本次 slug 没动这块代码
|
|
93
|
+
devflow verify --accept-regression-fail --reason="regression T-foo 早于本 slug 1 周就挂,已有 ISSUE-123,不阻塞"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- state.json 记录 "accepted_regression_fail"
|
|
97
|
+
- 报告 frontmatter status = partial,或 regression-test.md 单独 fail(不影响整体 finalize)
|
|
98
|
+
- ISSUE 要真实存在(review 会核对)
|
|
99
|
+
|
|
100
|
+
### "Self-test AC 未满足,实现 scope 有漏"
|
|
101
|
+
|
|
102
|
+
具体看漏得多严重:
|
|
103
|
+
|
|
104
|
+
| 漏的程度 | 处置 |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| 1-2 条次要 AC(可延期) | 申请 scope 调整,回 requirement 砍 scope 或加迭代 |
|
|
107
|
+
| 核心 AC 漏 | 回 apply 补 |
|
|
108
|
+
| 大半 AC 漏 | 回 plan(plan 本身漏了)或 tech-spec(设计就不完整) |
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 审计格式
|
|
113
|
+
|
|
114
|
+
每次 verify 失败,`state.json` 加一条 iteration:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"iterations": [
|
|
119
|
+
{
|
|
120
|
+
"id": 3,
|
|
121
|
+
"triggeredAt": "verify:perf-test",
|
|
122
|
+
"rollbackTo": "tech-spec",
|
|
123
|
+
"reason": "P99=320ms 不达 NFR=200ms,profiler 显示数据库连接池瓶颈",
|
|
124
|
+
"evidence": "reports/perf-test.md#结果",
|
|
125
|
+
"affectedTasks": [],
|
|
126
|
+
"affectedDocs": ["design.md", "delta/coupon-batch-grant.md"],
|
|
127
|
+
"resolvedAt": null
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
修好后 `resolvedAt` 填入时间戳。
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 反模式
|
|
138
|
+
|
|
139
|
+
### "测试挂了再跑两次就过"
|
|
140
|
+
|
|
141
|
+
禁止。测试挂了要修,不是"多跑几次碰运气"。真 flaky 要 quarantine 并 ISSUE。
|
|
142
|
+
|
|
143
|
+
### "perf 差一点点,在 verify 里微调 NFR"
|
|
144
|
+
|
|
145
|
+
禁止。NFR 是 requirement 的一部分,调 NFR 必须走 requirement-analysis。
|
|
146
|
+
|
|
147
|
+
### "跳过 perf 直接 deliver"
|
|
148
|
+
|
|
149
|
+
verify 硬闸拦住。要跳过必须 `--accept-missing-nfr` 并给 justification + 补偿计划(canary 验证 / 上线后监控加强)。
|
|
150
|
+
|
|
151
|
+
### "self-test AC 3 条漏,写 partial 但 finalize 接受"
|
|
152
|
+
|
|
153
|
+
finalize 里 status=partial 默认会阻止 deliver。orchestrator 审计后可以**有条件**放行(如果漏的 AC 被明确标记为"P2,下迭代"),但必须在 state 里记。
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 回退后的重跑规则
|
|
158
|
+
|
|
159
|
+
修复后不能只跑挂的那条报告:
|
|
160
|
+
|
|
161
|
+
| 修复影响范围 | 需要重跑 |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| 1 个方法的 bug(apply T-N) | T-N 所在模块的 unit + smoke |
|
|
164
|
+
| 多模块修复 | unit + integration + smoke |
|
|
165
|
+
| 架构级(tech-spec revise) | 全套必需报告 |
|
|
166
|
+
| 数据 / DDL 修复 | integration + e2e + self-test |
|
|
167
|
+
| 性能优化 | perf + smoke(确认没退化功能) |
|
|
168
|
+
|
|
169
|
+
**原则**:越上游的回退,重跑越全。
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## verify.md 的聚合结构
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
# 验证汇总 — <slug>
|
|
177
|
+
|
|
178
|
+
## 结论
|
|
179
|
+
|
|
180
|
+
**状态**: completed | rolled-back | blocked
|
|
181
|
+
**最终结论**: ready for deliver
|
|
182
|
+
|
|
183
|
+
## 报告清单
|
|
184
|
+
|
|
185
|
+
| 类型 | 状态 | 链接 | 关键指标 |
|
|
186
|
+
| --- | --- | --- | --- |
|
|
187
|
+
| unit | pass | [reports/test-report.md#unit](reports/test-report.md#unit) | 243/243, cov 86% |
|
|
188
|
+
| integration | pass | [reports/test-report.md#integration](reports/test-report.md#integration) | 52/52 |
|
|
189
|
+
| e2e | pass | [reports/test-report.md#e2e](reports/test-report.md#e2e) | 18/18 |
|
|
190
|
+
| smoke | pass | [reports/test-report.md#smoke](reports/test-report.md#smoke) | 成功路径已打通 |
|
|
191
|
+
| self-test | pass | [reports/test-report.md#self-test](reports/test-report.md#self-test) | 12/12 AC |
|
|
192
|
+
| perf | pass | [reports/test-report.md#perf](reports/test-report.md#perf) | P99=180ms / NFR=200ms |
|
|
193
|
+
|
|
194
|
+
## 本次迭代
|
|
195
|
+
|
|
196
|
+
- 迭代 #1: verify → apply(T-12 nullpointer 修复)
|
|
197
|
+
- 迭代 #2: verify → tech-spec(perf P99 超标,加连接池)
|
|
198
|
+
- 迭代 #3: verify 通过
|
|
199
|
+
|
|
200
|
+
## 残留 concern
|
|
201
|
+
|
|
202
|
+
- REG-04 在 regression 套件红,与本 slug 无关,追踪 ISSUE-789
|
|
203
|
+
|
|
204
|
+
## 下一步
|
|
205
|
+
|
|
206
|
+
`devflow deliver`
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 和 orchestrator 的交互
|
|
212
|
+
|
|
213
|
+
verify finalize 后产出 STATUS block:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
---STATUS---
|
|
217
|
+
result: DONE
|
|
218
|
+
verifyStatus: pass
|
|
219
|
+
nextAction: devflow deliver
|
|
220
|
+
---END_STATUS---
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
verify fail 且回退:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
---STATUS---
|
|
227
|
+
result: NEEDS_INPUT
|
|
228
|
+
verifyStatus: fail
|
|
229
|
+
rollbackTo: apply
|
|
230
|
+
rollbackReason: unit-test T-12 nullpointer
|
|
231
|
+
nextAction: devflow apply --task 12 --resume
|
|
232
|
+
---END_STATUS---
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
orchestrator 根据 rollbackTo 自动切换 phase,不需用户干预(用户可接管或跳过)。
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 最大反模式:verify 阶段偷偷改 design.md / plan.md
|
|
240
|
+
|
|
241
|
+
verify 不允许写回上游产物。想改 → 走回退流程。直接改会导致:
|
|
242
|
+
|
|
243
|
+
- archive 时 spec delta 和实际行为不一致
|
|
244
|
+
- 下一个 slug 的 requirement / design 基于错误 spec 展开
|
|
245
|
+
- 审计链断裂,事后难追溯
|
|
246
|
+
|
|
247
|
+
**verify 只产出 reports/ + verify.md,不动任何上游 md**。
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fsSync = require('fs');
|
|
3
|
+
const log = require('../../utils/log.js');
|
|
4
|
+
const paths = require('../../core/paths.js');
|
|
5
|
+
const change = require('../../core/change.js');
|
|
6
|
+
const state = require('../../core/state.js');
|
|
7
|
+
const workflow = require('../../core/workflow.js');
|
|
8
|
+
const workflowCheck = require('../../core/workflow-check.js');
|
|
9
|
+
const templates = require('../../templates/index.js');
|
|
10
|
+
|
|
11
|
+
async function resolveSlug(root, flags = {}, positional = []) {
|
|
12
|
+
if (!fsSync.existsSync(paths.devflowDir(root))) {
|
|
13
|
+
log.error('not a devflow project. run "devflow init" first.');
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const slug = flags.slug || positional[0] || (await change.getCurrent(root));
|
|
17
|
+
if (!slug) {
|
|
18
|
+
log.error('no change found. run "devflow ingest <input>" or "devflow new <slug>".');
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return slug;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function loadStateOrFail(root, slug) {
|
|
25
|
+
try { return await state.read(root, slug); }
|
|
26
|
+
catch (e) {
|
|
27
|
+
log.error(`cannot read state for ${slug}: ${e.message}`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function writePhaseArtifact(root, slug, st, name, templateFile, vars) {
|
|
33
|
+
const tpl = await templates.load(templateFile);
|
|
34
|
+
const body = templates.render(tpl, {
|
|
35
|
+
slug,
|
|
36
|
+
title: st.title || slug,
|
|
37
|
+
date: new Date().toISOString().slice(0, 10),
|
|
38
|
+
...vars,
|
|
39
|
+
});
|
|
40
|
+
if (await change.hasArtifact(root, slug, name)) {
|
|
41
|
+
log.warn(`${name} already exists (skipping write; edit manually).`);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const file = await change.writeArtifact(root, slug, name, body);
|
|
45
|
+
log.ok(`${name}: ${file}`);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function blockWorkflowStep(root, st, slug, stepId, commandName) {
|
|
50
|
+
try {
|
|
51
|
+
workflow.assertStepAllowed(st.workflow, stepId);
|
|
52
|
+
return false;
|
|
53
|
+
} catch (e) {
|
|
54
|
+
if (e.code === 'WORKFLOW_NOT_CONFIRMED') {
|
|
55
|
+
log.error(`${commandName} blocked: change workflow is not confirmed.`);
|
|
56
|
+
log.dim(`run: devflow flow card --slug=${slug} --json`);
|
|
57
|
+
log.dim(`script preflight: devflow flow check --slug=${slug} --json`);
|
|
58
|
+
log.dim(`then, if ok=true: devflow flow confirm --slug=${slug}`);
|
|
59
|
+
const result = workflowCheck.checkWorkflow(root, slug, st);
|
|
60
|
+
if (result.ok && result.confirmationCard) renderWorkflowConfirmationCard(result.confirmationCard);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
if (e.code === 'WORKFLOW_STEP_BLOCKED') {
|
|
65
|
+
log.error(`${commandName} blocked by workflow gate: currentStep=${e.currentStep}, requested=${stepId}.`);
|
|
66
|
+
log.dim(`run the current workflow step first, or inspect: devflow flow explain --slug=${slug}`);
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
throw e;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function completeWorkflowStep(st, stepId) {
|
|
75
|
+
if (!st.workflow) return false;
|
|
76
|
+
return workflow.completeStep(st.workflow, stepId);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function printWorkflowSelectionGuidance(slug) {
|
|
80
|
+
log.dim(`workflow picker: devflow flow picker --slug=${slug} --json`);
|
|
81
|
+
log.dim(`selection: devflow flow apply-selection --slug=${slug} --selection='<json>' --json`);
|
|
82
|
+
log.dim(`card: devflow flow card --slug=${slug} --json`);
|
|
83
|
+
log.dim(`check: devflow flow check --slug=${slug} --json`);
|
|
84
|
+
log.dim(`confirm: devflow flow confirm --slug=${slug}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function renderWorkflowConfirmationCard(card) {
|
|
88
|
+
log.raw(card.title || '确认本次 workflow');
|
|
89
|
+
if (card.question) log.raw(`question: ${card.question}`);
|
|
90
|
+
const activeSteps = (card.steps || [])
|
|
91
|
+
.filter((step) => step.status !== 'disabled')
|
|
92
|
+
.map((step) => step.id);
|
|
93
|
+
log.raw(`steps: ${activeSteps.join(' -> ') || '-'}`);
|
|
94
|
+
if (card.primaryAction) log.raw(`confirm: ${card.primaryAction.command}`);
|
|
95
|
+
for (const action of card.secondaryActions || []) {
|
|
96
|
+
log.raw(`${action.id}: ${action.command}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = {
|
|
101
|
+
resolveSlug,
|
|
102
|
+
loadStateOrFail,
|
|
103
|
+
writePhaseArtifact,
|
|
104
|
+
blockWorkflowStep,
|
|
105
|
+
completeWorkflowStep,
|
|
106
|
+
printWorkflowSelectionGuidance,
|
|
107
|
+
renderWorkflowConfirmationCard,
|
|
108
|
+
};
|