kld-sdd 2.6.0 → 2.6.1
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/README.md +3 -3
- package/package.json +1 -1
- package/skywalk-sdd/index.cjs +1 -1
- package/skywalk-sdd/ontology/id.cjs +16 -19
- package/templates/openspec/proposal.md +1 -1
- package/templates/skills/kld-sdd/opsx-apply/SKILL.md +27 -4
- package/templates/skills/kld-sdd/opsx-apply/checklist.md +29 -1
- package/templates/skills/kld-sdd/opsx-apply/implementer-prompt.md +54 -3
- package/templates/skills/kld-sdd/opsx-apply/reference.md +26 -0
- package/templates/skills/kld-sdd/opsx-check/SKILL.md +19 -4
- package/templates/skills/kld-sdd/opsx-check/checklist.md +17 -1
- package/templates/skills/kld-sdd/opsx-propose/reference.md +6 -4
- package/templates/skills/kld-sdd/opsx-task/SKILL.md +41 -8
- package/templates/skills/kld-sdd/opsx-task/checklist.md +15 -0
- package/templates/skills/kld-sdd/opsx-task/reference.md +73 -2
- package/templates/skills/kld-sdd/opsx-test/SKILL.md +17 -0
package/README.md
CHANGED
|
@@ -32,8 +32,8 @@ Entity sourcedFrom SEC
|
|
|
32
32
|
每个本体实体使用双层身份:
|
|
33
33
|
|
|
34
34
|
- `anchor`:`STMT-ORDER-005` 等人工可读编号,跨迭代保持稳定且删除后不复用。
|
|
35
|
-
- `entity-id`:全局唯一
|
|
36
|
-
- `version-id`:全局唯一
|
|
35
|
+
- `entity-id`:全局唯一 32 位 ID(8 位十六进制),同一逻辑实体跨迭代复用。
|
|
36
|
+
- `version-id`:全局唯一 32 位 ID,每次 added/modified/removed 产生新版本;unchanged 复用历史版本。
|
|
37
37
|
- `predecessor-version`:modified/removed 指向同一实体的直接前序版本。
|
|
38
38
|
|
|
39
39
|
UUID 由本地命令生成,不依赖网络、机器号或中央 ID 服务:
|
|
@@ -53,7 +53,7 @@ node skywalk-sdd/log.cjs semantic-identity --delta-state=unchanged --entity-id=<
|
|
|
53
53
|
本地命令:
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
|
-
# 解析与诊断;首次运行会为 Artifact/DocumentSection
|
|
56
|
+
# 解析与诊断;首次运行会为 Artifact/DocumentSection 分配并持久化 32 位结构 ID sidecar
|
|
57
57
|
node skywalk-sdd/log.cjs semantic-scan --project=. --change=<name>
|
|
58
58
|
|
|
59
59
|
# 文件与工作态本体实例全量对账
|
package/package.json
CHANGED
package/skywalk-sdd/index.cjs
CHANGED
|
@@ -4686,7 +4686,7 @@ SDD Telemetry CLI - 流程度量采集工具
|
|
|
4686
4686
|
tasks-status 扫描 Full/Simple 模式 tasks.md 勾选状态
|
|
4687
4687
|
check-task 扫描变更目录 tasks.md 并勾选指定 task_id
|
|
4688
4688
|
archive-docs 将 Simple/Full spec 变更真实移动到 openspec/changes/archive/,并可结束 archive 阶段生成报告
|
|
4689
|
-
semantic-identity 生成或复用实体/版本
|
|
4689
|
+
semantic-identity 生成或复用实体/版本 ID(8 位十六进制);无需网络和中央 ID 服务
|
|
4690
4690
|
semantic-scan 只读解析并校验当前 Change
|
|
4691
4691
|
semantic-reconcile 全量对账文件与本地工作态本体实例
|
|
4692
4692
|
semantic-check 全量对账并在通过时标记 pending
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
const crypto = require('crypto');
|
|
4
4
|
const { ID_PREFIX_TYPES, entityTypeForId } = require('./schema.cjs');
|
|
5
5
|
|
|
6
|
+
const ID_BYTE_LENGTH = 4;
|
|
7
|
+
const ID_HEX_LENGTH = ID_BYTE_LENGTH * 2;
|
|
8
|
+
|
|
6
9
|
function normalizeSlug(value) {
|
|
7
10
|
const raw = String(value || '').trim();
|
|
8
11
|
const ascii = raw
|
|
@@ -48,25 +51,16 @@ function isValidEntityId(entityId, expectedType = '') {
|
|
|
48
51
|
return true;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
let value = BigInt(milliseconds);
|
|
58
|
-
for (let index = 5; index >= 0; index -= 1) {
|
|
59
|
-
bytes[index] = Number(value & 0xffn);
|
|
60
|
-
value >>= 8n;
|
|
61
|
-
}
|
|
62
|
-
bytes[6] = (bytes[6] & 0x0f) | 0x70;
|
|
63
|
-
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
64
|
-
const hex = bytes.toString('hex');
|
|
65
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
54
|
+
function generateIdentityId() {
|
|
55
|
+
return crypto.randomBytes(ID_BYTE_LENGTH).toString('hex');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function generateUuidV7() {
|
|
59
|
+
return generateIdentityId();
|
|
66
60
|
}
|
|
67
61
|
|
|
68
62
|
function isValidUuid(value) {
|
|
69
|
-
return
|
|
63
|
+
return new RegExp(`^[0-9a-f]{${ID_HEX_LENGTH}}$`).test(String(value || '').trim().toLowerCase());
|
|
70
64
|
}
|
|
71
65
|
|
|
72
66
|
const isValidUuidV7 = isValidUuid;
|
|
@@ -84,8 +78,8 @@ function allocateIdentity(options = {}) {
|
|
|
84
78
|
}
|
|
85
79
|
if (deltaState === 'added') {
|
|
86
80
|
return {
|
|
87
|
-
entity_id:
|
|
88
|
-
version_id:
|
|
81
|
+
entity_id: generateIdentityId(),
|
|
82
|
+
version_id: generateIdentityId(),
|
|
89
83
|
predecessor_version_id: null,
|
|
90
84
|
delta_state: deltaState,
|
|
91
85
|
};
|
|
@@ -109,16 +103,19 @@ function allocateIdentity(options = {}) {
|
|
|
109
103
|
}
|
|
110
104
|
return {
|
|
111
105
|
entity_id: entityId,
|
|
112
|
-
version_id:
|
|
106
|
+
version_id: generateIdentityId(),
|
|
113
107
|
predecessor_version_id: predecessorVersionId,
|
|
114
108
|
delta_state: deltaState,
|
|
115
109
|
};
|
|
116
110
|
}
|
|
117
111
|
|
|
118
112
|
module.exports = {
|
|
113
|
+
ID_BYTE_LENGTH,
|
|
114
|
+
ID_HEX_LENGTH,
|
|
119
115
|
normalizeSlug,
|
|
120
116
|
nextEntityId,
|
|
121
117
|
isValidEntityId,
|
|
118
|
+
generateIdentityId,
|
|
122
119
|
generateUuidV7,
|
|
123
120
|
isValidUuid,
|
|
124
121
|
isValidUuidV7,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
# 【用户选择配置 - 由 /opsx:propose 引导填写】
|
|
3
3
|
change-id: "CHG-<CHANGE-SLUG>" # 创建时生成,后续不得修改
|
|
4
|
-
entity-id: "<
|
|
4
|
+
entity-id: "<8位十六进制ID>" # Change 的全局逻辑实体 ID,added 时生成
|
|
5
5
|
version-id: "<UUID>" # 本次 Change 版本 UUID
|
|
6
6
|
delta-state: "added"
|
|
7
7
|
predecessor-version: "" # added 留空;modified/removed 指向直接前序版本
|
|
@@ -192,11 +192,34 @@ f. **⛔ 立即更新任务状态** — tasks.md `- [ ]`→`- [x]` 与 `**状态
|
|
|
192
192
|
g. **继续下一个层级** — 重新检查 DAG,找出依赖已满足的下一层级任务。
|
|
193
193
|
|
|
194
194
|
**【S2 逐任务红绿节奏】**:每个任务完成后,在编译检查(d)和测试门禁(e)之外,如果 `test-strategy` 为 `tdd`,要求:
|
|
195
|
-
1.
|
|
196
|
-
2.
|
|
197
|
-
3.
|
|
195
|
+
1. **测试-RED 任务**:编写带真实断言的测试 → 运行测试 → 确认失败(失败原因必须是功能未实现)→ 记录失败原因
|
|
196
|
+
2. **实现-GREEN 任务**:读取对应 RED 的失败原因 → 写最少代码让测试通过 → 运行测试确认通过
|
|
197
|
+
3. **重构-REFACTOR 任务**:在测试全绿状态下重构 → 运行全部测试确认仍绿
|
|
198
|
+
4. 再进入下一个任务
|
|
198
199
|
|
|
199
|
-
|
|
200
|
+
这确保每个行为点都有对应的测试保护,测试真实驱动实现,而非最后统一跑测试。
|
|
201
|
+
|
|
202
|
+
**【S2.1 RED 测试质量标准】**(test-strategy=tdd 时强制):
|
|
203
|
+
|
|
204
|
+
> ⛔ 核心原则:**Mock 边界,不 Mock 行为**
|
|
205
|
+
>
|
|
206
|
+
> 测试应验证**真实行为链路**(输入→输出),而非验证"能否 catch mock 抛的异常"。
|
|
207
|
+
|
|
208
|
+
1. **禁止 mock 被测行为本身**:测试的 Given 应准备**真实的前置条件**(如真实的 invalid token 字符串),让被测代码自然走完链路;而非直接 mock 出**期望的中间结果**(如 mock parseToken 抛异常)
|
|
209
|
+
- ❌ `when(jwtUtil.parseToken("invalid")).thenThrow(...)` — mock 了被测行为(token 解析失败),GREEN 只需加 try-catch
|
|
210
|
+
- ✅ 使用真实 JwtUtil + 真实 invalid token 字符串,让解析自然失败,测试验证完整链路
|
|
211
|
+
|
|
212
|
+
2. **Mock 仅用于系统边界依赖**:数据库 Mapper、HTTP 客户端、消息队列等外部依赖可 mock;但被测类自身的业务逻辑、实现被测行为的工具类不可 mock
|
|
213
|
+
- ✅ Mock `BookMapper.countByPublisher()` — 数据库边界,需要真实 DB 环境才能验证
|
|
214
|
+
- ❌ Mock `JwtUtil.parseToken()` — 这是被测行为的实现,mock 它等于跳过了被测逻辑
|
|
215
|
+
|
|
216
|
+
3. **RED 测试的 Given 必须是真实输入**:传入真实的数据(如 `"invalid"` 字符串、`null`、空对象),让被测代码自行处理;不能 mock 出"这个输入会导致什么结果"
|
|
217
|
+
- ❌ `when(parseToken("invalid")).thenThrow()` — 预定了"invalid 会导致抛异常"这个结论
|
|
218
|
+
- ✅ 传入 `"invalid"` 字符串,让真实的 parseToken 自行决定是否失败
|
|
219
|
+
|
|
220
|
+
4. **GREEN 实现后测试不应需要修改**:测试描述行为契约(输入→期望输出),GREEN 只写让契约满足的最少代码。如果 GREEN 后需要改测试才能通过,说明 RED 测试有问题
|
|
221
|
+
|
|
222
|
+
5. **判断标准**:如果删掉被测类的实现(方法体清空),测试是否仍然因为 mock 而通过?如果是,说明测试是假的——真实测试应该在实现缺失时失败
|
|
200
223
|
|
|
201
224
|
### 5f. 【S3 apply 结束前 checkbox 全量自检】
|
|
202
225
|
|
|
@@ -34,10 +34,37 @@ description: opsx-apply 的阶段强制检查点与自检清单。仅在执行 a
|
|
|
34
34
|
|
|
35
35
|
### §5e 测试执行门禁(按 `proposal.md` 的 `test-strategy`)
|
|
36
36
|
|
|
37
|
-
- [ ] `tdd` → **⛔
|
|
37
|
+
- [ ] `tdd` → **⛔ 强制执行**:
|
|
38
|
+
- 测试-RED 任务:运行测试确认**失败**,失败原因必须是功能未实现(非编译错误)
|
|
39
|
+
- 实现-GREEN 任务:运行测试确认**通过**
|
|
40
|
+
- 重构-REFACTOR 任务:运行**全部测试**确认仍绿
|
|
41
|
+
- 测试失败禁止继续,必须修复
|
|
38
42
|
- [ ] `impl-first` → **⚠️ 警告模式**:运行测试,失败时显示警告但允许继续
|
|
39
43
|
- [ ] `none` → **跳过**:不执行测试门禁
|
|
40
44
|
|
|
45
|
+
### §5e.1 TDD 执行合规自检(仅 test-strategy=tdd 时)
|
|
46
|
+
|
|
47
|
+
- [ ] RED 任务执行后已运行测试并确认失败
|
|
48
|
+
- [ ] RED 任务失败原因是"功能未实现"而非编译错误
|
|
49
|
+
- [ ] GREEN 任务执行后已运行测试确认通过
|
|
50
|
+
- [ ] GREEN 任务未提前实现没有测试要求的功能
|
|
51
|
+
- [ ] REFACTOR 任务执行后已运行全部测试确认仍绿
|
|
52
|
+
- [ ] 未出现"先写生产代码再补测试"的情况
|
|
53
|
+
|
|
54
|
+
### §5e.2 RED 测试质量门禁(仅 test-strategy=tdd 时,RED 任务完成后强制检查)
|
|
55
|
+
|
|
56
|
+
> ⛔ 核心原则:**Mock 边界,不 Mock 行为**
|
|
57
|
+
|
|
58
|
+
- [ ] **未 mock 被测行为本身**:测试的 Given 准备的是真实前置条件(如真实 invalid token 字符串),让被测代码自然走完链路;而非直接 mock 出期望的中间结果
|
|
59
|
+
- ❌ `when(jwtUtil.parseToken("invalid")).thenThrow(...)` — mock 了被测行为(解析失败),GREEN 只需加 try-catch
|
|
60
|
+
- ✅ 使用真实 JwtUtil + 真实 invalid token,让解析自然失败
|
|
61
|
+
- [ ] **Mock 仅用于系统边界依赖**:数据库 Mapper、HTTP 客户端等外部依赖可 mock;被测类自身的业务逻辑、实现被测行为的工具类不可 mock
|
|
62
|
+
- ✅ Mock `BookMapper.countByPublisher()` — 数据库边界
|
|
63
|
+
- ❌ Mock `JwtUtil.parseToken()` — 被测行为的实现
|
|
64
|
+
- [ ] **RED 测试的 Given 是真实输入**:传入真实数据让被测代码自行处理,不 mock 出"这个输入会导致什么结果"
|
|
65
|
+
- [ ] **删掉实现后测试仍因 mock 而通过?** 如果是 → 测试是假的,必须重写
|
|
66
|
+
- [ ] **GREEN 后测试不需要修改**:如果 GREEN 后需要改测试才能通过 → RED 测试有问题
|
|
67
|
+
|
|
41
68
|
### 任务状态实时更新
|
|
42
69
|
|
|
43
70
|
- [ ] tasks.md:`- [ ]` → `- [x]`(拓扑图和任务详情中的复选框)
|
|
@@ -81,6 +108,7 @@ description: opsx-apply 的阶段强制检查点与自检清单。仅在执行 a
|
|
|
81
108
|
- [ ] ⛔ **DAG 依赖拦截**:执行任务前必须检查依赖,前置未完成必须拦截
|
|
82
109
|
- [ ] ⛔ **编译检查门禁**:每完成一个任务后必须运行编译检查,编译失败禁止标记已完成
|
|
83
110
|
- [ ] ⛔ **测试执行门禁**:根据 `test-strategy` 决定(tdd=强制, impl-first=强制补跑, none=跳过);须真实执行并留 telemetry,`sdd-apply-test-gate` 校验非占位数据
|
|
111
|
+
- [ ] ⛔ **RED 测试质量门禁**:Mock 边界不 Mock 行为;未 mock 被测行为本身;Mock 仅用于系统边界依赖;RED 测试 Given 是真实输入
|
|
84
112
|
- [ ] ⛔ **必须实时更新任务状态**:每完成一个任务立即改 tasks.md,两种格式(`- [ ]`→`- [x]` 与 `**状态**: [ ]`→`[x]`)同步
|
|
85
113
|
- [ ] **Git 只读策略**:禁止为了度量自动初始化 Git、创建分支或提交 commit;非 Git 项目用 `vcs_mode=no-git` 继续执行
|
|
86
114
|
- [ ] ⛔ **Step 0.1 隔离校验必做**:建 worktree / 建议分支名前必须完成 proposal + 跨 cap spec 依赖校验并输出报告;未通过不得按 full 并行策略拆 `kld-sdd/<change>/<cap>`
|
|
@@ -2,6 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
在派发实现子代理时使用此模板。每个 DAG 任务由一个独立子代理执行。
|
|
4
4
|
|
|
5
|
+
## TDD 铁律(当 test-strategy=tdd 时生效)
|
|
6
|
+
|
|
7
|
+
**NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST.**
|
|
8
|
+
|
|
9
|
+
- 如果要写生产代码,必须先有一个失败的测试
|
|
10
|
+
- 如果先写了生产代码再写测试:删掉生产代码,从测试开始
|
|
11
|
+
- "太简单不用测" → 如果值得写,就值得测
|
|
12
|
+
- "事后补测一样" → 不一样,TDD 的价值在于测试驱动设计
|
|
13
|
+
- "删了浪费" → 删掉重来比带着错误前提实现更省时间
|
|
14
|
+
|
|
15
|
+
### 执行 测试-RED 任务
|
|
16
|
+
1. 读取对应 spec.md 场景和 design.md 设计
|
|
17
|
+
2. 编写测试代码:Given-When-Then 结构 + 真实断言
|
|
18
|
+
3. 运行测试:`mvn test -Dtest=XxxTest#testMethodName`(或项目对应命令)
|
|
19
|
+
4. 确认测试失败:失败原因必须是"功能未实现"(如 NullPointerException、AssertionError)
|
|
20
|
+
5. 如果测试通过:说明测试无效或功能已存在,重新编写测试
|
|
21
|
+
6. 记录失败原因到任务状态
|
|
22
|
+
|
|
23
|
+
**⛔ RED 测试质量标准(Mock 边界,不 Mock 行为):**
|
|
24
|
+
|
|
25
|
+
- **禁止 mock 被测行为本身**:测试的 Given 应准备**真实的前置条件**(如真实的 invalid token 字符串),让被测代码自然走完链路;而非直接 mock 出期望的中间结果
|
|
26
|
+
- ❌ `when(jwtUtil.parseToken("invalid")).thenThrow(...)` — mock 了被测行为(解析失败),GREEN 只需加 try-catch 就通过,测试无意义
|
|
27
|
+
- ✅ 使用真实 JwtUtil + 真实 invalid token 字符串,让解析自然失败,测试验证完整链路
|
|
28
|
+
- **Mock 仅用于系统边界依赖**:数据库 Mapper、HTTP 客户端、消息队列等外部依赖可 mock;但被测类自身的业务逻辑、实现被测行为的工具类不可 mock
|
|
29
|
+
- ✅ Mock `BookMapper.countByPublisher()` — 数据库边界,需要真实 DB 环境才能验证
|
|
30
|
+
- ❌ Mock `JwtUtil.parseToken()` — 这是被测行为的实现,mock 它等于跳过了被测逻辑
|
|
31
|
+
- **RED 测试的 Given 必须是真实输入**:传入真实的数据(如 `"invalid"` 字符串、`null`、空对象),让被测代码自行处理;不能 mock 出"这个输入会导致什么结果"
|
|
32
|
+
- **判断标准**:如果删掉被测类的实现(方法体清空),测试是否仍然因为 mock 而通过?如果是,说明测试是假的——真实测试应该在实现缺失时失败
|
|
33
|
+
|
|
34
|
+
### 执行 实现-GREEN 任务
|
|
35
|
+
1. 读取对应 RED 任务的失败原因
|
|
36
|
+
2. 编写**最少代码**让该测试通过
|
|
37
|
+
3. 不提前实现没有测试要求的功能(YAGNI)
|
|
38
|
+
4. **⛔ 禁止捆绑未测试的代码**:
|
|
39
|
+
- 如果 RED 测试只测了 Service 方法,GREEN 不得同时实现 Controller 接口
|
|
40
|
+
- 如果 RED 测试只测了一个行为点,GREEN 不得同时实现其他行为点的逻辑
|
|
41
|
+
- 如果需要修改多个文件才能让测试通过,检查是否测试范围过大
|
|
42
|
+
5. 运行测试:确认通过
|
|
43
|
+
6. 如果引入了新功能但无对应测试:删除多余代码
|
|
44
|
+
7. 自检:本次修改的文件列表是否与 RED 测试覆盖的范围一致?如果超出,报告 DONE_WITH_CONCERNS
|
|
45
|
+
|
|
46
|
+
### 执行 重构-REFACTOR 任务
|
|
47
|
+
1. 在所有测试通过的状态下开始
|
|
48
|
+
2. 优化代码结构(提取方法、消除重复、改善命名)
|
|
49
|
+
3. 运行**全部测试**:`mvn test`(或项目对应命令)
|
|
50
|
+
4. 确认所有测试仍通过
|
|
51
|
+
5. 如果任何测试失败:回退重构,重新尝试
|
|
52
|
+
|
|
5
53
|
## 派发格式
|
|
6
54
|
|
|
7
55
|
```
|
|
@@ -13,7 +61,7 @@ Agent (general-purpose):
|
|
|
13
61
|
## 当前任务
|
|
14
62
|
|
|
15
63
|
[TASK-ID]: [完整任务描述,从 tasks.md 中提取]
|
|
16
|
-
- 类型: [
|
|
64
|
+
- 类型: [数据层/接口层/UI层/测试-RED/实现-GREEN/重构-REFACTOR/测试-验证/配置]
|
|
17
65
|
- 依赖: [前置任务列表] ✅ 已完成
|
|
18
66
|
- 层级: [N]
|
|
19
67
|
|
|
@@ -50,8 +98,11 @@ Agent (general-purpose):
|
|
|
50
98
|
2. 遵循 design.md 的设计约定
|
|
51
99
|
3. 遵循 overview.md 的全局规范
|
|
52
100
|
4. 保持变更最小化,不超出任务范围
|
|
53
|
-
5.
|
|
54
|
-
6.
|
|
101
|
+
5. **当任务类型为 测试-RED 时**:编写带真实断言的测试,运行并确认失败,记录失败原因
|
|
102
|
+
6. **当任务类型为 实现-GREEN 时**:读取对应 RED 的失败原因,写最少代码让测试通过,不提前实现未要求的功能
|
|
103
|
+
7. **当任务类型为 重构-REFACTOR 时**:在测试全绿状态下优化代码,运行全部测试确认仍绿
|
|
104
|
+
8. 自我审查(见下方)
|
|
105
|
+
9. 报告结果
|
|
55
106
|
|
|
56
107
|
工作目录:[项目根目录]
|
|
57
108
|
|
|
@@ -370,6 +370,32 @@ node skywalk-sdd/log.cjs record --type=ai_adoption_review --command=apply --proj
|
|
|
370
370
|
|
|
371
371
|
---
|
|
372
372
|
|
|
373
|
+
## §6.0a 测试反模式检查(TDD 模式下,RED 阶段 + GREEN 完成后双重检查)
|
|
374
|
+
|
|
375
|
+
> ⛔ **RED 阶段就必须检查**:不要等到 GREEN 之后才发现测试是假的。RED 写完立即自检,发现反模式立即重写。
|
|
376
|
+
|
|
377
|
+
### RED 阶段强制检查(写完测试、运行确认失败后)
|
|
378
|
+
|
|
379
|
+
| 反模式 | 表现 | 修复方案 |
|
|
380
|
+
|--------|------|---------|
|
|
381
|
+
| **Mock 被测行为本身** | `when(jwtUtil.parseToken("invalid")).thenThrow(...)` — mock 了被测行为(解析失败),GREEN 只需加 try-catch | 使用真实 JwtUtil + 真实 invalid token,让解析自然失败 |
|
|
382
|
+
| **Mock 预定结论而非准备条件** | `when(bookMapper.countByPublisher(1L)).thenReturn(3)` 后只测 `if (count > 0) throw` — trivial 逻辑 | Mock 边界依赖(Mapper)是合理的,但测试断言应验证完整行为链路(如 verify 不会执行 delete) |
|
|
383
|
+
| **Given 不是真实输入** | mock 出"这个输入会导致什么结果",而非传入真实数据让被测代码自行处理 | 传入真实数据(如 `"invalid"` 字符串、`null`),让被测代码自行决定结果 |
|
|
384
|
+
|
|
385
|
+
### GREEN 完成后补充检查
|
|
386
|
+
|
|
387
|
+
| 反模式 | 表现 | 修复方案 |
|
|
388
|
+
|--------|------|---------|
|
|
389
|
+
| 测试 mock 行为而非真实行为 | 测试验证的是 mock 被调用,而非真实业务逻辑 | 测试应验证输出/状态变化,而非方法调用 |
|
|
390
|
+
| 生产类中加测试专用方法 | 为方便测试在生产类中加了 public/protected 方法 | 通过公共 API 测试,不加测试专用方法 |
|
|
391
|
+
| 不理解依赖就 mock | mock 了不理解的依赖,隐藏了结构假设 | 先理解依赖的职责再决定是否 mock |
|
|
392
|
+
| 不完整的 mock | partial mock 隐藏了对象间的结构关系 | 要么完整 mock,要么用真实对象 |
|
|
393
|
+
| 集成测试作为事后补充 | 单元测试不足,用集成测试弥补 | 每个行为点应有独立的单元测试 |
|
|
394
|
+
|
|
395
|
+
> 参照来源:`skill-references/superpowers-tdd/testing-anti-patterns.md`
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
373
399
|
## §6.1 Worktree 收尾(仅当 §1.5 已创建 worktree)
|
|
374
400
|
|
|
375
401
|
> **⛔ 本次 Apply 若创建了 worktree**:DAG 全部完成且 **§6.0 测试门禁(若适用)** 通过后,必须在**主仓库根目录**执行收尾脚本(禁止在 `.worktrees/...` 内执行)。
|
|
@@ -33,7 +33,7 @@ allowed-tools:
|
|
|
33
33
|
> - 不要省略 `--source=opsx-command` 与 `--session-id=<会话ID>`。
|
|
34
34
|
> **📊 Telemetry(必做,不得跳过)**
|
|
35
35
|
> - 阶段开始:`node skywalk-sdd/log.cjs start --command=check --project=. --change=<变更名称> --capability=<可选capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID>`(保存 event_id)
|
|
36
|
-
> - 检查报告生成后,必须先记录结构化检查结果:`node skywalk-sdd/log.cjs record --type=check_result --command=check --project=. --change=<变更名称> --capability=<可选capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --result=success/partial/failure --summary="检查结果摘要" --details-json="{\"check_results\":{\"total\":0,\"errors\":0,\"warnings\":0,\"warning_items\":[],\"suggestions\":0,\"fixed_before_apply\":0,\"consistency_score\":null,\"categories\":{\"completeness\":{\"passed\":0,\"total\":0},\"consistency\":{\"passed\":0,\"total\":0},\"executability\":{\"passed\":0,\"total\":0}},\"task_completion\":{\"completed\":0,\"incomplete\":0,\"total\":0,\"has_incomplete\":false,\"checked_for_archive_readiness\":false}}}"`
|
|
36
|
+
> - 检查报告生成后,必须先记录结构化检查结果:`node skywalk-sdd/log.cjs record --type=check_result --command=check --project=. --change=<变更名称> --capability=<可选capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --result=success/partial/failure --summary="检查结果摘要" --details-json="{\"check_results\":{\"total\":0,\"errors\":0,\"warnings\":0,\"warning_items\":[],\"suggestions\":0,\"fixed_before_apply\":0,\"consistency_score\":null,\"categories\":{\"completeness\":{\"passed\":0,\"total\":0},\"consistency\":{\"passed\":0,\"total\":0},\"executability\":{\"passed\":0,\"total\":0},\"tdd_compliance\":{\"passed\":0,\"total\":0}},\"task_completion\":{\"completed\":0,\"incomplete\":0,\"total\":0,\"has_incomplete\":false,\"checked_for_archive_readiness\":false}}}"`
|
|
37
37
|
> - `check_result` 记录成功后,才允许阶段结束:`node skywalk-sdd/log.cjs end --event-id=<event_id> --command=check --project=. --change=<变更名称> --capability=<可选capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --result=success/partial/failure --summary="摘要"`
|
|
38
38
|
> - **【B1 摘要数字校验】** `stage_end --summary` 中的数字(如「N 个场景」「N 层 DAG」「N 个任务」)必须与 `spec.md`/`tasks.md`/`test-scenarios.md` 的实统计交叉校验一致后再填写,不得凭记忆自填。典型失真:summary 写「11 个场景」实际 spec 含 13 条断言、「5 层 DAG」实际 tasks 修复后为 6 层。check 阶段发现不一致时,修正 summary 或补齐文档,使三者数字自洽。
|
|
39
39
|
|
|
@@ -45,7 +45,7 @@ allowed-tools:
|
|
|
45
45
|
|------|------|
|
|
46
46
|
| 核心问题 | 文档链质量是否达标 |
|
|
47
47
|
| 关键输出 | 检查报告(通过/警告/失败) |
|
|
48
|
-
| 检查维度 |
|
|
48
|
+
| 检查维度 | 完整性、一致性、算法正确性、可执行性、TDD合规性(仅test-strategy=tdd时) |
|
|
49
49
|
| 上游依赖 | proposal → specs → design → tasks 全文档链 |
|
|
50
50
|
|
|
51
51
|
---
|
|
@@ -81,7 +81,7 @@ openspec list
|
|
|
81
81
|
| 代码文件 | 验证 design 可行性、锚点准确性 | 可执行性 |
|
|
82
82
|
| 算法文档 | 验证算法设计正确性 | 算法正确性 |
|
|
83
83
|
|
|
84
|
-
### 4.
|
|
84
|
+
### 4. 执行五维质量检查
|
|
85
85
|
|
|
86
86
|
#### 4.1 完整性检查
|
|
87
87
|
|
|
@@ -111,6 +111,20 @@ openspec list
|
|
|
111
111
|
- [ ] 所有外部依赖已明确状态
|
|
112
112
|
- [ ] 代码锚点存在且可访问
|
|
113
113
|
|
|
114
|
+
#### 4.4a TDD 合规性检查(仅 test-strategy=tdd 时执行)
|
|
115
|
+
|
|
116
|
+
检查项:
|
|
117
|
+
1. RED 任务验收标准是否包含"测试运行失败"(而非"断言为空")
|
|
118
|
+
2. GREEN 任务是否为行为级粒度(一个 GREEN 对应一个 RED,非模块级)
|
|
119
|
+
3. DAG 中是否存在 RED→GREEN 循环对(而非 TEST(全部)→IMPL(全部)批次)
|
|
120
|
+
4. 是否存在 REFACTOR 任务(推荐但不强制)
|
|
121
|
+
5. 非 TDD 模块(前端/配置/SQL)是否正确排除红绿循环
|
|
122
|
+
6. GREEN 任务验收标准是否为"让对应 RED 通过"(而非"实现完整功能")
|
|
123
|
+
7. **GREEN 任务无捆绑**:每个 GREEN 任务的输出不包含未测试的 Controller/Filter/Config
|
|
124
|
+
8. **Controller 层策略已声明**:tasks.md 中明确声明 Controller 层使用策略 A 或策略 B
|
|
125
|
+
9. **RED 任务有测试方法名**:每个 RED 任务包含 `{method}_{state}_{outcome}` 格式的测试方法名
|
|
126
|
+
10. **REFACTOR 有具体方向**:每个 REFACTOR 任务列出至少 2 个具体重构点
|
|
127
|
+
|
|
114
128
|
#### 4.5 任务完成状态检查(实现后 / 归档前)
|
|
115
129
|
|
|
116
130
|
`task` 阶段允许 `tasks.md` 出现未完成项;这只是计划状态。但如果当前变更已经进入 apply 之后,或本次 check 发现实现代码、测试报告、`build_result/test_result/task_update/conformance_review` 等实施证据,必须检查任务勾选状态:
|
|
@@ -135,6 +149,7 @@ node skywalk-sdd/log.cjs tasks-status --project=. --change=<变更名称>
|
|
|
135
149
|
> | 一致性 | ✅/⚠️/❌ | [具体问题] |
|
|
136
150
|
> | 算法正确性 | ✅/⚠️/❌ | [具体问题] |
|
|
137
151
|
> | 可执行性 | ✅/⚠️/❌ | [具体问题] |
|
|
152
|
+
> | TDD合规性 | ✅/⚠️/❌/— | [仅test-strategy=tdd时检查] |
|
|
138
153
|
>
|
|
139
154
|
> **总体结果**:✅ 通过 / ⚠️ 有警告 / ❌ 未通过
|
|
140
155
|
>
|
|
@@ -158,7 +173,7 @@ node skywalk-sdd/log.cjs tasks-status --project=. --change=<变更名称>
|
|
|
158
173
|
|
|
159
174
|
在终端执行(必须成功):
|
|
160
175
|
```bash
|
|
161
|
-
node skywalk-sdd/log.cjs record --type=check_result --command=check --project=. --change=<变更名称> --capability=<可选capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --result=success/partial/failure --summary="检查结果摘要" --details-json="{\"check_results\":{\"total\":0,\"errors\":0,\"warnings\":0,\"warning_items\":[],\"suggestions\":0,\"fixed_before_apply\":0,\"consistency_score\":null,\"categories\":{\"completeness\":{\"passed\":0,\"total\":0},\"consistency\":{\"passed\":0,\"total\":0},\"executability\":{\"passed\":0,\"total\":0}},\"task_completion\":{\"completed\":0,\"incomplete\":0,\"total\":0,\"has_incomplete\":false,\"checked_for_archive_readiness\":false}}}"
|
|
176
|
+
node skywalk-sdd/log.cjs record --type=check_result --command=check --project=. --change=<变更名称> --capability=<可选capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --result=success/partial/failure --summary="检查结果摘要" --details-json="{\"check_results\":{\"total\":0,\"errors\":0,\"warnings\":0,\"warning_items\":[],\"suggestions\":0,\"fixed_before_apply\":0,\"consistency_score\":null,\"categories\":{\"completeness\":{\"passed\":0,\"total\":0},\"consistency\":{\"passed\":0,\"total\":0},\"executability\":{\"passed\":0,\"total\":0},\"tdd_compliance\":{\"passed\":0,\"total\":0}},\"task_completion\":{\"completed\":0,\"incomplete\":0,\"total\":0,\"has_incomplete\":false,\"checked_for_archive_readiness\":false}}}"
|
|
162
177
|
```
|
|
163
178
|
|
|
164
179
|
> **⚠️ P1-1 check_result details 不得为空**:`--details-json` 必须含 `consistency_score` / `categories` / `task_completion` 等字段,**禁止传空对象 `{}`**。空 details 会导致 report 的 Q5 跨文档一致性得分、P4b 修复率为 null(工具侧虽有 state fallback 兜底,但事件 details 是主数据源)。
|
|
@@ -33,7 +33,23 @@ description: "opsx-check 阶段日志自检清单 — 仅在 check 自检时读
|
|
|
33
33
|
|
|
34
34
|
## D. 检查报告四维
|
|
35
35
|
|
|
36
|
-
- [ ]
|
|
36
|
+
- [ ] 完整性、一致性、算法正确性、可执行性、TDD合规性(仅test-strategy=tdd时)五维均已输出
|
|
37
37
|
- [ ] 报告问题对应修复建议(spec/design/task)
|
|
38
|
+
|
|
39
|
+
## E. TDD 合规性检查(仅 test-strategy=tdd 时)
|
|
40
|
+
|
|
41
|
+
- [ ] tasks.md 中 测试-RED 任务的验收标准包含"测试运行失败"
|
|
42
|
+
- [ ] tasks.md 中无"断言为空"或"编译通过但断言为空"的验收标准
|
|
43
|
+
- [ ] tasks.md 中 实现-GREEN 任务为行为级粒度(一对一对应 RED)
|
|
44
|
+
- [ ] tasks.md 中 DAG 存在 RED→GREEN 循环对
|
|
45
|
+
- [ ] tasks.md 中非 TDD 模块未拆红绿循环
|
|
46
|
+
- [ ] tasks.md 中 GREEN 任务的输出不包含未测试的 Controller/Filter/Config
|
|
47
|
+
- [ ] tasks.md 中已声明 Controller 层处理策略(策略 A 或策略 B)
|
|
48
|
+
- [ ] tasks.md 中每个 RED 任务包含测试方法名
|
|
49
|
+
- [ ] tasks.md 中每个 REFACTOR 任务列出至少 2 个具体重构点
|
|
50
|
+
- [ ] check_result 的 categories 中包含 `tdd_compliance`
|
|
51
|
+
|
|
52
|
+
## F. 语义门禁与工作态
|
|
53
|
+
|
|
38
54
|
- [ ] `openspec/changes/<变更名称>/artifact-index.json` 已覆盖当前全部 proposal/spec/design/tasks,且每份 `artifacts/*.ontology.json` 与 `working-ontology.json` revision 一致
|
|
39
55
|
- [ ] 全部语义门禁通过时工作态 JSON 已从 draft 刷新为 pending;check 未修改任何 Markdown 原文
|
|
@@ -56,10 +56,12 @@ description: opsx-propose 的详细模板:telemetry 命令、文档拆分模
|
|
|
56
56
|
|
|
57
57
|
> "🧪 **请选择测试策略:**
|
|
58
58
|
>
|
|
59
|
-
> **A) 测试驱动 (TDD)** -
|
|
60
|
-
> -
|
|
61
|
-
> - DAG:
|
|
62
|
-
> -
|
|
59
|
+
> **A) 测试驱动 (TDD)** - 红绿重构循环
|
|
60
|
+
> - 每个行为点先写失败测试(红),再写最少代码让它通过(绿),最后重构
|
|
61
|
+
> - DAG: RED → GREEN → REFACTOR → RED → GREEN → ...(行为级小步循环)
|
|
62
|
+
> - 任务数量较多(每个行为点一对红绿),但每个测试都真实驱动实现
|
|
63
|
+
> - 适合:核心业务逻辑、质量要求高、需要测试驱动设计
|
|
64
|
+
> - ⚠️ 注意:TDD 模式下任务数量会显著增加(约为模块级拆分的 3-5 倍)
|
|
63
65
|
>
|
|
64
66
|
> **B) 实现优先 (Impl-First)** - 代码先行
|
|
65
67
|
> - 先生成实现任务,测试作为验证步骤
|
|
@@ -133,7 +133,7 @@ Simple 模式或单文件能力域下,**不要拆成多个同文件任务**。
|
|
|
133
133
|
**若已设置**:向用户确认
|
|
134
134
|
> "🧪 **当前测试策略:[test-strategy]**
|
|
135
135
|
>
|
|
136
|
-
> - `tdd`:
|
|
136
|
+
> - `tdd`: 红绿重构循环 - 每个行为点先写失败测试(红),再写最少代码让它通过(绿),最后重构
|
|
137
137
|
> - `impl-first`: 实现优先 - 先实现后测试
|
|
138
138
|
> - `none`: 无测试 - 不生成测试任务
|
|
139
139
|
>
|
|
@@ -142,10 +142,12 @@ Simple 模式或单文件能力域下,**不要拆成多个同文件任务**。
|
|
|
142
142
|
**若未设置**:使用 **AskUserQuestion** 工具询问
|
|
143
143
|
> "🧪 **未检测到测试策略配置,请选择:**
|
|
144
144
|
>
|
|
145
|
-
> **A) 测试驱动 (TDD)** -
|
|
146
|
-
> -
|
|
147
|
-
> - DAG
|
|
148
|
-
> -
|
|
145
|
+
> **A) 测试驱动 (TDD)** - 红绿重构循环
|
|
146
|
+
> - 每个行为点先写失败测试(红),再写最少代码让它通过(绿),最后重构
|
|
147
|
+
> - DAG 顺序:RED → GREEN → REFACTOR → RED → GREEN → ...(行为级小步循环)
|
|
148
|
+
> - 任务数量较多(每个行为点一对红绿),但每个测试都真实驱动实现
|
|
149
|
+
> - 适合:核心业务逻辑、质量要求高、需要测试驱动设计
|
|
150
|
+
> - ⚠️ 注意:TDD 模式下任务数量会显著增加(约为模块级拆分的 3-5 倍)
|
|
149
151
|
>
|
|
150
152
|
> **B) 实现优先 (Impl-First)** - 代码先行
|
|
151
153
|
> - 先生成实现任务,测试作为验证步骤
|
|
@@ -162,6 +164,16 @@ Simple 模式或单文件能力域下,**不要拆成多个同文件任务**。
|
|
|
162
164
|
|
|
163
165
|
向用户确认拆解维度、任务粒度、预计 DAG 层级。**根据 test-strategy 调整 DAG 生成规则**,规则表(tdd / impl-first / none 对应的 DAG 生成规则)见 `./reference.md`「§6 DAG 生成规则表」。
|
|
164
166
|
|
|
167
|
+
**当 test-strategy=tdd 时,必须向用户说明:**
|
|
168
|
+
> "🧪 TDD 模式将采用红绿重构循环:
|
|
169
|
+
> - 每个行为点拆为一对 RED+GREEN 任务(+可选 REFACTOR)
|
|
170
|
+
> - 任务数量会比模块级拆分更多,但每个测试都真实驱动一段实现
|
|
171
|
+
> - RED 任务验收标准:测试运行失败,且失败原因正确(功能未实现)
|
|
172
|
+
> - GREEN 任务验收标准:写最少代码让对应 RED 测试通过
|
|
173
|
+
> - 非 TDD 模块(前端 UI、配置、SQL DDL)不拆红绿,按常规任务处理
|
|
174
|
+
>
|
|
175
|
+
> 是否继续使用 TDD 策略?"
|
|
176
|
+
|
|
165
177
|
### 7. 创建局部 tasks.md(含 DAG 拓扑)
|
|
166
178
|
|
|
167
179
|
**输出路径**:`changes/<name>/specs/<capability>/tasks.md`
|
|
@@ -170,9 +182,30 @@ Simple 模式或单文件能力域下,**不要拆成多个同文件任务**。
|
|
|
170
182
|
|
|
171
183
|
> **必须包含**:任务执行拓扑图(DAG)+ 原子任务清单。任务结构字段(TASK-ID / 类型 / 依赖 / 状态 / 描述等)见 `./reference.md`「§7 任务结构」。
|
|
172
184
|
|
|
185
|
+
**当 test-strategy=tdd 时,任务生成规则:**
|
|
186
|
+
1. 将 spec.md 中每个需求项的每个场景拆为一个行为点
|
|
187
|
+
2. 每个行为点生成一对任务:`[TASK-XX-RED-N]` + `[TASK-XX-GREEN-N]`
|
|
188
|
+
3. RED 任务依赖:前置基础设施任务(如脚手架、数据层)
|
|
189
|
+
4. GREEN 任务依赖:对应的 RED 任务
|
|
190
|
+
5. 可选:每 3-5 个行为点后插入一个 `[TASK-XX-REFACTOR]` 任务
|
|
191
|
+
6. 模块末尾可保留一个 `[TASK-XX-VERIFY]` 任务做全量测试验证
|
|
192
|
+
7. 非 TDD 模块(如前端 UI、配置、SQL DDL)不拆红绿,按常规任务处理
|
|
193
|
+
8. RED 任务验收标准必须包含"测试运行失败,且失败原因正确(功能未实现)"
|
|
194
|
+
9. GREEN 任务验收标准必须包含"写最少代码让对应 RED 测试通过",不包含"实现完整功能"。
|
|
195
|
+
**⛔ 禁止在 GREEN 任务中捆绑未测试的代码**(如 Controller 接口、Filter、Config 等)。
|
|
196
|
+
如果 GREEN 需要同时修改多个文件才能让测试通过,检查是否测试范围过大或实现范围超出测试要求。
|
|
197
|
+
10. **GREEN 任务范围限制**:每个 GREEN 任务只能实现让对应 RED 测试通过的代码,禁止捆绑未测试的功能。具体规则:
|
|
198
|
+
- Service 层 GREEN 只实现当前行为点的 Service 方法逻辑
|
|
199
|
+
- Controller 层不捆绑在 Service GREEN 中,必须独立处理
|
|
200
|
+
11. **Controller 层处理策略**(二选一,由 AI 根据项目复杂度判断,必须在 tasks.md §2.0 中声明):
|
|
201
|
+
- 策略 A(推荐):为每个 Controller 接口生成 RED 测试(使用 @WebMvcTest),拆为 RED→GREEN 对
|
|
202
|
+
- 策略 B:将 Controller 层声明为非 TDD 模块,作为独立接口层任务,依赖对应 Service 完成
|
|
203
|
+
- 无论哪种策略,Controller 不得捆绑在 Service 的 GREEN 任务中
|
|
204
|
+
12. **RED 任务必须包含**:测试方法名(`{method}_{state}_{outcome}` 格式)、Given-When-Then 结构描述、输出文件路径、关联 spec 场景编号
|
|
205
|
+
|
|
173
206
|
### 8. 质量红线自检
|
|
174
207
|
|
|
175
|
-
> 逐项确认,完整 7
|
|
208
|
+
> 逐项确认,完整 7 项自检清单 + TDD 合规性自检(结构符合模板 / 拓扑图已绘制 / 依赖字段已填写 / 无循环依赖 / 颗粒度 ≤5 分钟 / 100% 覆盖 design / 每任务有验收标准)见 `./checklist.md`「§8 质量红线自检 + §8.1 TDD 合规性自检」。如有任意一项未满足,重新生成对应章节,直至全部通过。
|
|
176
209
|
|
|
177
210
|
### 9. 确认任务并输出
|
|
178
211
|
|
|
@@ -220,5 +253,5 @@ Simple 模式或单文件能力域下,**不要拆成多个同文件任务**。
|
|
|
220
253
|
|
|
221
254
|
## 渐进披露
|
|
222
255
|
|
|
223
|
-
- Read `checklist.md` 仅在执行 task 需要校验时 — 含阶段边界⛔(Task 阶段约束)、§8 质量红线自检(7
|
|
224
|
-
- Read `reference.md` 仅在需要参考详细模板时 — 含 📊 Telemetry 命令模板(start/end)、§6 DAG 生成规则表(tdd/impl-first/none)、§7 任务结构(TASK-ID/类型/依赖/状态/描述等字段)。
|
|
256
|
+
- Read `checklist.md` 仅在执行 task 需要校验时 — 含阶段边界⛔(Task 阶段约束)、§8 质量红线自检(7 项 + TDD 合规性自检)、Guardrails ⛔ 强制项勾选表。
|
|
257
|
+
- Read `reference.md` 仅在需要参考详细模板时 — 含 📊 Telemetry 命令模板(start/end)、§6 DAG 生成规则表(tdd/impl-first/none)、§6.1 TDD 拆分示例、§6.2 非 TDD 模块处理规则、§7 任务结构(TASK-ID/类型/依赖/状态/描述等字段)。
|
|
@@ -34,6 +34,21 @@ description: opsx-task 的阶段强制检查点与自检清单。仅在执行 ta
|
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
37
|
+
## §8.1 TDD 合规性自检(仅 test-strategy=tdd 时)
|
|
38
|
+
|
|
39
|
+
- [ ] **RED 任务有真实断言**:每个 测试-RED 任务的验收标准包含"测试运行失败",而非"断言为空"或"编译通过"
|
|
40
|
+
- [ ] **GREEN 任务为行为级粒度**:每个 实现-GREEN 任务只对应一个 RED 测试,不是模块级整体实现
|
|
41
|
+
- [ ] **存在红绿循环**:DAG 中存在 RED→GREEN 的循环对,而非 TEST(全部)→IMPL(全部)的批次模式
|
|
42
|
+
- [ ] **有 REFACTOR 任务**:每 3-5 个行为点后至少有一个重构任务(可选但推荐)
|
|
43
|
+
- [ ] **GREEN 验收为"最少代码"**:验收标准包含"让对应 RED 测试通过",不包含"实现完整功能"
|
|
44
|
+
- [ ] **非 TDD 模块已排除**:前端 UI、配置、SQL DDL 等不拆红绿循环
|
|
45
|
+
- [ ] **GREEN 任务无捆绑**:每个 GREEN 任务的输出文件不包含未测试的 Controller/Filter/Config(除非该 GREEN 对应的 RED 测试明确测试了这些组件)
|
|
46
|
+
- [ ] **Controller 层策略已声明**:tasks.md §2.0 中明确声明 Controller 层使用策略 A(拆 RED→GREEN)还是策略 B(非 TDD 任务)
|
|
47
|
+
- [ ] **RED 任务有测试方法名**:每个 RED 任务包含 `{method}_{state}_{outcome}` 格式的测试方法名
|
|
48
|
+
- [ ] **REFACTOR 有具体方向**:每个 REFACTOR 任务列出至少 2 个具体重构点
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
37
52
|
## Guardrails ⛔ 强制项
|
|
38
53
|
|
|
39
54
|
- [ ] 必须以 `openspec-templates/tasks.md` 为模板基准
|
|
@@ -22,19 +22,90 @@ description: opsx-task 的详细模板:telemetry 命令、DAG 生成规则表
|
|
|
22
22
|
|
|
23
23
|
| test-strategy | DAG 生成规则 |
|
|
24
24
|
|---------------|---------------|
|
|
25
|
-
| `tdd` |
|
|
25
|
+
| `tdd` | 每个行为点拆为 RED→GREEN 对,GREEN Depends-On RED;每 3-5 个行为点后可插入 REFACTOR(Depends-On 前一个 GREEN);模块末尾可加 VERIFY(Depends-On 最后一个 GREEN/REFACTOR) |
|
|
26
26
|
| `impl-first` | 实现任务在前,测试任务 Depends-On 实现任务 |
|
|
27
27
|
| `none` | 不生成测试任务,仅编译检查 |
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
+
## §6.1 TDD 拆分示例
|
|
32
|
+
|
|
33
|
+
### TDD 模式拆分示例(认证模块)
|
|
34
|
+
|
|
35
|
+
spec.md user-auth 定义了 7 个场景,拆为 7 对 RED+GREEN + 1 个 REFACTOR:
|
|
36
|
+
|
|
37
|
+
| 任务 ID | 行为点 | 类型 | 依赖 | 验收标准 |
|
|
38
|
+
|---------|--------|------|------|---------|
|
|
39
|
+
| TASK-05-RED-1 | 登录成功返回 Token | 测试-RED | TASK-04-IMPL | 测试带断言运行失败,失败原因:AuthService 未实现 |
|
|
40
|
+
| TASK-05-GREEN-1 | 登录成功最小实现 | 实现-GREEN | TASK-05-RED-1 | 写最少代码让 RED-1 通过,不提前实现密码校验等 |
|
|
41
|
+
| TASK-05-RED-2 | 密码错误返回 2001 | 测试-RED | TASK-05-GREEN-1 | 测试失败,失败原因:未校验密码 |
|
|
42
|
+
| TASK-05-GREEN-2 | 密码校验实现 | 实现-GREEN | TASK-05-RED-2 | 让 RED-2 通过 |
|
|
43
|
+
| TASK-05-RED-3 | 账号禁用返回 2002 | 测试-RED | TASK-05-GREEN-2 | 测试失败 |
|
|
44
|
+
| TASK-05-GREEN-3 | 账号状态校验 | 实现-GREEN | TASK-05-RED-3 | 让 RED-3 通过 |
|
|
45
|
+
| TASK-05-RED-4 | Refresh Token 有效 | 测试-RED | TASK-05-GREEN-3 | 测试失败 |
|
|
46
|
+
| TASK-05-GREEN-4 | Refresh 实现 | 实现-GREEN | TASK-05-RED-4 | 让 RED-4 通过 |
|
|
47
|
+
| TASK-05-RED-5 | Refresh Token 无效返回 3001 | 测试-RED | TASK-05-GREEN-4 | 测试失败 |
|
|
48
|
+
| TASK-05-GREEN-5 | Refresh 校验实现 | 实现-GREEN | TASK-05-RED-5 | 让 RED-5 通过 |
|
|
49
|
+
| TASK-05-RED-6 | 登出加入黑名单 | 测试-RED | TASK-05-GREEN-5 | 测试失败 |
|
|
50
|
+
| TASK-05-GREEN-6 | 登出实现 | 实现-GREEN | TASK-05-RED-6 | 让 RED-6 通过 |
|
|
51
|
+
| TASK-05-REFACTOR | 重构优化 | 重构-REFACTOR | TASK-05-GREEN-6 | 所有测试仍绿,代码清理 |
|
|
52
|
+
|
|
53
|
+
**关键区别**:
|
|
54
|
+
- 每个 RED 任务都带**真实断言**,跑起来确实失败
|
|
55
|
+
- 每个 GREEN 任务只写**让当前测试通过的最少代码**
|
|
56
|
+
- 行为点粒度,一次一个,有小步循环
|
|
57
|
+
- 重构独立成任务,在全部绿灯后进行
|
|
58
|
+
|
|
59
|
+
### Controller 层处理示例
|
|
60
|
+
|
|
61
|
+
**策略 A:Controller 也拆 RED→GREEN(推荐,适合接口数量少时)**
|
|
62
|
+
|
|
63
|
+
| 任务 ID | 行为点 | 类型 | 依赖 | 验收标准 |
|
|
64
|
+
|---------|--------|------|------|---------|
|
|
65
|
+
| TASK-05-RED-8 | POST /auth/login 返回 Token | 测试-RED | TASK-05-GREEN-1 | @WebMvcTest 测试 HTTP 请求,断言响应 JSON 含 accessToken,测试失败 |
|
|
66
|
+
| TASK-05-GREEN-8 | AuthController.login() 实现 | 实现-GREEN | TASK-05-RED-8 | 只实现 login 接口让 RED-8 通过 |
|
|
67
|
+
| TASK-05-RED-9 | POST /auth/refresh 返回新 Token | 测试-RED | TASK-05-GREEN-4 | 测试失败 |
|
|
68
|
+
| TASK-05-GREEN-9 | AuthController.refresh() 实现 | 实现-GREEN | TASK-05-RED-9 | 只实现 refresh 接口 |
|
|
69
|
+
| TASK-05-RED-10 | POST /auth/logout 返回成功 | 测试-RED | TASK-05-GREEN-6 | 测试失败 |
|
|
70
|
+
| TASK-05-GREEN-10 | AuthController.logout() 实现 | 实现-GREEN | TASK-05-RED-10 | 只实现 logout 接口 |
|
|
71
|
+
|
|
72
|
+
**策略 B:Controller 作为非 TDD 任务(适合接口数量多时)**
|
|
73
|
+
|
|
74
|
+
| 任务 ID | 行为点 | 类型 | 依赖 | 验收标准 |
|
|
75
|
+
|---------|--------|------|------|---------|
|
|
76
|
+
| TASK-05-CTRL | AuthController 3 个接口接线 | 接口层 | TASK-05-GREEN-6 | Controller 编译通过,调用对应 Service 方法,返回 Result 统一响应体 |
|
|
77
|
+
|
|
78
|
+
注意:策略 B 中 Controller 任务不是 GREEN,不对应任何 RED 测试,仅做编译检查。
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## §6.2 非 TDD 模块处理规则
|
|
83
|
+
|
|
84
|
+
以下模块不需要红绿循环,按常规任务处理:
|
|
85
|
+
- 前端 UI 页面(Vue 组件)→ UI层任务
|
|
86
|
+
- 项目脚手架/配置(pom.xml, application.yml)→ 配置任务
|
|
87
|
+
- 数据库迁移脚本(SQL DDL)→ 数据层任务
|
|
88
|
+
- 前端路由/状态管理/API 封装 → UI层任务
|
|
89
|
+
- Controller 层(可选)→ 接口层任务(当选择策略 B 时,Controller 作为接线层不拆红绿)
|
|
90
|
+
|
|
91
|
+
⚠️ Controller 层处理策略需在 tasks.md §2.0 中明确声明,不能默认选择。
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
31
95
|
## §7 任务结构
|
|
32
96
|
|
|
33
97
|
**必须包含**:
|
|
34
98
|
1. **任务执行拓扑图(DAG)** - 层级关系清晰
|
|
35
99
|
2. **原子任务清单** - 每个任务包含:
|
|
36
100
|
- `[TASK-XXX-01]` 唯一标识
|
|
37
|
-
- `类型`: 数据层 / 接口层 / UI层 /
|
|
101
|
+
- `类型`: 数据层 / 接口层 / UI层 / 测试-RED / 实现-GREEN / 重构-REFACTOR / 测试-验证 / 配置
|
|
38
102
|
- `依赖`: 前置依赖(无 或 TASK-ID 列表)
|
|
39
103
|
- `状态`: [ ] 未完成
|
|
40
104
|
- 任务描述、输入、输出、实现步骤、验收标准
|
|
105
|
+
- **测试-RED 任务额外必填**:
|
|
106
|
+
- 测试方法名:`{method}_{state}_{outcome}` 格式
|
|
107
|
+
- Given-When-Then 结构描述
|
|
108
|
+
- 输出文件路径
|
|
109
|
+
- 关联 spec 场景编号
|
|
110
|
+
- **重构-REFACTOR 任务额外必填**:
|
|
111
|
+
- 具体重构方向(至少列出 2 个重构点,如"提取公共方法""消除重复代码")
|
|
@@ -131,6 +131,23 @@ node skywalk-sdd/log.cjs record --type=test_result --command=test --project=. --
|
|
|
131
131
|
> |--------|------|---------|
|
|
132
132
|
> | [name] | [file:line] | [error] |"
|
|
133
133
|
|
|
134
|
+
### 5a. TDD 报告模式(当 test-strategy=tdd 时)
|
|
135
|
+
|
|
136
|
+
在标准测试报告基础上,增加 TDD 追踪信息:
|
|
137
|
+
|
|
138
|
+
| 行为点 | RED 状态 | GREEN 状态 | 测试方法 |
|
|
139
|
+
|--------|---------|-----------|---------|
|
|
140
|
+
| [行为点1] | ✅ 曾失败 | ✅ 已通过 | [testMethodName] |
|
|
141
|
+
| [行为点2] | ✅ 曾失败 | ✅ 已通过 | [testMethodName] |
|
|
142
|
+
| ... | | | |
|
|
143
|
+
|
|
144
|
+
反模式检测:
|
|
145
|
+
- [ ] 无"测试 mock 行为而非真实行为"
|
|
146
|
+
- [ ] 无"生产类中加测试专用方法"
|
|
147
|
+
- [ ] 无"不理解依赖就 mock"
|
|
148
|
+
- [ ] 无"不完整的 mock"
|
|
149
|
+
- [ ] 无"集成测试作为事后补充"
|
|
150
|
+
|
|
134
151
|
### 6. 【交互引导】根据结果引导下一步
|
|
135
152
|
|
|
136
153
|
**全部通过**:
|