kld-sdd 2.6.4 → 2.6.6
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/lib/skills-bundle.js +5 -0
- package/package.json +1 -1
- package/templates/skills/kld-sdd/opsx-apply/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-apply/checklist.md +16 -0
- package/templates/skills/kld-sdd/opsx-archive/SKILL.md +7 -2
- package/templates/skills/kld-sdd/opsx-check/SKILL.md +4 -0
- package/templates/skills/kld-sdd/opsx-check/checklist.md +7 -0
- package/templates/skills/kld-sdd/opsx-kb-ingest/SKILL.md +190 -0
- package/templates/skills/kld-sdd/opsx-kb-ingest/reference.md +196 -0
- package/templates/skills/kld-sdd/opsx-kb-ingest/state.example.json +7 -0
- package/templates/skills/kld-sdd/opsx-ontology-query/SKILL.md +180 -0
- package/templates/skills/kld-sdd/opsx-ontology-query/reference.md +157 -0
- package/templates/skills/kld-sdd/opsx-ontology-query/state.example.json +7 -0
- package/templates/skills/kld-sdd/opsx-propose/SKILL.md +11 -7
- package/templates/skills/kld-sdd/opsx-spec/SKILL.md +7 -3
- package/templates/skills/kld-sdd/opsx-task/SKILL.md +8 -1
- package/templates/skills/kld-sdd/opsx-task/checklist.md +3 -0
- package/templates/skills/kld-sdd/opsx-tdd-anti-patterns/SKILL.md +5 -2
- package/templates/skills/kld-sdd/opsx-tdd-anti-patterns/reference.md +29 -0
- package/templates/skills/kld-sdd/opsx-tdd-core/checklist.md +4 -0
- package/templates/skills/kld-sdd/opsx-tdd-rules/SKILL.md +1 -1
- package/templates/skills/kld-sdd/opsx-tdd-rules/rules/multi-validation-split.md +35 -1
package/lib/skills-bundle.js
CHANGED
|
@@ -19,6 +19,9 @@ const OPSX_SKILL_DIRS = [
|
|
|
19
19
|
'opsx-explore',
|
|
20
20
|
'opsx-knowledge',
|
|
21
21
|
'opsx-rules',
|
|
22
|
+
// Engineering KB 依赖技能(随 init 部署;propose/spec/archive 硬依赖)
|
|
23
|
+
'opsx-ontology-query',
|
|
24
|
+
'opsx-kb-ingest',
|
|
22
25
|
];
|
|
23
26
|
|
|
24
27
|
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
@@ -97,6 +100,8 @@ const KUNLUN_SLASH_COMMANDS = [
|
|
|
97
100
|
'test',
|
|
98
101
|
'archive',
|
|
99
102
|
'explore',
|
|
103
|
+
'ontology-query',
|
|
104
|
+
'kb-ingest',
|
|
100
105
|
];
|
|
101
106
|
|
|
102
107
|
function transformKunlunSlashCommands(content) {
|
package/package.json
CHANGED
|
@@ -211,6 +211,7 @@ g. **继续下一个层级** — 重新检查 DAG,找出依赖已满足的下
|
|
|
211
211
|
> 合理化预防表见 opsx-tdd-core/SKILL.md §7
|
|
212
212
|
> REFACTOR 检查点见 opsx-tdd-rules/rules/refactor-checklist.md
|
|
213
213
|
> 异常路径覆盖门禁见 opsx-tdd-rules/rules/exception-path-coverage.md
|
|
214
|
+
> TDD 节奏校验(执行后校验)见 `./checklist.md` §5e.1
|
|
214
215
|
|
|
215
216
|
**【S2.1 RED 测试质量标准】**(test-strategy=tdd 时强制):
|
|
216
217
|
|
|
@@ -282,6 +283,7 @@ g. **继续下一个层级** — 重新检查 DAG,找出依赖已满足的下
|
|
|
282
283
|
- **⛔ 编译检查门禁**:每完成一个任务后必须运行编译检查,编译失败禁止标记已完成。
|
|
283
284
|
- **⛔ 测试执行门禁**:根据 `test-strategy` 决定(tdd=强制, impl-first=强制补跑, none=跳过);须真实执行并留 telemetry。${HOOK_GATE_DESCRIPTION}
|
|
284
285
|
- **⛔ 必须实时更新任务状态**:每完成一个任务立即改 tasks.md,两种格式同步。
|
|
286
|
+
- **⛔ apply 结束前 checkbox 全量同步校验**:`stage_end` 前对比 telemetry `task_update` 记录数与 tasks.md `[x]` 数量,不一致则补齐(见 `./checklist.md` §5f.1)。
|
|
285
287
|
- **⛔ task_update 后必须验证 checkbox 已更新**:执行 `check-task` 确认 tasks.md 对应行已变更;未更新则手动修改。
|
|
286
288
|
- **⛔ TDD RED→GREEN 严格串行**:不适用同层并行派发;RED-N 确认失败后必须执行中断声明再进入 GREEN-N;GREEN 完成后必须通过 Scope 门禁再进入下一个 RED。
|
|
287
289
|
- **Git 只读策略**:禁止为了度量自动初始化 Git、创建分支或提交 commit;非 Git 项目用 `vcs_mode=no-git` 继续执行。
|
|
@@ -298,7 +300,7 @@ g. **继续下一个层级** — 重新检查 DAG,找出依赖已满足的下
|
|
|
298
300
|
|
|
299
301
|
## 渐进披露
|
|
300
302
|
|
|
301
|
-
- Read `checklist.md` 仅在执行 apply 需要校验门禁/自检时 — 含 §1.2 Check 门禁检查点、§5d/§5e 编译/测试门禁自检、§6.0 单元测试真实执行自检、§6.1 worktree 收尾前置条件、Guardrails ⛔ 强制项勾选表。
|
|
303
|
+
- Read `checklist.md` 仅在执行 apply 需要校验门禁/自检时 — 含 §1.2 Check 门禁检查点、§5d/§5e 编译/测试门禁自检、§5e.1 TDD 节奏校验、§5f.1 checkbox 全量同步校验、§6.0 单元测试真实执行自检、§6.1 worktree 收尾前置条件、Guardrails ⛔ 强制项勾选表。
|
|
302
304
|
- Read `reference.md` 仅在需要参考详细模板时 — 含 📊 Telemetry 命令模板(start/end/task_update/ai_adoption_review/worktree_finish)、§1.5 worktree 全套策略(Step 0.1-3 + record-base + 多 cap 合并顺序)、§5c 子代理派发、§5.1 AI 产出快照、§6.0 单元测试、§6.1 worktree 收尾脚本。
|
|
303
305
|
- `implementer-prompt.md` 为子代理派发提示模板(§5c 派发时组合 tasks/design/overview 上下文使用)。
|
|
304
306
|
- `worktree-setup.md` 为 worktree 快速参考(§1.5 策略的精简版,与 reference.md §1.5 完整版并存:reference=完整策略,worktree-setup=快速参考)。
|
|
@@ -47,6 +47,11 @@ description: opsx-apply 的阶段强制检查点与自检清单。仅在执行 a
|
|
|
47
47
|
> 不在此内联复制,以 opsx-tdd-core/checklist.md §A 为唯一真相源。
|
|
48
48
|
> 额外补充:REFACTOR 任务还需执行 `opsx-tdd-rules/rules/refactor-checklist.md`(7 项重构检查点)。
|
|
49
49
|
|
|
50
|
+
⛔ **TDD 节奏校验**(RED→GREEN 严格串行的执行后校验):
|
|
51
|
+
- [ ] 连续的 RED-N `task_update` 与 GREEN-N `task_update` 之间有可验证的执行间隔(建议 >60 秒),若时间戳差距过小视为批量执行信号
|
|
52
|
+
- [ ] 每对 RED→GREEN 之间已执行 🔴 中断声明(`🔴 RED-N 确认失败,原因:XXX。现在进入 GREEN-N`)
|
|
53
|
+
- [ ] 若同层有多个 RED→GREEN 对,确认是逐对完成而非一次性编写多个 RED 再一次性实现多个 GREEN
|
|
54
|
+
|
|
50
55
|
### §5e.2 RED 测试质量门禁(仅 test-strategy=tdd 时,RED 任务完成后强制检查)
|
|
51
56
|
|
|
52
57
|
⛔ 核心原则(引用 opsx-tdd-quality/SKILL.md §2):Mock 边界,不 Mock 行为
|
|
@@ -79,6 +84,15 @@ description: opsx-apply 的阶段强制检查点与自检清单。仅在执行 a
|
|
|
79
84
|
- [ ] 记录任务级 Telemetry(`task_update`,`--task-id=<TASK-ID>` 必填,否则 E4 指标无法计算);TDD 测试骨架任务须在 `--details-json` 带 `"task_kind":"test-skeleton"`(P3,避免红灯误判拉低 E4)
|
|
80
85
|
- [ ] ⛔ **task_update 后必须验证 checkbox 已更新**:执行 `node skywalk-sdd/index.cjs check-task --project=. --change=<变更名称> --task-id=<TASK-ID>` 确认 tasks.md 中对应行已从 `- [ ]` 变为 `- [x]`;若未更新,手动修改 tasks.md 并报告
|
|
81
86
|
|
|
87
|
+
### §5f.1 apply 结束前 checkbox 全量同步校验
|
|
88
|
+
|
|
89
|
+
> ⛔ 在 `stage_end` telemetry 记录前必须执行此校验,防止任务状态滞后到 archive 阶段。
|
|
90
|
+
|
|
91
|
+
- [ ] 对比 telemetry `task_update` 记录的已完成任务数与 tasks.md 中 `[x]` 数量,不一致则补齐
|
|
92
|
+
- [ ] tasks.md 中所有 `- [ ]` / `- [x]` 与 `**状态**: [ ]` / `[x]` 两种格式已同步
|
|
93
|
+
- [ ] 手动验证清单(如有)已勾选
|
|
94
|
+
- [ ] 文档更新项(如有)已完成或显式标注推迟
|
|
95
|
+
|
|
82
96
|
---
|
|
83
97
|
|
|
84
98
|
## §6.0 单元测试真实执行自检(`test-strategy` 非 `none`)
|
|
@@ -114,8 +128,10 @@ description: opsx-apply 的阶段强制检查点与自检清单。仅在执行 a
|
|
|
114
128
|
- [ ] ⛔ **测试执行门禁**:根据 `test-strategy` 决定(tdd=强制, impl-first=强制补跑, none=跳过);须真实执行并留 telemetry,`sdd-apply-test-gate` 校验非占位数据
|
|
115
129
|
- [ ] ⛔ **RED 测试质量门禁**:见 §5e.2(引用 opsx-tdd-quality + opsx-tdd-anti-patterns,不在此内联复制)
|
|
116
130
|
- [ ] ⛔ **必须实时更新任务状态**:每完成一个任务立即改 tasks.md,两种格式(`- [ ]`→`- [x]` 与 `**状态**: [ ]`→`[x]`)同步
|
|
131
|
+
- [ ] ⛔ **apply 结束前 checkbox 全量同步校验**:见 §5f.1,`stage_end` 前对比 telemetry `task_update` 记录数与 tasks.md `[x]` 数量
|
|
117
132
|
- [ ] ⛔ **task_update 后必须验证 checkbox 已更新**:执行 `check-task` 确认 tasks.md 对应行已变更;未更新则手动修改
|
|
118
133
|
- [ ] ⛔ **TDD RED→GREEN 严格串行**:不适用同层并行派发;RED-N 确认失败后必须执行中断声明再进入 GREEN-N;GREEN 完成后必须通过 Scope 门禁再进入下一个 RED
|
|
134
|
+
- [ ] ⛔ **TDD 节奏校验**:见 §5e.1,连续 RED-N/GREEN-N 的 `task_update` 时间戳须有可验证间距
|
|
119
135
|
- [ ] **Git 只读策略**:禁止为了度量自动初始化 Git、创建分支或提交 commit;非 Git 项目用 `vcs_mode=no-git` 继续执行
|
|
120
136
|
- [ ] ⛔ **Step 0.1 隔离校验必做**:建 worktree / 建议分支名前必须完成 proposal + 跨 cap spec 依赖校验并输出报告;未通过不得按 full 并行策略拆 `kld-sdd/<change>/<cap>`
|
|
121
137
|
- [ ] **Worktree 为加速手段,非必选项**:校验通过且解耦方可多 worktree;有依赖或共享修改面则串行
|
|
@@ -3,10 +3,11 @@ name: opsx-archive
|
|
|
3
3
|
description: "归档变更技能 - 将已结束的 SDD 变更真实移入 archive,并生成最终中文度量报告"
|
|
4
4
|
argument-hint: "[change-name]"
|
|
5
5
|
license: MIT
|
|
6
|
-
compatibility: Requires skywalk-sdd/log.cjs.
|
|
6
|
+
compatibility: Requires skywalk-sdd/log.cjs; depends on opsx-kb-ingest for KB upload.
|
|
7
7
|
metadata:
|
|
8
8
|
author: sdd-team
|
|
9
9
|
version: "3.2"
|
|
10
|
+
depends-on: opsx-kb-ingest
|
|
10
11
|
allowed-tools:
|
|
11
12
|
- Bash
|
|
12
13
|
- Read
|
|
@@ -16,6 +17,8 @@ allowed-tools:
|
|
|
16
17
|
|
|
17
18
|
你是一个 SDD(Specification-Driven Development)变更归档专家。激活本技能后,你要安全地结束变更生命周期:真实归档文档、同步正式 specs、记录 archive telemetry,并生成最终中文度量报告。
|
|
18
19
|
|
|
20
|
+
> **硬依赖(收尾入库)**:zip 生成后的上传依赖同级已部署的 **`opsx-kb-ingest`**。进入 §5.5 前必须先 `Read` 该技能的 `SKILL.md` 并完成其 Session 启动。缺失则提示用户重新 `kld-sdd-init`,**不要**自造另一套入库协议。
|
|
21
|
+
|
|
19
22
|
> **跨平台执行规则**
|
|
20
23
|
> - 先确认当前终端工作目录是项目根目录;若不是,先 `cd` 到项目根目录。
|
|
21
24
|
> - Telemetry 命令默认使用 `--project=.`,兼容 Windows、macOS、Linux。
|
|
@@ -117,7 +120,9 @@ node skywalk-sdd/log.cjs archive-docs --project=. --change=<变更名称> --reas
|
|
|
117
120
|
|
|
118
121
|
### 5.5 收尾入库(opsx-kb-ingest)
|
|
119
122
|
|
|
120
|
-
|
|
123
|
+
1. 确认 `${AGENT_SKILL_DIR}/opsx-kb-ingest/SKILL.md` 存在并 Read;按该技能完成 API Key / targets。
|
|
124
|
+
2. 归档 zip 生成后,**加载并执行** **`opsx-kb-ingest`** 上传(勿只口头提示而不走技能流程);成功则写 `ingest-receipt.json`。
|
|
125
|
+
3. 若返回 `EXTERNAL_REF_CONFLICT`,引导回 spec/check 修正后重入,**禁止**在 KB 内现场改绑。
|
|
121
126
|
|
|
122
127
|
> 注意:`archive-docs` 成功执行后已经在内部写入 `stage_end`,因此**不要在成功的归档后再单独运行 `node skywalk-sdd/log.cjs end --command=archive ...`**。仅在第 5 步归档命令失败时,才需要运行下方的失败分支 `end`。
|
|
123
128
|
|
|
@@ -97,6 +97,10 @@ openspec list
|
|
|
97
97
|
- [ ] spec.md 的需求项在 design.md 中 100% 被覆盖
|
|
98
98
|
- [ ] design.md 的设计点在 tasks.md 中 100% 被拆解
|
|
99
99
|
- [ ] 跨文档引用路径正确
|
|
100
|
+
- [ ] ⛔ **CON 覆盖一致性**:spec.md 中每个 CON 在 tasks.md 中有对应验证任务或显式声明间接覆盖;tasks.md 声明"100% 覆盖 CON"时必须可追溯
|
|
101
|
+
- [ ] ⛔ **安全/审计要求覆盖一致性**:spec.md §5.x 中的安全与审计要求在 tasks.md 中有对应任务或显式声明推迟
|
|
102
|
+
- [ ] ⛔ **AC 变体覆盖一致性**:spec.md 中含"或"条件的 AC 场景,其 RED 任务验收标准须列出所有变体的测试方法(规则见 `opsx-tdd-rules/rules/multi-validation-split.md` §AC 内"或"条件变体覆盖)
|
|
103
|
+
- [ ] ⛔ **tasks.md §4.x 验证方式表内部一致性**:§4.x 验证方式表中的测试注解/配置与任务实现步骤中的声明一致
|
|
100
104
|
|
|
101
105
|
#### 4.3 算法正确性检查
|
|
102
106
|
|
|
@@ -36,6 +36,13 @@ description: "opsx-check 阶段日志自检清单 — 仅在 check 自检时读
|
|
|
36
36
|
- [ ] 完整性、一致性、算法正确性、可执行性、TDD合规性(仅test-strategy=tdd时)五维均已输出
|
|
37
37
|
- [ ] 报告问题对应修复建议(spec/design/task)
|
|
38
38
|
|
|
39
|
+
## D2. 一致性补充检查(SKILL.md §4.2 扩展)
|
|
40
|
+
|
|
41
|
+
- [ ] **CON 覆盖**:spec.md 中每个 CON 在 tasks.md 中有对应验证任务或显式声明间接覆盖
|
|
42
|
+
- [ ] **安全/审计要求覆盖**:spec.md §5.x 中的安全与审计要求在 tasks.md 中有对应任务或显式声明推迟
|
|
43
|
+
- [ ] **AC 变体覆盖**:spec.md 中含"或"条件的 AC 场景,其 RED 任务验收标准列出所有变体的测试方法(引用 `opsx-tdd-rules/rules/multi-validation-split.md`)
|
|
44
|
+
- [ ] **§4.x 验证方式表内部一致性**:tasks.md §4.x 验证方式表中的测试注解/配置与任务实现步骤中的声明一致
|
|
45
|
+
|
|
39
46
|
## E. TDD 合规性检查(仅 test-strategy=tdd 时)
|
|
40
47
|
|
|
41
48
|
⛔ 执行 `opsx-tdd-core/checklist.md` §B(11 项)逐项检查。
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: opsx-kb-ingest
|
|
3
|
+
description: >-
|
|
4
|
+
Uploads knowledge archive packages (zip) to the Engineering KB via API Key
|
|
5
|
+
(archive:ingest scope). Prompts for API key and multi-selects spaces/KBs into
|
|
6
|
+
local skill state. Supports upload, job status query, job list, and retry.
|
|
7
|
+
Use when ingesting new or updated knowledge archives into the ontology KB.
|
|
8
|
+
argument-hint: "[path-to-archive.zip]"
|
|
9
|
+
license: MIT
|
|
10
|
+
compatibility: Requires Engineering KB API (API Key with archive:ingest).
|
|
11
|
+
metadata:
|
|
12
|
+
author: sdd-team
|
|
13
|
+
version: "1.0"
|
|
14
|
+
source: "kb-sdd/skills/opsx-kb-ingest"
|
|
15
|
+
allowed-tools:
|
|
16
|
+
- Bash
|
|
17
|
+
- Read
|
|
18
|
+
- Write
|
|
19
|
+
- Edit
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# 本体知识库 · 入库
|
|
23
|
+
|
|
24
|
+
> **部署说明**:本技能随 `kld-sdd-init` 安装到项目 skills 目录。权威源在工程知识库仓 `skills/opsx-kb-ingest`;`opsx-archive` **硬依赖**本技能完成收尾入库。
|
|
25
|
+
|
|
26
|
+
只负责**入库**(zip 上传)。鉴权只用 **API Key**(`Authorization: Bearer sk_sdd_…`),**禁止**走手机号登录。
|
|
27
|
+
|
|
28
|
+
> 控制台知识库页另有浮动 Ontology Agent(会话登录 + SSE);本 Skill 仍走 API Key,二者分开。
|
|
29
|
+
|
|
30
|
+
本地状态文件(含密钥,勿提交):
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
skills/opsx-kb-ingest/.local/state.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
字段说明 → [reference.md](reference.md)。
|
|
37
|
+
|
|
38
|
+
## Session 启动(每次用本 Skill 必做)
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Task Progress:
|
|
42
|
+
- [ ] 1. 读 .local/state.json(没有则当空)
|
|
43
|
+
- [ ] 2. 无 apiKey → 向用户索取并写入 state(勿把完整 key 打进聊天摘要)
|
|
44
|
+
- [ ] 3. 无 targets 或用户要重置 → 拉空间/KB 列表,让用户多选后写入
|
|
45
|
+
- [ ] 4. 按意图执行入库操作(上传 / 查状态 / 列表 / 重试)
|
|
46
|
+
- [ ] 5. 按模板输出结果
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 1–2. API Key
|
|
50
|
+
|
|
51
|
+
若 `state.apiKey` 为空或无效(401/403):
|
|
52
|
+
|
|
53
|
+
1. 请用户提供 API Key(控制台「API 密钥」创建,至少含 `archive:ingest`)。
|
|
54
|
+
2. 可选:请用户确认 `api`(默认 `http://localhost:8090/api`)与 `tenantKey`(默认 `default`)。
|
|
55
|
+
3. 写入 `.local/state.json`(创建目录若不存在)。
|
|
56
|
+
4. 用 `GET $API/health` 探活;再用 `GET $API/v1/spaces?tenantKey=…` + Bearer 校验 key。
|
|
57
|
+
|
|
58
|
+
用户说「换密钥 / 重置 API Key」→ 清空 `apiKey`(可保留 targets),回到本步。
|
|
59
|
+
|
|
60
|
+
### 3. 选择空间与知识库(支持多选)
|
|
61
|
+
|
|
62
|
+
若 `state.targets` 为空,或用户说「重新选择 / 重置空间 / 重置知识库」:
|
|
63
|
+
|
|
64
|
+
1. `GET $API/v1/spaces?tenantKey=$TENANT_KEY`
|
|
65
|
+
2. 对每个相关 space:`GET $API/v1/spaces/{spaceId}/knowledge-bases`
|
|
66
|
+
3. 向用户展示「空间名 / spaceId → KB 名 / kbId」清单,**允许多选**。
|
|
67
|
+
4. 写入 `targets: [{ spaceId, spaceName, spaceKey, kbId, kbName }, …]`。
|
|
68
|
+
5. 仅清空 targets、保留 apiKey 即完成「重置空间和知识库」。
|
|
69
|
+
|
|
70
|
+
入库时:用户指定目标 KB(从 `targets` 中选择),仅对选中的 KB 执行上传。
|
|
71
|
+
|
|
72
|
+
### 4. 入库操作
|
|
73
|
+
|
|
74
|
+
路径前缀:`/api/v1/spaces/{spaceId}/knowledge-bases/{kbId}/ingestions`
|
|
75
|
+
所有请求:`-H "Authorization: Bearer $API_KEY"`
|
|
76
|
+
|
|
77
|
+
| 意图 | 调用 |
|
|
78
|
+
|------|------|
|
|
79
|
+
| 上传 zip 包入库 | `POST …/ingestions`(multipart,字段名 `package`) |
|
|
80
|
+
| 列出入库任务 | `GET …/ingestions` |
|
|
81
|
+
| 查看任务状态 | `GET …/ingestions/{jobId}` |
|
|
82
|
+
| 重试失败任务 | `POST …/ingestions/{jobId}/retry` |
|
|
83
|
+
|
|
84
|
+
**上传入库**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
curl -sS -X POST "$API/v1/spaces/$SPACE_ID/knowledge-bases/$KB_ID/ingestions" \
|
|
88
|
+
-H "Authorization: Bearer $API_KEY" \
|
|
89
|
+
-F "package=@/path/to/your-archive.zip;type=application/zip"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**查看任务状态**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
curl -sS -X GET "$API/v1/spaces/$SPACE_ID/knowledge-bases/$KB_ID/ingestions/$JOB_ID" \
|
|
96
|
+
-H "Authorization: Bearer $API_KEY"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**列出入库任务**
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
curl -sS -X GET "$API/v1/spaces/$SPACE_ID/knowledge-bases/$KB_ID/ingestions" \
|
|
103
|
+
-H "Authorization: Bearer $API_KEY"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**重试失败任务**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
curl -sS -X POST "$API/v1/spaces/$SPACE_ID/knowledge-bases/$KB_ID/ingestions/$JOB_ID/retry" \
|
|
110
|
+
-H "Authorization: Bearer $API_KEY"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Archive Package 要求
|
|
114
|
+
|
|
115
|
+
上传的 zip 包必须满足以下条件(否则入库会失败):
|
|
116
|
+
|
|
117
|
+
- 包含三个必需 JSON 文件:`archive-manifest.json`、`canonical-facts.json`、`conversion-report.json`
|
|
118
|
+
- `canonical-facts.json` 支持 `kld-sdd-canonical-facts/v1` 与 **`v2`**(v2 可选实体级 `external_refs`)
|
|
119
|
+
- 所有文件需通过 SHA-256 校验(manifest 中记录每个文件的 `content_hash`)
|
|
120
|
+
- 允许的文件类型:`.md`、`.json`、`.jsonl`、`.yaml`、`.yml`
|
|
121
|
+
- 大小限制:包 ≤ 50MB,条目 ≤ 2000 个,单文件 ≤ 10MB,解压后 ≤ 200MB
|
|
122
|
+
- `archive-manifest.json` 中的 `project_id` 必须与目标 Space 的 `spaceKey` 一致
|
|
123
|
+
|
|
124
|
+
**v2 本地预检(skill 侧,上传前)**
|
|
125
|
+
|
|
126
|
+
- `external_refs[]` 每项含 `system` / `object_type` / `external_id`
|
|
127
|
+
- object_type 与实体类型匹配:`requirement`/`feature`→Capability;`scenario`→SpecificationStatement|AcceptanceCriterion
|
|
128
|
+
- 包内无重复 `(external key, entity_id)` 绑定对
|
|
129
|
+
- `project_id` / `spaceKey` 既有规则保留
|
|
130
|
+
|
|
131
|
+
详细字段说明 → [reference.md](reference.md)。
|
|
132
|
+
|
|
133
|
+
### 5. 输出模板
|
|
134
|
+
|
|
135
|
+
```markdown
|
|
136
|
+
### 入库结果
|
|
137
|
+
- 目标 KB:{spaceName}/{kbName}
|
|
138
|
+
- 操作:{上传 | 查状态 | 列表 | 重试}
|
|
139
|
+
- 状态:{succeeded | failed | running | idempotent}
|
|
140
|
+
- Job ID:{jobId}
|
|
141
|
+
|
|
142
|
+
### 详情
|
|
143
|
+
- archiveId:{archiveId}
|
|
144
|
+
- contentHash:{contentHash}
|
|
145
|
+
- stage:{stage}
|
|
146
|
+
- relationStatus:{relationStatus}
|
|
147
|
+
- projectionStatus:{projectionStatus}
|
|
148
|
+
- 外部引用写入数:{externalRefsWritten 或 0}
|
|
149
|
+
- 幂等命中:{是 / 否}
|
|
150
|
+
- 错误信息:{errorCode — errorMessage 或 无}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
成功时展示 `report.externalRefsWritten`。冲突**不**出现在成功模板。
|
|
154
|
+
|
|
155
|
+
若 `errorCode=EXTERNAL_REF_CONFLICT`(整包已回滚):
|
|
156
|
+
|
|
157
|
+
1. 展示 `report.details`(externalRef / anchor / existingEntityId / incomingEntityId)。
|
|
158
|
+
2. 向用户给出两个修正选项:
|
|
159
|
+
- **复用历史身份**:回到 kld-sdd,复用 KB 中原有 entity_id / current version,重新 check → 归档 → 入库
|
|
160
|
+
- **改为新锚点**:回到 kld-sdd,分配新锚点与新 entity_id,重新 check → 归档 → 入库
|
|
161
|
+
3. **禁止**在 KB 内现场改绑或解绑。
|
|
162
|
+
|
|
163
|
+
**硬规则**
|
|
164
|
+
|
|
165
|
+
- 无 `apiKey` 不得猜密钥、不得改走 login。
|
|
166
|
+
- 无 `targets` 不得臆造 spaceId/kbId。
|
|
167
|
+
- 上传前确认 zip 包路径存在且为有效 zip 文件。
|
|
168
|
+
- 入库失败时展示 `errorCode` 和 `errorMessage`,不编造原因。
|
|
169
|
+
- 完整 apiKey 只写 state 文件;聊天里最多显示前缀(如 `sk_sdd_****`)。
|
|
170
|
+
- 401/403 时清掉 `apiKey`,请用户重贴;勿循环重试。
|
|
171
|
+
|
|
172
|
+
## 用户口令
|
|
173
|
+
|
|
174
|
+
| 用户说 | Agent 做 |
|
|
175
|
+
|--------|----------|
|
|
176
|
+
| (首次使用) | 要 key → 选 KB(多选)→ 再操作 |
|
|
177
|
+
| 换密钥 / 重置 API Key | 清 apiKey,重走第 2 步 |
|
|
178
|
+
| 重新选择 / 重置空间或知识库 | 清 targets,重走第 3 步 |
|
|
179
|
+
| 上传 / 入库 | 用当前 targets 中选中的 KB 上传 zip |
|
|
180
|
+
| 查状态 / 看任务 | 用 jobId 查询任务状态 |
|
|
181
|
+
| 列任务 / 看历史 | 列出最近入库任务 |
|
|
182
|
+
| 重试 | 对失败的 jobId 执行重试 |
|
|
183
|
+
|
|
184
|
+
## 心智模型(简述)
|
|
185
|
+
|
|
186
|
+
- 入库是同步操作:上传后后端立即解析 zip、校验、写入数据库,返回最终 job 状态。
|
|
187
|
+
- 幂等机制:同一 `archive_id` + `content_hash` 重复上传会命中幂等,不重复写入。
|
|
188
|
+
- `archive_id` 不可变:同一 `archive_id` 上传不同 `content_hash` 会被拒绝(`ARCHIVE_IMMUTABILITY_VIOLATION`)。
|
|
189
|
+
- `project_id` 必须匹配:zip 包 manifest 中的 `project_id` 必须等于目标 Space 的 `spaceKey`。
|
|
190
|
+
- 细节与 state schema → [reference.md](reference.md)。
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# 本体入库 · 参考
|
|
2
|
+
|
|
3
|
+
需要鉴权细节、state 字段或 Archive Package 规格时再读。
|
|
4
|
+
|
|
5
|
+
## `.local/state.json`
|
|
6
|
+
|
|
7
|
+
路径:`skills/opsx-kb-ingest/.local/state.json`(已 gitignore)。
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"api": "http://localhost:8090/api",
|
|
12
|
+
"tenantKey": "default",
|
|
13
|
+
"apiKey": "sk_sdd_…",
|
|
14
|
+
"updatedAt": "2026-07-19T12:00:00Z",
|
|
15
|
+
"targets": [
|
|
16
|
+
{
|
|
17
|
+
"spaceId": "uuid",
|
|
18
|
+
"spaceKey": "demo",
|
|
19
|
+
"spaceName": "演示空间",
|
|
20
|
+
"kbId": "uuid",
|
|
21
|
+
"kbName": "默认知识库"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
| 字段 | 必填 | 说明 |
|
|
28
|
+
|------|------|------|
|
|
29
|
+
| `api` | 是 | API 根,含 `/api` |
|
|
30
|
+
| `tenantKey` | 是 | 列空间用;默认 `default` |
|
|
31
|
+
| `apiKey` | 是 | 控制台创建的 `sk_sdd_…`,scope 至少 `archive:ingest` |
|
|
32
|
+
| `targets` | 操作前必填 | 多选;可为空仅当尚未完成选择 |
|
|
33
|
+
| `updatedAt` | 建议 | ISO-8601 |
|
|
34
|
+
|
|
35
|
+
示例(无密钥)见 [state.example.json](state.example.json)。
|
|
36
|
+
|
|
37
|
+
## 鉴权
|
|
38
|
+
|
|
39
|
+
```http
|
|
40
|
+
Authorization: Bearer sk_sdd_…
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- **不要** `POST /auth/login`。
|
|
44
|
+
- Key 在控制台「API 密钥」创建;创建时勾选 **入库 / archive:ingest**(写入需要)。
|
|
45
|
+
- 401/403:清掉 state 里的 `apiKey`,请用户重贴;勿循环重试。
|
|
46
|
+
|
|
47
|
+
探活与校验:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
curl -sf "$API/health"
|
|
51
|
+
curl -sS -H "Authorization: Bearer $API_KEY" \
|
|
52
|
+
"$API/v1/spaces?tenantKey=$TENANT_KEY"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 列表接口(选择用)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# 空间
|
|
59
|
+
GET $API/v1/spaces?tenantKey=$TENANT_KEY
|
|
60
|
+
|
|
61
|
+
# 某空间下 KB
|
|
62
|
+
GET $API/v1/spaces/{spaceId}/knowledge-bases
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
API Key 一般为租户范围;`apiKeySpaceId` 为空时可列出租户下多空间,便于多选。
|
|
66
|
+
|
|
67
|
+
## 入库接口
|
|
68
|
+
|
|
69
|
+
路径前缀:`/api/v1/spaces/{spaceId}/knowledge-bases/{kbId}/ingestions`
|
|
70
|
+
|
|
71
|
+
### 上传 zip 包
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
POST {base}/ingestions
|
|
75
|
+
Content-Type: multipart/form-data
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
curl -sS -X POST "$API/v1/spaces/$SPACE_ID/knowledge-bases/$KB_ID/ingestions" \
|
|
80
|
+
-H "Authorization: Bearer $API_KEY" \
|
|
81
|
+
-F "package=@/path/to/archive.zip;type=application/zip"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 列出入库任务
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
GET {base}/ingestions
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
返回最近 100 条入库任务,按 `created_at DESC` 排序。
|
|
91
|
+
|
|
92
|
+
### 查看任务状态
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
GET {base}/ingestions/{jobId}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 重试失败任务
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
POST {base}/ingestions/{jobId}/retry
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
仅 `status=failed` 的任务可重试;后端会重新解析原始上传的 zip 包。
|
|
105
|
+
|
|
106
|
+
## IngestionJobDto 响应字段
|
|
107
|
+
|
|
108
|
+
| 字段 | 类型 | 说明 |
|
|
109
|
+
|------|------|------|
|
|
110
|
+
| `jobId` | UUID | 任务 ID |
|
|
111
|
+
| `spaceId` | UUID | 空间 ID |
|
|
112
|
+
| `archiveId` | String | 归档 ID(来自 manifest) |
|
|
113
|
+
| `contentHash` | String | 内容哈希 `sha256:…` |
|
|
114
|
+
| `packageName` | String | 上传的文件名 |
|
|
115
|
+
| `packageHash` | String | 包哈希 `sha256:…` |
|
|
116
|
+
| `status` | String | `running` / `succeeded` / `failed` |
|
|
117
|
+
| `stage` | String | `validating` / `canonical-store` / `committed` / `failed` |
|
|
118
|
+
| `idempotentHit` | boolean | 是否命中幂等(同 archive_id + content_hash) |
|
|
119
|
+
| `relationStatus` | String | `pending` / `committed` / `rolled_back` / `not_required` |
|
|
120
|
+
| `projectionStatus` | String | `pending` / `not_started` / … |
|
|
121
|
+
| `errorCode` | String | 失败错误码(见下表) |
|
|
122
|
+
| `errorMessage` | String | 失败错误描述 |
|
|
123
|
+
| `report` | JsonNode | 入库报告(成功含 `externalRefsWritten`;冲突失败含 `details`) |
|
|
124
|
+
| `attempts` | int | 尝试次数 |
|
|
125
|
+
| `createdBy` | String | 创建者标识 |
|
|
126
|
+
| `createdAt` | Instant | 创建时间 |
|
|
127
|
+
| `updatedAt` | Instant | 更新时间 |
|
|
128
|
+
| `finishedAt` | Instant | 完成时间 |
|
|
129
|
+
|
|
130
|
+
## 常见错误码
|
|
131
|
+
|
|
132
|
+
| errorCode | 含义 |
|
|
133
|
+
|-----------|------|
|
|
134
|
+
| `INGEST_FAILED` | 通用入库失败 |
|
|
135
|
+
| `PROJECT_SPACE_MISMATCH` | manifest 中 project_id 与目标 Space spaceKey 不一致 |
|
|
136
|
+
| `ARCHIVE_IMMUTABILITY_VIOLATION` | 同一 archive_id 已存在不同 content_hash |
|
|
137
|
+
| `MANIFEST_MISSING` | 缺少必需的 manifest 文件 |
|
|
138
|
+
| `INVALID_FILE_TYPE` | 包含不允许的文件类型 |
|
|
139
|
+
| `SIZE_LIMIT_EXCEEDED` | 超过包/文件/条目大小限制 |
|
|
140
|
+
| `HASH_MISMATCH` | 文件 SHA-256 校验不通过 |
|
|
141
|
+
| `EXTERNAL_REF_CONFLICT` | 同外部键+同锚点已绑不同 entity_id;整包回滚;见 `report.details` |
|
|
142
|
+
| `EXTERNAL_REFERENCE_TYPE_MISMATCH` | 包内 object_type 与实体类型不匹配 |
|
|
143
|
+
| `EXTERNAL_REFERENCE_DUPLICATE_IN_PACKAGE` | 包内重复 `(external key, entity_id)` |
|
|
144
|
+
| `FACTS_SCHEMA_UNSUPPORTED` | canonical-facts schema 非 v1/v2 |
|
|
145
|
+
|
|
146
|
+
### `EXTERNAL_REF_CONFLICT` 的 report.details
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"externalRef": { "system": "requirement-mgmt", "objectType": "requirement", "externalId": "REQ-…" },
|
|
151
|
+
"anchor": "CAP-ORDER-CANCEL",
|
|
152
|
+
"existingEntityId": "<uuid>",
|
|
153
|
+
"existingCurrentVersionId": "<uuid>",
|
|
154
|
+
"incomingEntityId": "<uuid>",
|
|
155
|
+
"remediation": ["reuse-existing-identity", "assign-new-anchor"]
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
修正必须回到 kld-sdd(复用历史身份或换新锚点),重新 check → 归档 → 入库;禁止在 KB 改绑。
|
|
160
|
+
|
|
161
|
+
## Archive Package 规格
|
|
162
|
+
|
|
163
|
+
### 必需文件
|
|
164
|
+
|
|
165
|
+
| 文件 | 说明 |
|
|
166
|
+
|------|------|
|
|
167
|
+
| `archive-manifest.json` | 归档清单,含 archive_id、project_id、content_hash、files 列表 |
|
|
168
|
+
| `canonical-facts.json` | 规范化事实:`kld-sdd-canonical-facts/v1` 或 **`v2`**(v2 可选实体级 `external_refs`) |
|
|
169
|
+
| `conversion-report.json` | 转换报告(`target_schema` 可为 v1 或 v2) |
|
|
170
|
+
|
|
171
|
+
### 文件类型白名单
|
|
172
|
+
|
|
173
|
+
`.md`、`.json`、`.jsonl`、`.yaml`、`.yml`
|
|
174
|
+
|
|
175
|
+
### 大小限制
|
|
176
|
+
|
|
177
|
+
| 限制项 | 默认值 |
|
|
178
|
+
|--------|--------|
|
|
179
|
+
| 包大小 | 50 MB |
|
|
180
|
+
| 条目数 | 2000 |
|
|
181
|
+
| 单文件大小 | 10 MB |
|
|
182
|
+
| 解压后总大小 | 200 MB |
|
|
183
|
+
|
|
184
|
+
### manifest 关键字段
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"archive_id": "2026-07-18-user-center",
|
|
189
|
+
"project_id": "<必须与目标 Space spaceKey 一致>",
|
|
190
|
+
"content_hash": "sha256:<canonical-facts.json 的哈希>",
|
|
191
|
+
"files": [
|
|
192
|
+
{ "path": "canonical-facts.json", "content_hash": "sha256:…" },
|
|
193
|
+
{ "path": "conversion-report.json", "content_hash": "sha256:…" }
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
```
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: opsx-ontology-query
|
|
3
|
+
description: >-
|
|
4
|
+
Queries the Engineering KB ontology via API Key (context search, match-requirement,
|
|
5
|
+
entity/impact/ontology-view). Prompts for API key and multi-selects spaces/KBs into
|
|
6
|
+
local skill state. Use when looking up Spec/design facts, Spec reuse, impact, or
|
|
7
|
+
citation-backed answers from the ontology KB.
|
|
8
|
+
argument-hint: "[query or continuity intent]"
|
|
9
|
+
license: MIT
|
|
10
|
+
compatibility: Requires Engineering KB API (API Key with context:read).
|
|
11
|
+
metadata:
|
|
12
|
+
author: sdd-team
|
|
13
|
+
version: "1.0"
|
|
14
|
+
source: "kb-sdd/skills/opsx-ontology-query"
|
|
15
|
+
allowed-tools:
|
|
16
|
+
- Bash
|
|
17
|
+
- Read
|
|
18
|
+
- Write
|
|
19
|
+
- Edit
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# 本体知识库 · 查询
|
|
23
|
+
|
|
24
|
+
> **部署说明**:本技能随 `kld-sdd-init` 安装到项目 skills 目录。权威源在工程知识库仓 `skills/opsx-ontology-query`;`opsx-propose` / `opsx-spec` 等流程技能**硬依赖**本技能,缺失时不得用本地 archive 兜底。
|
|
25
|
+
|
|
26
|
+
只负责**查**。鉴权只用 **API Key**(`Authorization: Bearer sk_sdd_…`),**禁止**走手机号登录。
|
|
27
|
+
|
|
28
|
+
> 控制台知识库页另有浮动 Ontology Agent(会话登录 + SSE);本 Skill 仍走 API Key,二者分开。
|
|
29
|
+
>
|
|
30
|
+
> **Agent 角色(V1)**:控制台 Agent 是 **单一 ReActAgent + 角色人格切换**(架构师 / 业务分析师 / 数据分析师),
|
|
31
|
+
> 不是三个独立 JVM agent。共享工具集,仅 sysPrompt 与工具偏好不同——Studio 仍单 run、延迟更低,后续需要再拆。
|
|
32
|
+
> 交互硬规则:自然语言优先,不向用户索要 UUID;多实体时用 `ask_user` Generative UI 卡片(`type=choice`,options.label=名称)。
|
|
33
|
+
>
|
|
34
|
+
> **Skills 激活**:控制台 Agent 通过 AgentScope `FileSystemSkillRepository`(`skillsRoot`,见
|
|
35
|
+
> `classpath:agent/agent.yml`)挂载本目录;运行时用内置工具 `load_skill_through_path`
|
|
36
|
+
> (skillId=`opsx-ontology-query`,path=`SKILL.md` / `reference.md`)按需加载,不把全文塞进 system prompt。
|
|
37
|
+
>
|
|
38
|
+
> **记忆**:会话短期用 AgentScope `InMemoryAgentStateStore`;本体事实仍走 KB(pgvector/SQL)。
|
|
39
|
+
> **不需要 mem0**,除非以后要跨会话个人偏好记忆。
|
|
40
|
+
|
|
41
|
+
本地状态文件(含密钥,勿提交):
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
skills/opsx-ontology-query/.local/state.json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
字段说明 → [reference.md](reference.md)。
|
|
48
|
+
|
|
49
|
+
## Session 启动(每次用本 Skill 必做)
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
Task Progress:
|
|
53
|
+
- [ ] 1. 读 .local/state.json(没有则当空)
|
|
54
|
+
- [ ] 2. 无 apiKey → 向用户索取并写入 state(勿把完整 key 打进聊天摘要)
|
|
55
|
+
- [ ] 3. 无 targets 或用户要重置 → 拉空间/KB 列表,让用户多选后写入
|
|
56
|
+
- [ ] 4. 按意图查询(可对多个 KB 逐个查询)
|
|
57
|
+
- [ ] 5. 按模板输出;无命中不编造
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 1–2. API Key
|
|
61
|
+
|
|
62
|
+
若 `state.apiKey` 为空或无效(401/403):
|
|
63
|
+
|
|
64
|
+
1. 请用户提供 API Key(控制台「API 密钥」创建,至少含 `context:read`)。
|
|
65
|
+
2. 可选:请用户确认 `api`(默认 `http://localhost:8090/api`)与 `tenantKey`(默认 `default`)。
|
|
66
|
+
3. 写入 `.local/state.json`(创建目录若不存在)。
|
|
67
|
+
4. 用 `GET $API/health` 探活;再用 `GET $API/v1/spaces?tenantKey=…` + Bearer 校验 key。
|
|
68
|
+
|
|
69
|
+
用户说「换密钥 / 重置 API Key」→ 清空 `apiKey`(可保留 targets),回到本步。
|
|
70
|
+
|
|
71
|
+
### 3. 选择空间与知识库(支持多选)
|
|
72
|
+
|
|
73
|
+
若 `state.targets` 为空,或用户说「重新选择 / 重置空间 / 重置知识库」:
|
|
74
|
+
|
|
75
|
+
1. `GET $API/v1/spaces?tenantKey=$TENANT_KEY`
|
|
76
|
+
2. 对每个相关 space:`GET $API/v1/spaces/{spaceId}/knowledge-bases`
|
|
77
|
+
3. 向用户展示「空间名 / spaceId → KB 名 / kbId」清单,**允许多选**。
|
|
78
|
+
4. 写入 `targets: [{ spaceId, spaceName, spaceKey, kbId, kbName }, …]`。
|
|
79
|
+
5. 仅清空 targets、保留 apiKey 即完成「重置空间和知识库」。
|
|
80
|
+
|
|
81
|
+
查询时:对 `targets` **逐个**调用同一查询,结果按 KB 分组展示。用户若指定「只用某某 KB」,则仅查对应子集。
|
|
82
|
+
|
|
83
|
+
### 4. 查询
|
|
84
|
+
|
|
85
|
+
路径前缀:`/api/v1/spaces/{spaceId}/knowledge-bases/{kbId}`
|
|
86
|
+
所有请求:`-H "Authorization: Bearer $API_KEY"`
|
|
87
|
+
|
|
88
|
+
| 意图 | 调用 |
|
|
89
|
+
|------|------|
|
|
90
|
+
| 开放问题 / 相似事实 | `POST …/context/search` |
|
|
91
|
+
| Continuity / 按外部需求号定位身份 | `POST …/entities/resolve`(带 `externalSystem` / `externalObjectType` / `externalId`;可选 `entityType`) |
|
|
92
|
+
| Spec 复用 / 转换 | `POST …/context/match-requirement`(可带外部三元组与/或 `entityId`) |
|
|
93
|
+
| 对象详情 | `GET …/entities/{id}/current-version` |
|
|
94
|
+
| 一跳结构 | `GET …/entities/{id}/ontology-view` |
|
|
95
|
+
| 多跳影响 | `GET …/entities/{id}/impact` |
|
|
96
|
+
| 原文 | `POST …/context/disclosures`(见 reference) |
|
|
97
|
+
|
|
98
|
+
**机器意图(SDD 流程 Agent)**
|
|
99
|
+
|
|
100
|
+
- Continuity(只要身份、不要 reuseBundles)→ 优先 `POST …/entities/resolve`
|
|
101
|
+
- Spec 复用 → `POST …/context/match-requirement`,带 external 与/或 `entityId`
|
|
102
|
+
- **禁止**扫描消费方本地 `archive/` 目录当跨迭代继承源;历史有效规格以 KB current 为准
|
|
103
|
+
|
|
104
|
+
**search**
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
curl -sS -X POST "$API/v1/spaces/$SPACE_ID/knowledge-bases/$KB_ID/context/search" \
|
|
108
|
+
-H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
|
|
109
|
+
-d '{"query":"用户登录与会话","entityTypes":[],"limit":15}'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**entities/resolve(外部需求号)**
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
curl -sS -X POST "$API/v1/spaces/$SPACE_ID/knowledge-bases/$KB_ID/entities/resolve" \
|
|
116
|
+
-H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
|
|
117
|
+
-d '{
|
|
118
|
+
"externalSystem":"requirement-mgmt",
|
|
119
|
+
"externalObjectType":"requirement",
|
|
120
|
+
"externalId":"REQ-FI-2024-001",
|
|
121
|
+
"entityType":"Capability"
|
|
122
|
+
}'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
命中时关注:`resolution=LINK_EXISTING` 且 `inheritanceAllowed=true`(可继承 n);`removedBindingCount`(已失效绑定 m);`matchType=HISTORICAL_ONLY` 表示仅有失效绑定,不可继承。
|
|
126
|
+
|
|
127
|
+
**match-requirement**
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
curl -sS -X POST "$API/v1/spaces/$SPACE_ID/knowledge-bases/$KB_ID/context/match-requirement" \
|
|
131
|
+
-H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
|
|
132
|
+
-d '{
|
|
133
|
+
"query":"用户登录与会话",
|
|
134
|
+
"targetStage":"spec",
|
|
135
|
+
"entityId":"<capability-entity-uuid>",
|
|
136
|
+
"externalSystem":"requirement-mgmt",
|
|
137
|
+
"externalObjectType":"requirement",
|
|
138
|
+
"externalId":"REQ-FI-2024-001"
|
|
139
|
+
}'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
检索通道:精确/结构 + 全文 + 向量(就绪时)→ RRF →(可选)图谱扩展。看 `degraded` / `degradationReasons`。
|
|
143
|
+
|
|
144
|
+
### 5. 输出模板
|
|
145
|
+
|
|
146
|
+
```markdown
|
|
147
|
+
### 本体查询结论
|
|
148
|
+
- 目标 KB:{spaceName}/{kbName}(可多行)
|
|
149
|
+
- 意图:{复用 | 事实检索 | 影响}
|
|
150
|
+
- 可信度:{高 | 中(降级) | 无命中}
|
|
151
|
+
- 降级:{reasons 或 无}
|
|
152
|
+
|
|
153
|
+
### 命中
|
|
154
|
+
1. **{displayName}**({entityType})@ {kbName}
|
|
155
|
+
- id / version / matchType / externalRefs …
|
|
156
|
+
- 若外部键命中:可继承 n / 已失效绑定 m
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**硬规则**
|
|
160
|
+
|
|
161
|
+
- 无 `apiKey` 不得猜密钥、不得改走 login。
|
|
162
|
+
- 无 `targets` 不得臆造 spaceId/kbId。
|
|
163
|
+
- 无命中 → 写明「无当前依据」,禁止编造条款。
|
|
164
|
+
- 完整 apiKey 只写 state 文件;聊天里最多显示前缀(如 `sk_sdd_****`)。
|
|
165
|
+
|
|
166
|
+
## 用户口令
|
|
167
|
+
|
|
168
|
+
| 用户说 | Agent 做 |
|
|
169
|
+
|--------|----------|
|
|
170
|
+
| (首次使用) | 要 key → 选 KB(多选)→ 再查 |
|
|
171
|
+
| 换密钥 / 重置 API Key | 清 apiKey,重走第 2 步 |
|
|
172
|
+
| 重新选择 / 重置空间或知识库 | 清 targets,重走第 3 步 |
|
|
173
|
+
| 查 / Spec 复用 / 影响… | 用当前 targets 查询 |
|
|
174
|
+
|
|
175
|
+
## 心智模型(简述)
|
|
176
|
+
|
|
177
|
+
- 本体真相在 PG(entity + relation);控制台地图/对象用 SQL 遍历。
|
|
178
|
+
- **外部需求号是确定性身份**;自然语言只产生 REFERENCE 候选,不能自动 sameAs。
|
|
179
|
+
- `context/search` 才是语义检索主通道(+ 可选 AGE 扩邻);跨迭代 Continuity 走 `entities/resolve`。
|
|
180
|
+
- 细节与 state schema → [reference.md](reference.md)。
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# 本体查询 · 参考
|
|
2
|
+
|
|
3
|
+
需要鉴权细节、state 字段或响应字段时再读。
|
|
4
|
+
|
|
5
|
+
## `.local/state.json`
|
|
6
|
+
|
|
7
|
+
路径:`skills/opsx-ontology-query/.local/state.json`(已 gitignore)。
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"api": "http://localhost:8090/api",
|
|
12
|
+
"tenantKey": "default",
|
|
13
|
+
"apiKey": "sk_sdd_…",
|
|
14
|
+
"updatedAt": "2026-07-19T12:00:00Z",
|
|
15
|
+
"targets": [
|
|
16
|
+
{
|
|
17
|
+
"spaceId": "uuid",
|
|
18
|
+
"spaceKey": "demo",
|
|
19
|
+
"spaceName": "演示空间",
|
|
20
|
+
"kbId": "uuid",
|
|
21
|
+
"kbName": "默认知识库"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
| 字段 | 必填 | 说明 |
|
|
28
|
+
|------|------|------|
|
|
29
|
+
| `api` | 是 | API 根,含 `/api` |
|
|
30
|
+
| `tenantKey` | 是 | 列空间用;默认 `default` |
|
|
31
|
+
| `apiKey` | 是 | 控制台创建的 `sk_sdd_…`,scope 至少 `context:read` |
|
|
32
|
+
| `targets` | 查询前必填 | 多选;可为空仅当尚未完成选择 |
|
|
33
|
+
| `updatedAt` | 建议 | ISO-8601 |
|
|
34
|
+
|
|
35
|
+
示例(无密钥)见 [state.example.json](state.example.json)。
|
|
36
|
+
|
|
37
|
+
## 鉴权
|
|
38
|
+
|
|
39
|
+
```http
|
|
40
|
+
Authorization: Bearer sk_sdd_…
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- **不要** `POST /auth/login`。
|
|
44
|
+
- Key 在控制台「API 密钥」创建;创建时勾选 **读取上下文 / context:read**(查询够用)。
|
|
45
|
+
- 401/403:清掉 state 里的 `apiKey`,请用户重贴;勿循环重试。
|
|
46
|
+
|
|
47
|
+
探活与校验:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
curl -sf "$API/health"
|
|
51
|
+
curl -sS -H "Authorization: Bearer $API_KEY" \
|
|
52
|
+
"$API/v1/spaces?tenantKey=$TENANT_KEY"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 列表接口(选择用)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# 空间
|
|
59
|
+
GET $API/v1/spaces?tenantKey=$TENANT_KEY
|
|
60
|
+
|
|
61
|
+
# 某空间下 KB
|
|
62
|
+
GET $API/v1/spaces/{spaceId}/knowledge-bases
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
API Key 一般为租户范围;`apiKeySpaceId` 为空时可列出租户下多空间,便于多选。
|
|
66
|
+
|
|
67
|
+
## context/search
|
|
68
|
+
|
|
69
|
+
`POST {base}/context/search`
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{ "query": "string", "entityTypes": [], "limit": 15 }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
| 字段 | 含义 |
|
|
76
|
+
|------|------|
|
|
77
|
+
| `degraded` / `degradationReasons` | 向量/AGE/rerank 等降级 |
|
|
78
|
+
| `results[].matchType` | exact / structural / fulltext / vector / graph … |
|
|
79
|
+
| `results[].entityId` / `entityVersionId` | 溯源 |
|
|
80
|
+
| `results[].scoreExplanation` | RRF channel ranks 等 |
|
|
81
|
+
|
|
82
|
+
## entities/resolve(Continuity / 外部需求号)
|
|
83
|
+
|
|
84
|
+
`POST {base}/entities/resolve`
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"externalSystem": "requirement-mgmt",
|
|
89
|
+
"externalObjectType": "requirement",
|
|
90
|
+
"externalId": "REQ-FI-2024-001",
|
|
91
|
+
"entityType": "Capability"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
也可传 `entityId` / `previousVersionId` / `canonicalKey` / `query`。
|
|
96
|
+
|
|
97
|
+
| 结果 | 含义 |
|
|
98
|
+
|------|------|
|
|
99
|
+
| `resolution=LINK_EXISTING` + `inheritanceAllowed=true` | ≥1 可继承绑定;`candidates` 仅存活实体;`removedBindingCount` 为失效绑定数 |
|
|
100
|
+
| `matchType=HISTORICAL_ONLY` | 有绑定但全部无 current / removed;`inheritanceAllowed=false`,不得当迭代继承 |
|
|
101
|
+
| `NEEDS_CONFIRM` / `SIMILAR_REQUIREMENT` | 名称/结构相似,仅候选 |
|
|
102
|
+
| `NEW_REQUIREMENT` | 无命中 |
|
|
103
|
+
|
|
104
|
+
**禁止**用本地 `archive/` 目录当跨迭代继承源。
|
|
105
|
+
|
|
106
|
+
## context/match-requirement
|
|
107
|
+
|
|
108
|
+
`POST {base}/context/match-requirement`
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"query": "string",
|
|
113
|
+
"targetStage": "spec",
|
|
114
|
+
"limit": 20,
|
|
115
|
+
"entityId": "<uuid>",
|
|
116
|
+
"externalSystem": "requirement-mgmt",
|
|
117
|
+
"externalObjectType": "requirement",
|
|
118
|
+
"externalId": "REQ-…"
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`entityId` / `previousVersionId` / 外部三元组齐全时走 resolve;仅当可继承(非 `HISTORICAL_ONLY`)时组装 `reuseMode=INHERIT` bundles。实体与 statement/AC 上可带 `externalRefs`。
|
|
123
|
+
|
|
124
|
+
| matchType | 含义 |
|
|
125
|
+
|-----------|------|
|
|
126
|
+
| `SAME_ITERATION` | 已对齐同一实体 |
|
|
127
|
+
| `HISTORICAL_ONLY` | 外部键仅有失效绑定,不可继承 |
|
|
128
|
+
| `SIMILAR_REQUIREMENT` | 可作复用候选 |
|
|
129
|
+
| `NEEDS_CONFIRM` | 需人确认 |
|
|
130
|
+
| `NEW_REQUIREMENT` | 无可信复用 |
|
|
131
|
+
|
|
132
|
+
## 对象读
|
|
133
|
+
|
|
134
|
+
| 方法 | 路径 |
|
|
135
|
+
|------|------|
|
|
136
|
+
| GET | `/entities?type=&q=&page=&size=` |
|
|
137
|
+
| GET | `/entities/{id}/current-version` |
|
|
138
|
+
| GET | `/entities/{id}/lineage` |
|
|
139
|
+
| GET | `/entities/{id}/ontology-view` |
|
|
140
|
+
| GET | `/entities/{id}/impact` |
|
|
141
|
+
|
|
142
|
+
`impact` / `ontology-view` 走 PG 关系;与 `context/search` 不同链路。
|
|
143
|
+
|
|
144
|
+
## disclosures
|
|
145
|
+
|
|
146
|
+
`POST {base}/context/disclosures`
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"anchorId": "STMT-…",
|
|
151
|
+
"entityId": null,
|
|
152
|
+
"entityVersionId": null,
|
|
153
|
+
"level": "preview"
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`level`:`preview` | `section` | `document`。
|
|
@@ -3,10 +3,11 @@ name: opsx-propose
|
|
|
3
3
|
description: "业务意图文档技能 - 引导创建 proposal.md,定义变更的 Why 和上下文总览"
|
|
4
4
|
argument-hint: "[change-name] [上下文文件...]"
|
|
5
5
|
license: MIT
|
|
6
|
-
compatibility: Requires openspec CLI.
|
|
6
|
+
compatibility: Requires openspec CLI; depends on opsx-ontology-query.
|
|
7
7
|
metadata:
|
|
8
8
|
author: sdd-team
|
|
9
9
|
version: "3.0"
|
|
10
|
+
depends-on: opsx-ontology-query
|
|
10
11
|
allowed-tools:
|
|
11
12
|
- Bash
|
|
12
13
|
- Read
|
|
@@ -16,6 +17,8 @@ allowed-tools:
|
|
|
16
17
|
|
|
17
18
|
你是一个 SDD(Specification-Driven Development)业务意图文档专家。激活本技能后,你将引导用户创建符合质量红线标准的 **proposal.md** 文档。
|
|
18
19
|
|
|
20
|
+
> **硬依赖**:本技能 Continuity 步骤依赖同级已部署的 **`opsx-ontology-query`**。启动 Continuity 前必须先 `Read` 该技能的 `SKILL.md`,并按其中流程准备 `.local/state.json`(API Key + targets)。若项目 skills 目录中不存在 `opsx-ontology-query/`,停止 Continuity,提示用户重新执行 `kld-sdd-init`;**禁止**用本地 `archive/` 冒充查询。
|
|
21
|
+
|
|
19
22
|
> **⚠️ 阶段边界约束**
|
|
20
23
|
>
|
|
21
24
|
> 当前处于 **Propose(规划)阶段**:
|
|
@@ -164,7 +167,8 @@ openspec instructions proposal --change "<name>" --json
|
|
|
164
167
|
在创建变更目录之后、写 proposal 能力列表之前(或紧接 CAP 编号分配前):
|
|
165
168
|
|
|
166
169
|
1. 提取 / 询问外部需求号 `REQ-*`(没有则问一次)。
|
|
167
|
-
2.
|
|
170
|
+
2. **先加载依赖技能**:确认 `${AGENT_SKILL_DIR}/opsx-ontology-query/SKILL.md`(或当前编辑器等价 skills 路径)存在并 Read;按该技能完成 API Key / 空间与 KB 选择(写入其 `.local/state.json`)。未安装则停止本步。
|
|
171
|
+
3. 调用知识库 **`opsx-ontology-query`**(权威);可用薄封装,但契约以该技能为准:
|
|
168
172
|
```bash
|
|
169
173
|
node skywalk-sdd/context-client.cjs --mode=resolve \
|
|
170
174
|
--external-system=requirement-mgmt \
|
|
@@ -174,11 +178,11 @@ node skywalk-sdd/context-client.cjs --mode=resolve \
|
|
|
174
178
|
--space-id="$ENGINEERING_KB_SPACE_ID" \
|
|
175
179
|
--kb-id="$ENGINEERING_KB_KB_ID"
|
|
176
180
|
```
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
4. 按 KB 结果确认 Continuity:`iteration` / `similar-reference` / `new`;勾选本次涉及的 CAP。
|
|
182
|
+
5. 写入 proposal frontmatter:`requirement-refs` + `continuity`(字段来自 KB:`kb-space-id` / `kb-id` / `base-capabilities[].entity-id` / `current-version-id`)。**禁止**写本地 archive 文件夹名作为 `base-archive`。
|
|
183
|
+
6. CAP 级「同 key + 同锚点、不同 entity_id」当场问 A/B/C;决议写入 `openspec/changes/<name>/continuity-resolution.json` 的 `capabilities[]`。
|
|
184
|
+
7. KB 不可用 → `degraded` 继续,**禁止**扫本地 `archive/` 抄 UUID。预期:恢复后同锚点入库可能触发 `EXTERNAL_REF_CONFLICT`。
|
|
185
|
+
8. **不得**在本阶段生成 STMT/AC/场景或裁决场景身份。
|
|
182
186
|
|
|
183
187
|
### 7. 【交互引导】文档拆分模式选择
|
|
184
188
|
|
|
@@ -3,10 +3,11 @@ name: opsx-spec
|
|
|
3
3
|
description: "技术契约文档技能 - 为每个能力创建 spec.md,定义业务场景与技术规范"
|
|
4
4
|
argument-hint: "[change-name] [上下文文件...]"
|
|
5
5
|
license: MIT
|
|
6
|
-
compatibility: Requires openspec CLI.
|
|
6
|
+
compatibility: Requires openspec CLI; depends on opsx-ontology-query.
|
|
7
7
|
metadata:
|
|
8
8
|
author: sdd-team
|
|
9
9
|
version: "3.0"
|
|
10
|
+
depends-on: opsx-ontology-query
|
|
10
11
|
allowed-tools:
|
|
11
12
|
- Bash
|
|
12
13
|
- Read
|
|
@@ -16,6 +17,8 @@ allowed-tools:
|
|
|
16
17
|
|
|
17
18
|
你是一个 SDD(Specification-Driven Development)技术契约专家。激活本技能后,你将引导用户为每个 Capability 创建 **spec.md** 文档。
|
|
18
19
|
|
|
20
|
+
> **硬依赖**:场景身份 / Spec 复用依赖同级已部署的 **`opsx-ontology-query`**。进入知识库上下文步骤前必须先 `Read` 该技能的 `SKILL.md` 并完成其 Session 启动(API Key + targets)。缺失则停止复用查询,提示重新 `kld-sdd-init`;**禁止**从本地 `archive/` 抄 UUID。
|
|
21
|
+
|
|
19
22
|
> **⚠️ 阶段边界约束**
|
|
20
23
|
>
|
|
21
24
|
> 当前处于 **Spec(契约)阶段**:
|
|
@@ -109,7 +112,8 @@ openspec list
|
|
|
109
112
|
|
|
110
113
|
**【默认尝试】工程 Spec 知识库上下文(场景身份主战场)**:
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
1. **先加载依赖技能**:确认 `${AGENT_SKILL_DIR}/opsx-ontology-query/SKILL.md` 存在并 Read;按该技能完成 API Key / targets(`.local/state.json`)。未安装则停止本步。
|
|
116
|
+
2. 读取 proposal Continuity。对**当前 Capability** 各调一次(「全部」= 循环 N 次,不是一次大查询)——优先走 **`opsx-ontology-query`** 的 `match-requirement`;薄封装仅作参数拼装:
|
|
113
117
|
|
|
114
118
|
```bash
|
|
115
119
|
node skywalk-sdd/context-client.cjs \
|
|
@@ -123,7 +127,7 @@ node skywalk-sdd/context-client.cjs \
|
|
|
123
127
|
--kb-id="$ENGINEERING_KB_KB_ID"
|
|
124
128
|
```
|
|
125
129
|
|
|
126
|
-
- 配置项:`ENGINEERING_KB_API`、`ENGINEERING_KB_SPACE_ID`、`ENGINEERING_KB_KB_ID`、可选 `ENGINEERING_KB_TOKEN
|
|
130
|
+
- 配置项:`ENGINEERING_KB_API`、`ENGINEERING_KB_SPACE_ID`、`ENGINEERING_KB_KB_ID`、可选 `ENGINEERING_KB_TOKEN`。查询权威技能是 **`opsx-ontology-query`**;本脚本只是薄封装。
|
|
127
131
|
- Continuity=`iteration` 时**必须**带 `--entity-id` + external。
|
|
128
132
|
- **禁止**从本地 `archive/` 抄 UUID 当跨迭代继承源;跨迭代只认 KB current。
|
|
129
133
|
- 若返回 `available=false` / `degraded=true`,记录降级并继续,不得扫本地 archive 兜底。
|
|
@@ -189,7 +189,14 @@ Simple 模式或单文件能力域下,**不要拆成多个同文件任务**。
|
|
|
189
189
|
|
|
190
190
|
### 8. 质量红线自检
|
|
191
191
|
|
|
192
|
-
> 逐项确认,完整 7 项自检清单 + TDD 合规性自检(结构符合模板 / 拓扑图已绘制 / 依赖字段已填写 / 无循环依赖 / 颗粒度 ≤5 分钟 / 100% 覆盖 design / 每任务有验收标准)见 `./checklist.md`「§8 质量红线自检 + §8.1 TDD
|
|
192
|
+
> 逐项确认,完整 7 项自检清单 + TDD 合规性自检(结构符合模板 / 拓扑图已绘制 / 依赖字段已填写 / 无循环依赖 / 颗粒度 ≤5 分钟 / 100% 覆盖 design / 每任务有验收标准)见 `./checklist.md`「§8 质量红线自检 + §8.1 TDD 合规性自检」。
|
|
193
|
+
>
|
|
194
|
+
> 额外强制项(见 `./checklist.md` §8):
|
|
195
|
+
> - ⛔ **CON 覆盖**:spec.md 中每个 CON 必须有对应验证任务或显式声明间接覆盖
|
|
196
|
+
> - ⛔ **安全/审计要求覆盖**:spec.md §5.x 中的安全与审计要求必须有对应任务或显式声明推迟
|
|
197
|
+
> - ⛔ **§4.x 验证方式表内部一致性**:§4.x 验证方式表中的测试注解/配置必须与任务实现步骤中的声明一致
|
|
198
|
+
>
|
|
199
|
+
> 如有任意一项未满足,重新生成对应章节,直至全部通过。
|
|
193
200
|
|
|
194
201
|
### 9. 确认任务并输出
|
|
195
202
|
|
|
@@ -29,6 +29,9 @@ description: opsx-task 的阶段强制检查点与自检清单。仅在执行 ta
|
|
|
29
29
|
- [ ] 每个任务颗粒度 ≤ 5 分钟
|
|
30
30
|
- [ ] 100% 覆盖 design.md 定义
|
|
31
31
|
- [ ] 每个任务都有验收标准
|
|
32
|
+
- [ ] ⛔ **约束(CON)覆盖**:spec.md 中每个 CON 必须有对应验证任务,或在任务中显式声明"通过现有 AC 间接覆盖"并说明理由;tasks.md 质量红线声明"100% 覆盖 CON"时必须可追溯
|
|
33
|
+
- [ ] ⛔ **安全/审计要求覆盖**:spec.md §5.x 中的安全与审计要求(日志记录、脱敏、告警等)必须有对应任务,或显式声明推迟到后续迭代并在任务中标注
|
|
34
|
+
- [ ] ⛔ **§4.x 验证方式表内部一致性**:§4.x 验证方式表中的测试注解/配置必须与任务实现步骤中的声明一致,不得出现"§4.1 声明 @WebMvcTest 但实现步骤允许 @SpringBootTest"的矛盾
|
|
32
35
|
|
|
33
36
|
**如有任意一项未满足,重新生成对应章节,直至全部通过。**
|
|
34
37
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: opsx-tdd-anti-patterns
|
|
3
|
-
description: "测试反模式防护层 —
|
|
3
|
+
description: "测试反模式防护层 — 16 种反模式检测(RED 阶段 3 种 + GREEN 后 13 种),每种带门禁函数和修复方案。当编写或审查测试代码时引用本技能。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# opsx-tdd-anti-patterns — 反模式防护层
|
|
@@ -32,7 +32,7 @@ description: "测试反模式防护层 — 15 种反模式检测(RED 阶段 3
|
|
|
32
32
|
| 2 | **Mock 预定结论而非准备条件** | `when(bookMapper.countByPublisher(1L)).thenReturn(3)` 后只测 `if (count > 0) throw` — trivial 逻辑 | "我的测试是在验证完整行为链路,还是只验证一个 if 分支?" | Mock 边界依赖(Mapper)是合理的,但测试断言应验证完整行为链路(如 verify 不会执行 delete) |
|
|
33
33
|
| 3 | **Given 不是真实输入** | mock 出"这个输入会导致什么结果",而非传入真实数据让被测代码自行处理 | "我的 Given 是真实数据还是 mock 出的预定结论?" | 传入真实数据(如 `"invalid"` 字符串、`null`、空对象),让被测代码自行决定结果 |
|
|
34
34
|
|
|
35
|
-
## §4 GREEN 后反模式(
|
|
35
|
+
## §4 GREEN 后反模式(13 种)
|
|
36
36
|
|
|
37
37
|
| # | 反模式 | 问题表现 | 修复方案 |
|
|
38
38
|
|---|--------|---------|---------|
|
|
@@ -48,6 +48,7 @@ description: "测试反模式防护层 — 15 种反模式检测(RED 阶段 3
|
|
|
48
48
|
| 13 | **魔法值** | 测试中使用未解释的字面值(如 `assertEquals(42, result)` 无注释说明 42 的含义) | 使用命名常量或注释解释字面值含义 |
|
|
49
49
|
| 14 | **断言不足** | 只断言了部分结果,遗漏了关键属性(如只 assertNotNull 但不 assertEquals 具体值) | 每个测试至少有一个具体值断言(assertEquals),而非仅 assertNotNull |
|
|
50
50
|
| 15 | **缺少负面测试** | 只测试正常路径,不测试错误条件 | 每个方法至少有一个异常路径测试(见 `opsx-tdd-rules/rules/exception-path-coverage.md`) |
|
|
51
|
+
| 16 | **AC 变体覆盖不足** | AC 场景描述含"或"条件(如"缺少 A 或 B 或为空"),但测试只覆盖部分变体 | AC 中每个"或"条件变体必须有对应测试方法(规则见 `opsx-tdd-rules/rules/multi-validation-split.md` §AC 内"或"条件变体覆盖) |
|
|
51
52
|
|
|
52
53
|
## §5 门禁函数
|
|
53
54
|
|
|
@@ -82,3 +83,5 @@ AFTER GREEN(GREEN 完成后、标记通过前):
|
|
|
82
83
|
- 测试中只有 `assertNotNull` 无具体值断言
|
|
83
84
|
- 测试中存在未解释的魔法数字/字符串
|
|
84
85
|
- 正常路径有测试但异常路径无测试
|
|
86
|
+
- AC 场景描述含"或"条件但测试只覆盖部分变体
|
|
87
|
+
- 连续 RED/GREEN 的 task_update 时间戳差距过小(批量执行信号,违反 TDD 严格串行)
|
|
@@ -195,6 +195,35 @@ assertEquals("user-001", result.getUserId());
|
|
|
195
195
|
|
|
196
196
|
**修复**:每个方法至少有一个异常路径测试。规则见 `opsx-tdd-rules/rules/exception-path-coverage.md`。
|
|
197
197
|
|
|
198
|
+
## 反模式 16:AC 变体覆盖不足
|
|
199
|
+
|
|
200
|
+
**问题**:AC 场景描述含"或"条件(如"缺少 A 或 B 或为空"),但测试只覆盖部分变体,其余变体无测试守护。
|
|
201
|
+
|
|
202
|
+
**反例**:
|
|
203
|
+
```java
|
|
204
|
+
// AC-004: 请求体缺少 username 或 password 字段,或字段值为空字符串
|
|
205
|
+
// 仅测试 1/6 变体
|
|
206
|
+
@Test
|
|
207
|
+
void login_withMissingParams_returns1001() {
|
|
208
|
+
mockMvc.perform(post("/login")
|
|
209
|
+
.content("{\"username\":\"\",\"password\":\"admin123\"}"))
|
|
210
|
+
.andExpect(jsonPath("$.code").value(1001));
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**正例**:
|
|
215
|
+
```java
|
|
216
|
+
// 每个变体都有测试方法(或参数化测试)
|
|
217
|
+
@Test void login_withEmptyUsername_returns1001() { ... }
|
|
218
|
+
@Test void login_withEmptyPassword_returns1001() { ... }
|
|
219
|
+
@Test void login_withMissingUsernameField_returns1001() { ... }
|
|
220
|
+
@Test void login_withMissingPasswordField_returns1001() { ... }
|
|
221
|
+
@Test void login_withBothEmpty_returns1001() { ... }
|
|
222
|
+
@Test void login_withBothMissing_returns1001() { ... }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**修复**:AC 中每个"或"条件变体必须有对应测试方法。规则见 `opsx-tdd-rules/rules/multi-validation-split.md` §AC 内"或"条件变体覆盖。
|
|
226
|
+
|
|
198
227
|
## TDD 如何防止这些反模式
|
|
199
228
|
|
|
200
229
|
1. 先写测试 → 迫使你思考实际在测试什么
|
|
@@ -40,6 +40,9 @@ description: "opsx-tdd-core 自检清单 — TDD 执行合规自检、合规性
|
|
|
40
40
|
- [ ] 每个 RED 任务包含测试方法名(`{method}_{state}_{outcome}` 格式)
|
|
41
41
|
- [ ] 每个 GREEN 任务包含 YAGNI 围栏声明("不提前实现 [后续 RED 行为]")
|
|
42
42
|
- [ ] 每个 REFACTOR 任务列出至少 2 个具体重构点
|
|
43
|
+
- [ ] ⛔ **CON 覆盖**:spec.md 中每个 CON 在 tasks.md 中有对应验证任务或显式声明间接覆盖
|
|
44
|
+
- [ ] ⛔ **安全/审计要求覆盖**:spec.md §5.x 中的安全与审计要求在 tasks.md 中有对应任务或显式声明推迟
|
|
45
|
+
- [ ] ⛔ **AC 变体覆盖**:spec.md 中含"或"条件的 AC 场景,其 RED 任务验收标准列出所有变体的测试方法(引用 `opsx-tdd-rules/rules/multi-validation-split.md`)
|
|
43
46
|
|
|
44
47
|
## §C 完成验证清单(8 项)
|
|
45
48
|
|
|
@@ -53,5 +56,6 @@ description: "opsx-tdd-core 自检清单 — TDD 执行合规自检、合规性
|
|
|
53
56
|
- [ ] 输出纯净(无错误/警告)
|
|
54
57
|
- [ ] 测试使用真实代码(仅在不可避免时使用 mock)
|
|
55
58
|
- [ ] 边界情况和错误已覆盖
|
|
59
|
+
- [ ] ⛔ **AC "或"条件变体全覆盖**:AC 场景描述含"或"条件时,每个变体都有对应测试方法(引用 `opsx-tdd-rules/rules/multi-validation-split.md`)
|
|
56
60
|
|
|
57
61
|
> Can't check all boxes? You skipped TDD. Start over.
|
|
@@ -24,6 +24,6 @@ description: "TDD 规则库 — DAG 生成规则、Controller 策略、任务类
|
|
|
24
24
|
| `rules/green-yagni-fence.md` | GREEN 任务 YAGNI 围栏自动注入规则 | HIGH | opsx-task |
|
|
25
25
|
| `rules/green-scope-declaration.md` | GREEN 任务 Scope 声明步骤(断言清单→流程标记→仅实现属于的步骤) | HIGH | opsx-apply |
|
|
26
26
|
| `rules/des-step-annotation.md` | DES 元素步骤级标注规则(TDD 模式下标注 [GREEN-N] 归属) | MEDIUM | opsx-design |
|
|
27
|
-
| `rules/multi-validation-split.md` | 多校验条件拆分规则(每个校验条件须有独立 AC
|
|
27
|
+
| `rules/multi-validation-split.md` | 多校验条件拆分规则(每个校验条件须有独立 AC 场景;AC 内"或"条件变体须全覆盖) | MEDIUM | opsx-spec, opsx-task, opsx-check |
|
|
28
28
|
| `rules/exception-path-coverage.md` | 异常路径测试覆盖门禁(每个 orElseThrow/边界检查须有对应 RED 测试) | HIGH | opsx-task, opsx-apply, opsx-check |
|
|
29
29
|
| `rules/refactor-checklist.md` | REFACTOR 阶段检查点(public API 不变、行为保持、重构质量评估) | HIGH | opsx-apply, opsx-tdd-core |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 多校验拆分规则
|
|
2
2
|
|
|
3
3
|
> 影响等级:MEDIUM
|
|
4
|
-
> 引用方:opsx-spec(spec.md 生成)、opsx-spec/checklist.md
|
|
4
|
+
> 引用方:opsx-spec(spec.md 生成)、opsx-spec/checklist.md(自检)、opsx-task(RED 任务拆解)、opsx-check(一致性检查)
|
|
5
5
|
|
|
6
6
|
## 问题
|
|
7
7
|
|
|
@@ -34,3 +34,37 @@ AC-03: 可借数量不足(available_count = 0)
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
> 目的:每个校验条件有独立场景 → 独立 RED 测试 → 独立 GREEN 实现,避免 AI 在一个 GREEN 中实现所有校验。
|
|
37
|
+
|
|
38
|
+
## AC 内"或"条件变体覆盖
|
|
39
|
+
|
|
40
|
+
> 引用方:opsx-spec(spec.md 生成)、opsx-task(RED 任务拆解)、opsx-check(一致性检查)
|
|
41
|
+
|
|
42
|
+
### 问题
|
|
43
|
+
|
|
44
|
+
单个 AC 场景描述中包含"或"条件时(如"缺少 username **或** password 字段,或字段值为空字符串"),AI 在拆解 RED 任务时倾向于只取一个变体编写测试,导致其余变体无测试守护。
|
|
45
|
+
|
|
46
|
+
### 规则
|
|
47
|
+
|
|
48
|
+
当单个 AC 场景描述包含"或"条件时,必须检查:
|
|
49
|
+
|
|
50
|
+
1. 每个"或"条件变体是否有对应的测试方法
|
|
51
|
+
2. 若多个变体共享一个 RED 任务,RED 验收标准中必须列出所有变体的测试方法名
|
|
52
|
+
3. 变体可合并到一个 RED 任务的多个 `@Test` 方法中,但不得遗漏任何变体
|
|
53
|
+
|
|
54
|
+
### 反例(禁止)
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
AC-004: 请求体缺少 username 或 password 字段,或字段值为空字符串
|
|
58
|
+
RED-4: login_withMissingParams_returns1001
|
|
59
|
+
→ 仅测试 username="" 一种变体,password="" / 缺少字段 / 双空 / 双缺共 5 种变体未覆盖
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 正例(要求)
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
AC-004: 请求体缺少 username 或 password 字段,或字段值为空字符串
|
|
66
|
+
RED-4: login_withMissingParams_returns1001(含 6 个 @Test 方法或参数化测试)
|
|
67
|
+
→ username="" / password="" / 缺少 username / 缺少 password / 双空 / 双缺 均有测试
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> 目的:spec 中"或"条件描述的每个变体都有测试守护,防止参数校验逻辑回归。
|