kld-sdd 2.7.8-1 → 2.7.8-2
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/USABILITY.md +20 -0
- package/bin/kld-sdd-init.js +1 -1
- package/lib/init.js +7 -0
- package/package.json +2 -2
- package/skywalk-sdd/index.cjs +123 -24
- package/skywalk-sdd/lib/check-review.cjs +41 -0
- package/skywalk-sdd/lib/test-execution.cjs +110 -0
- package/templates/git-hooks/commit-msg +19 -5
- package/templates/git-hooks/consistency-check-core.cjs +31 -21
- package/templates/git-hooks/pre-commit +19 -5
- package/templates/git-hooks/pre-push +19 -5
- package/templates/hooks/claude/hooks/sdd-post-tool.cjs +2 -2
- package/templates/hooks/codebuddy/hooks/sdd-post-tool.cjs +2 -2
- package/templates/skills/kld-sdd/opsx-apply/SKILL.md +1 -0
- package/templates/skills/kld-sdd/opsx-apply/reference.md +19 -1
- package/templates/skills/kld-sdd/opsx-archive/SKILL.md +10 -8
- package/templates/skills/kld-sdd/opsx-check/SKILL.md +7 -5
- package/templates/skills/kld-sdd/opsx-check/reference.md +3 -1
- package/templates/skills/kld-sdd/opsx-check/review-template.json +22 -0
- package/templates/skills/kld-sdd/opsx-check/reviewer.md +5 -5
- package/templates/skills/kld-sdd/opsx-kb-config/SKILL.md +29 -154
- package/templates/skills/kld-sdd/opsx-kb-config/reference.md +8 -11
- package/templates/skills/kld-sdd/opsx-kb-ingest/reference.md +2 -2
- package/templates/skills/kld-sdd/opsx-propose/SKILL.md +1 -1
- package/templates/skills/kld-sdd/opsx-propose/interaction-policy.md +7 -0
- package/templates/skills/kld-sdd/opsx-task/SKILL.md +2 -2
|
@@ -49,7 +49,7 @@ function parseActiveChangesFromYaml(content) {
|
|
|
49
49
|
for (const raw of content.split(/\r?\n/)) {
|
|
50
50
|
const line = raw.replace(/#.*$/, '').replace(/\s+$/, '');
|
|
51
51
|
if (!line.trim()) continue;
|
|
52
|
-
if (/^active_changes:\s*(\[\s
|
|
52
|
+
if (/^active_changes:\s*(\[\s*])?\s*$/.test(line)) { inActive = true; continue; }
|
|
53
53
|
if (inActive) {
|
|
54
54
|
const m = /^\s+-\s+change-key:\s*(\S+)/.exec(line);
|
|
55
55
|
if (m) keys.push(m[1]);
|
|
@@ -144,17 +144,31 @@ function validateReportFields(report) {
|
|
|
144
144
|
// --- 变更文件采集 ---
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
|
-
* 简易 YAML 解析器:仅提取 code_repos
|
|
147
|
+
* 简易 YAML 解析器:仅提取 code_repos 列表。
|
|
148
|
+
* 逐行状态机解析(无正则量词嵌套),天然免疫 ReDoS(Sonar S5852)。
|
|
149
|
+
* 容忍条目间注释、行尾注释;遇到下一个顶层 key(非缩进行)即停止。
|
|
148
150
|
*/
|
|
149
151
|
function parseCodeRepos(yamlPath) {
|
|
150
152
|
try {
|
|
151
153
|
const content = fs.readFileSync(yamlPath, 'utf8');
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
.
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
const repos = [];
|
|
155
|
+
let inList = false;
|
|
156
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
157
|
+
const line = raw.replace(/#.*$/, '').replace(/\s+$/, '');
|
|
158
|
+
if (!line.trim()) continue;
|
|
159
|
+
if (!/^\s/.test(line)) {
|
|
160
|
+
// 顶层 key:进入 code_repos 列表 / 离开列表
|
|
161
|
+
inList = /^code_repos:\s*$/.test(line);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (!inList) continue;
|
|
165
|
+
const item = line.trim();
|
|
166
|
+
if (item.startsWith('- ')) {
|
|
167
|
+
const value = item.slice(2).trim();
|
|
168
|
+
if (value) repos.push(value);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return repos.length > 0 ? repos : null;
|
|
158
172
|
} catch {
|
|
159
173
|
return null;
|
|
160
174
|
}
|
|
@@ -185,10 +199,8 @@ function isTrivialDiffLine(line) {
|
|
|
185
199
|
if (trimmed.startsWith('#')) {
|
|
186
200
|
// 排除 C/C++ 预处理指令
|
|
187
201
|
const rest = trimmed.slice(1).trimStart();
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
return true; // Python/Shell/YAML 注释
|
|
202
|
+
return !/^(include|define|ifdef|ifndef|endif|else|elif|undef|pragma|error|warning|line|region|endregion)\b/.test(rest);
|
|
203
|
+
// Python/Shell/YAML 注释
|
|
192
204
|
}
|
|
193
205
|
if (trimmed.startsWith('/*') || trimmed.endsWith('*/')) return true; // 块注释开始/结束
|
|
194
206
|
if (trimmed.startsWith('*')) return true; // 块注释续行 (* ... 或 ** ...)
|
|
@@ -252,7 +264,7 @@ function parseDiffForTrivialFiles(diffOutput) {
|
|
|
252
264
|
if (line.startsWith('-') && !line.startsWith('---')) {
|
|
253
265
|
hasAnyChange = true;
|
|
254
266
|
if (!isTrivialDiffLine(line.slice(1))) hasSubstantive = true;
|
|
255
|
-
|
|
267
|
+
|
|
256
268
|
}
|
|
257
269
|
}
|
|
258
270
|
if (currentFile !== null && hasAnyChange && !hasSubstantive) {
|
|
@@ -413,7 +425,7 @@ function parseConsistencySection() {
|
|
|
413
425
|
let inSection = false;
|
|
414
426
|
for (const raw of content.split(/\r?\n/)) {
|
|
415
427
|
const line = raw.trim();
|
|
416
|
-
if (/^\[
|
|
428
|
+
if (/^\[.+]$/.test(line)) {
|
|
417
429
|
if (inSection) break;
|
|
418
430
|
inSection = line.toLowerCase() === '[consistency]';
|
|
419
431
|
continue;
|
|
@@ -493,9 +505,9 @@ function isBusinessCode(file) {
|
|
|
493
505
|
if (/(^|\/)(__tests__|tests?|e2e|cypress|fixtures|mocks?)(\/|$)/i.test(normalized)) return false;
|
|
494
506
|
if (/(^|\/)[^/]*(?:\.test|\.spec|_test)\.[a-z]+$/i.test(normalized)) return false;
|
|
495
507
|
if (TOOLCHAIN_CONFIG_RE.test(base)) return false;
|
|
496
|
-
|
|
508
|
+
return !DOTFILE_CONFIG_RE.test(base);
|
|
509
|
+
|
|
497
510
|
|
|
498
|
-
return true;
|
|
499
511
|
}
|
|
500
512
|
|
|
501
513
|
// --- 路径归一化:报告 coveredFiles → 代码仓相对 ---
|
|
@@ -968,7 +980,7 @@ function runConsistencyCheck(opts) {
|
|
|
968
980
|
function runFilterMode() {
|
|
969
981
|
const filesArg = readArg('files');
|
|
970
982
|
|
|
971
|
-
let input
|
|
983
|
+
let input;
|
|
972
984
|
if (filesArg) {
|
|
973
985
|
if (filesArg.startsWith('@')) {
|
|
974
986
|
input = fs.readFileSync(filesArg.slice(1), 'utf8').split(/\r?\n/);
|
|
@@ -1021,11 +1033,9 @@ function runCollectMode() {
|
|
|
1021
1033
|
const businessFiles = files.filter(isBusinessCode);
|
|
1022
1034
|
const excluded = files.filter(f => !isBusinessCode(f));
|
|
1023
1035
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1036
|
+
const hashedBusiness = [];
|
|
1037
|
+
const unreadableFiles = [];
|
|
1026
1038
|
if (withHash) {
|
|
1027
|
-
hashedBusiness = [];
|
|
1028
|
-
unreadableFiles = [];
|
|
1029
1039
|
for (const rel of businessFiles) {
|
|
1030
1040
|
const content = readWorkingFile(path.join(projectRoot, rel));
|
|
1031
1041
|
if (content === null) {
|
|
@@ -10,13 +10,24 @@ git_root=$(git rev-parse --show-toplevel 2>/dev/null) || {
|
|
|
10
10
|
exit 1
|
|
11
11
|
}
|
|
12
12
|
hooks_dir=""
|
|
13
|
+
# 统一反斜杠为正斜杠,保证 Windows 盘符路径(P:\a\b → P:/a/b)能被 case 判定为绝对路径
|
|
14
|
+
normalize_path() {
|
|
15
|
+
printf '%s' "$1" | tr '\\' '/'
|
|
16
|
+
}
|
|
17
|
+
# 绝对路径(/ 开头或盘符 X: 开头)直接使用;相对路径基于 git 根拼接
|
|
18
|
+
resolve_spec_dir() {
|
|
19
|
+
raw=$(normalize_path "$1")
|
|
20
|
+
case "$raw" in
|
|
21
|
+
/*|[A-Za-z]:*) printf '%s' "$raw" ;;
|
|
22
|
+
*) printf '%s' "$git_root/$raw" ;;
|
|
23
|
+
esac
|
|
24
|
+
}
|
|
13
25
|
spec_path=$(git -C "$git_root" config --local sdd.specPath 2>/dev/null)
|
|
14
26
|
if [ -n "$spec_path" ]; then
|
|
15
|
-
|
|
16
|
-
hooks_dir="$spec_path/skywalk-sdd/git-hooks"
|
|
27
|
+
hooks_dir="$(resolve_spec_dir "$spec_path")/skywalk-sdd/git-hooks"
|
|
17
28
|
elif [ -f "$git_root/.sdd-spec-root" ]; then
|
|
18
29
|
spec_rel=$(head -1 "$git_root/.sdd-spec-root" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
19
|
-
|
|
30
|
+
hooks_dir="$(resolve_spec_dir "$spec_rel")/skywalk-sdd/git-hooks"
|
|
20
31
|
fi
|
|
21
32
|
if [ -n "$hooks_dir" ] && [ ! -d "$hooks_dir" ]; then
|
|
22
33
|
echo "[SDD] 已配置的 Spec 路径失效:$hooks_dir"
|
|
@@ -27,12 +38,15 @@ fi
|
|
|
27
38
|
# 方法3: 从 git 根向上搜索 skywalk-sdd/git-hooks(spec 仓本身或父级)
|
|
28
39
|
if [ -z "$hooks_dir" ]; then
|
|
29
40
|
search_dir="$git_root"
|
|
30
|
-
while [ "$search_dir"
|
|
41
|
+
while [ -n "$search_dir" ] && [ "$search_dir" != "/" ]; do
|
|
31
42
|
if [ -d "$search_dir/skywalk-sdd/git-hooks" ]; then
|
|
32
43
|
hooks_dir="$search_dir/skywalk-sdd/git-hooks"
|
|
33
44
|
break
|
|
34
45
|
fi
|
|
35
|
-
|
|
46
|
+
# Windows 盘符根(P:/)dirname 后不变,需显式收敛,避免死循环
|
|
47
|
+
parent_dir="$(dirname "$search_dir")"
|
|
48
|
+
[ "$parent_dir" = "$search_dir" ] && break
|
|
49
|
+
search_dir="$parent_dir"
|
|
36
50
|
done
|
|
37
51
|
fi
|
|
38
52
|
|
|
@@ -10,13 +10,24 @@ git_root=$(git rev-parse --show-toplevel 2>/dev/null) || {
|
|
|
10
10
|
exit 1
|
|
11
11
|
}
|
|
12
12
|
hooks_dir=""
|
|
13
|
+
# 统一反斜杠为正斜杠,保证 Windows 盘符路径(P:\a\b → P:/a/b)能被 case 判定为绝对路径
|
|
14
|
+
normalize_path() {
|
|
15
|
+
printf '%s' "$1" | tr '\\' '/'
|
|
16
|
+
}
|
|
17
|
+
# 绝对路径(/ 开头或盘符 X: 开头)直接使用;相对路径基于 git 根拼接
|
|
18
|
+
resolve_spec_dir() {
|
|
19
|
+
raw=$(normalize_path "$1")
|
|
20
|
+
case "$raw" in
|
|
21
|
+
/*|[A-Za-z]:*) printf '%s' "$raw" ;;
|
|
22
|
+
*) printf '%s' "$git_root/$raw" ;;
|
|
23
|
+
esac
|
|
24
|
+
}
|
|
13
25
|
spec_path=$(git -C "$git_root" config --local sdd.specPath 2>/dev/null)
|
|
14
26
|
if [ -n "$spec_path" ]; then
|
|
15
|
-
|
|
16
|
-
hooks_dir="$spec_path/skywalk-sdd/git-hooks"
|
|
27
|
+
hooks_dir="$(resolve_spec_dir "$spec_path")/skywalk-sdd/git-hooks"
|
|
17
28
|
elif [ -f "$git_root/.sdd-spec-root" ]; then
|
|
18
29
|
spec_rel=$(head -1 "$git_root/.sdd-spec-root" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
19
|
-
|
|
30
|
+
hooks_dir="$(resolve_spec_dir "$spec_rel")/skywalk-sdd/git-hooks"
|
|
20
31
|
fi
|
|
21
32
|
if [ -n "$hooks_dir" ] && [ ! -d "$hooks_dir" ]; then
|
|
22
33
|
echo "[SDD] 已配置的 Spec 路径失效:$hooks_dir"
|
|
@@ -27,12 +38,15 @@ fi
|
|
|
27
38
|
# 方法3: 从 git 根向上搜索 skywalk-sdd/git-hooks(spec 仓本身或父级)
|
|
28
39
|
if [ -z "$hooks_dir" ]; then
|
|
29
40
|
search_dir="$git_root"
|
|
30
|
-
while [ "$search_dir"
|
|
41
|
+
while [ -n "$search_dir" ] && [ "$search_dir" != "/" ]; do
|
|
31
42
|
if [ -d "$search_dir/skywalk-sdd/git-hooks" ]; then
|
|
32
43
|
hooks_dir="$search_dir/skywalk-sdd/git-hooks"
|
|
33
44
|
break
|
|
34
45
|
fi
|
|
35
|
-
|
|
46
|
+
# Windows 盘符根(P:/)dirname 后不变,需显式收敛,避免死循环
|
|
47
|
+
parent_dir="$(dirname "$search_dir")"
|
|
48
|
+
[ "$parent_dir" = "$search_dir" ] && break
|
|
49
|
+
search_dir="$parent_dir"
|
|
36
50
|
done
|
|
37
51
|
fi
|
|
38
52
|
|
|
@@ -171,8 +171,8 @@ function recordTelemetry(projectRoot, activeStage, record, result, exitCodeKnown
|
|
|
171
171
|
skipped: counts.skipped,
|
|
172
172
|
} : {}),
|
|
173
173
|
duration_ms: Number.isFinite(toolResponse.duration_ms) ? toolResponse.duration_ms : 0,
|
|
174
|
-
failure_type: result === 'failure' ? (exitCode
|
|
175
|
-
expected_failure: tddPhase === 'red' && result === 'failure' && exitCode != null,
|
|
174
|
+
failure_type: result === 'failure' ? (exitCode != null && /ERR_ASSERTION|AssertionError|AssertionFailedError/.test(output) ? 'assertion' : 'infrastructure') : 'none',
|
|
175
|
+
expected_failure: tddPhase === 'red' && result === 'failure' && exitCode != null && /ERR_ASSERTION|AssertionError|AssertionFailedError/.test(output),
|
|
176
176
|
};
|
|
177
177
|
strictTestEvent = exitCode != null && Boolean(activeStage.task_id);
|
|
178
178
|
runId = stableRunId(input || {}, activeStage, details.test_results.command);
|
|
@@ -160,8 +160,8 @@ function recordTelemetry(projectRoot, activeStage, record, result, exitCodeKnown
|
|
|
160
160
|
skipped: counts.skipped,
|
|
161
161
|
} : {}),
|
|
162
162
|
duration_ms: Number.isFinite(toolResponse.duration_ms) ? toolResponse.duration_ms : 0,
|
|
163
|
-
failure_type: result === 'failure' ? (exitCode
|
|
164
|
-
expected_failure: tddPhase === 'red' && result === 'failure' && exitCode != null,
|
|
163
|
+
failure_type: result === 'failure' ? (exitCode != null && /ERR_ASSERTION|AssertionError|AssertionFailedError/.test(output) ? 'assertion' : 'infrastructure') : 'none',
|
|
164
|
+
expected_failure: tddPhase === 'red' && result === 'failure' && exitCode != null && /ERR_ASSERTION|AssertionError|AssertionFailedError/.test(output),
|
|
165
165
|
};
|
|
166
166
|
strictTestEvent = exitCode != null && Boolean(activeStage.task_id);
|
|
167
167
|
runId = stableRunId(input || {}, activeStage, details.test_results.command);
|
|
@@ -40,6 +40,7 @@ allowed-tools:
|
|
|
40
40
|
> - 较大的 `--details-json` 负载可先写入文件,再通过 `--details-file="$(cat .sdd-spec-root)/skywalk-sdd/state/<变更名称>-<type>.json"` 传递(例如 `task_update` 对应 `<变更名称>-task-update.json`)。
|
|
41
41
|
> - `task_update` 记录成功后会自动调用 `check-task` 更新 `tasks.md` 中的 checkbox;录入成功后,agent 可以通过 `check-task` 命令验证该 checkbox 已更新。
|
|
42
42
|
> - **⚠️ P1-2 ai_adoption_review 必填 ai_diff**:记录 AI 产出快照时,`--details-json` 必须含 `ai_diff.files_changed`(即使=0)与 `ai_diff.files`(产出文件路径数组,非空),**不得只发 `assertions`**。`vcs_mode=readonly` 时 `ai_diff.added_lines` 不得为 null——用只读 `git diff --numstat HEAD` 取值(apply Git 只读策略允许);`vcs_mode=no-git` 时可填 null。工具侧已加记录时硬校验:`files` 空数组或 `readonly` 下 `added_lines=null` 将 **拒绝记录**(与 conformance_review 校验对称)。缺失 `ai_diff` 会导致 report 变更文件数为 null(工具侧已加 `assertions[].files` 兜底,但 `ai_diff` 是主数据源)。完整模板见 `./reference.md`「§5.1」。
|
|
43
|
+
> - **默认测试入口**:使用 reference.md 中的 test-run 执行、采集和关联真实证据;可用 completion-file 同步已验证任务。不手填退出码、测试计数和耗时。
|
|
43
44
|
> - **严格证据链**:一次真实测试执行只写一条严格 `test_result`;任务完成事件只通过 `test_event_id` 引用成功的 green/refactor/regression 测试,并明确 `tdd_required=true/false`,不复制测试计数。测试不适用时必须写明原因。完整 schema 见 `./reference.md`。
|
|
44
45
|
> - **任务涉及文件必记**:每条严格 `task_update` 必须在 `task_update.files` 写本任务实际修改的仓库相对路径;本任务确实没有改文件时,改填具体的 `no_file_change_reason`。两者至少有一个。
|
|
45
46
|
> - **最终交付文件必记**:apply 所有文件就绪后记录严格 `final_output_snapshot`,其中 `final_output_snapshot.files` 是最终交付文件的仓库相对路径清单。报告把它与逐任务文件分开说明;旧 `ai_adoption_review.ai_diff.files` 只作兼容来源。
|
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
description: opsx-apply 的详细模板:telemetry 命令、worktree 全套策略、子代理派发、收尾脚本。仅在需要参考详细模板时读取。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
## 自动执行并取证(默认入口)
|
|
6
|
+
|
|
7
|
+
使用 test-run 运行真实测试并记录同一条严格事件。工具采集命令参数、实际 cwd、退出码、耗时、测试计数和原始输出哈希;不让模型抄写这些字段。测试命令用 JSON 参数数组,无 shell 展开。
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node "<spec-package>/skywalk-sdd/log.cjs" test-run --project="<spec-package>" --change=<变更名称> --session-id=<会话ID> --task-ids=<TASK-ID列表> --cwd="<代码仓>" --tdd-phase=regression --command-json='["node","--test","--test-reporter=tap","test/order-total.test.js"]'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
RED 使用 --tdd-phase=red --expected-failure;真正的断言失败才能形成有效 RED。找不到测试入口/模块、编译/环境错误、超时均不能冒充业务红灯。命令返回实际测试退出码,失败仍保留事件与回执;不要因为 RED 非零就重复执行同一个 run-id。
|
|
14
|
+
|
|
15
|
+
默认支持 Node TAP/Node 测试汇总。其他运行器输出无法可靠解析时 counts_known=false,不猜计数,不自动完成任务;已有适配器可继续用下方兼容入口提交实际报告。调用方明确声明 task-ids,工具不会把测试通过自动等同于覆盖了任意业务任务。
|
|
16
|
+
|
|
17
|
+
需要测试成功后同步任务时,增加 --completion-file=<完成信息JSON文件>。内容为数组,每项包含 task_id、实际修改的仓库相对 files、tdd_required;TDD 任务同时写 tdd_pair_id/tdd_role。无文件修改填写 no_file_change_reason。工具将完成事件自动关联本轮 test_event_id 并同步任务勾选;RED、失败或未知计数不会自动完成任务。
|
|
18
|
+
|
|
19
|
+
回执路径在输出 receipt 字段;原始 stdout/stderr 和执行清单保留在 skywalk-sdd/state/test-runs。记录失败后用原 details.json 重试 record --strict,禁止重写退出码或补造测试数。输出哈希不一致会被拒绝。自动 Hook 仅作补充,不对同一次 test-run 再手写一条 test_result。
|
|
20
|
+
|
|
21
|
+
以下手写 test_result 模板仅保留给旧集成和已有测试报告适配器,新流程优先用 test-run。
|
|
22
|
+
|
|
5
23
|
# opsx-apply — 详细参考(reference)
|
|
6
24
|
|
|
7
25
|
> 本文件承载 opsx-apply 的重细节模板:telemetry 命令、§1.5 worktree 全套策略、§5c 子代理派发、§5.1 AI 产出快照、§6.0 单元测试真实执行、§6.1 worktree 收尾脚本。
|
|
@@ -95,7 +113,7 @@ node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=test_res
|
|
|
95
113
|
- `expected_failure=true` 仅允许 `tdd_phase=red`
|
|
96
114
|
- 有效 RED:`expected_failure=true` + `exit_code≠0` + `failure_type` 为 `assertion` 或 `contract`
|
|
97
115
|
|
|
98
|
-
> **自动记录**:`sdd-post-tool.cjs` hook 会在 agent 运行 `mvn test`/`npm test` 等命令时自动记录 `test_result`,使用正确的 `test_results` key。但自动记录依赖 `activeStage.task_id`,若未设置则 `tdd_phase` 默认为 `regression`。需要精确标注 RED/GREEN
|
|
116
|
+
> **自动记录**:`sdd-post-tool.cjs` hook 会在 agent 运行 `mvn test`/`npm test` 等命令时自动记录 `test_result`,使用正确的 `test_results` key。但自动记录依赖 `activeStage.task_id`,若未设置则 `tdd_phase` 默认为 `regression`。需要精确标注 RED/GREEN 时使用上方 test-run 自动取证。
|
|
99
117
|
|
|
100
118
|
### process_note(阶段内过程事件:决策/范围变化/故障与恢复)
|
|
101
119
|
|
|
@@ -45,7 +45,7 @@ allowed-tools:
|
|
|
45
45
|
|
|
46
46
|
## 启动流程
|
|
47
47
|
|
|
48
|
-
### 1.
|
|
48
|
+
### 1. 确认变更名称
|
|
49
49
|
|
|
50
50
|
如果未提供变更名,运行:
|
|
51
51
|
|
|
@@ -53,13 +53,7 @@ allowed-tools:
|
|
|
53
53
|
openspec list
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" start --command=archive --project=. --change=<变更名称> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID>
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
保存 `event_id`。
|
|
56
|
+
按参数、会话或唯一活动变更定位;只有多个候选且无法判断时请用户选择。此时尚未开始 archive 阶段。
|
|
63
57
|
|
|
64
58
|
### 2. 记录归档原因
|
|
65
59
|
|
|
@@ -85,6 +79,14 @@ node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" doctor --project=. --change=<
|
|
|
85
79
|
|
|
86
80
|
如果存在 `severe_issues`,暂停归档并说明必须先修复。`superseded_open_stages` 和 `rework_summary` 只作为返工/重复执行展示,不要求用户人工区分测试回滚或真实研发返工。
|
|
87
81
|
|
|
82
|
+
诊断通过后才记录本轮 archive 开始,保存返回的 `event_id`:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" start --command=archive --project=. --change=<变更名称> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
不要在本轮阶段已开始但未结束时再次运行前置 doctor;历史未闭环阶段仍须按真实结果补齐,不得跳过诊断或删除事件。
|
|
89
|
+
|
|
88
90
|
### 4. 扫描 tasks 完成状态
|
|
89
91
|
|
|
90
92
|
```bash
|
|
@@ -44,7 +44,7 @@ node "<spec-package>/skywalk-sdd/log.cjs" start --command=check --project="<spec
|
|
|
44
44
|
## 2. 程序预检(在完整文档评审前)
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
node "<spec-package>/skywalk-sdd/log.cjs" semantic-check --project="<spec-package>" --change=<变更名称> --profile=auto --include-tasks
|
|
47
|
+
node "<spec-package>/skywalk-sdd/log.cjs" semantic-check --project="<spec-package>" --change=<变更名称> --profile=auto --include-tasks > "<spec-package>/skywalk-sdd/state/<变更名称>-preflight.json"
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
输出 `profile / valid / revision / counts / diagnostics`、`review_inputs`(文档路径与哈希、历史身份哈希)、`task_completion` 和 `timings_ms`。程序时间不等于模型评审总耗时。
|
|
@@ -93,15 +93,17 @@ ${CHECK_REVIEW_DELEGATION_GUIDANCE}
|
|
|
93
93
|
|
|
94
94
|
## 4. 一次记录与结束
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
将实际评审项和真实会话身份保存为 [review-template.json](review-template.json) 格式。每项只写唯一 ID、类别、结论和证据;工具自动计算统计、读取任务状态、判断 partial/failure、关联阶段结束。旧 [result-template.json](result-template.json) 仅保留给已有集成。
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
类别:completeness / consistency / executability / tdd_compliance;状态:passed / error / warning / suggestion / na。所有项包含证据或不适用理由,na 不计入通过。不要手填 total、errors、fixed_before_apply 或任务计数,不把模板占位内容当作已评审。
|
|
99
|
+
|
|
100
|
+
兼容旧集成时,顶层 `total` 必须是大于 0 的整数,且来自实际评审项;空 details 导致记录被拒绝、Q3 不可计算。`consistency_score` 仅为 legacy 字段,不能替代有证据的分类检查。新入口由工具计算这些统计,评审者无需重复填写。
|
|
99
101
|
|
|
100
102
|
```bash
|
|
101
|
-
node "<spec-package>/skywalk-sdd/log.cjs"
|
|
103
|
+
node "<spec-package>/skywalk-sdd/log.cjs" check-record --project="<spec-package>" --change=<变更名称> --run-id=<本轮Check稳定ID> --session-id=<父会话ID> --agent=<Agent类型> --preflight-file="<spec-package>/skywalk-sdd/state/<变更名称>-preflight.json" --review-file="<spec-package>/skywalk-sdd/state/<变更名称>-review.json" --end-event-id=<event_id>
|
|
102
104
|
```
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
check-record 按预检的同一 profile 重新核验正文、文件集合和历史身份。输入变化返回 CHECK_REVIEW_STALE,不写本轮通过记录;重新预检并复核受影响内容。成功时仍通过原 strict 校验和阶段结束入口,不另手动执行 end。评审输入始终保留,记录失败可以修复后重试。未真实开展评审时不用此命令,按原 end 命令记录 failure 和原因。
|
|
105
107
|
|
|
106
108
|
报告输出五维结论、多仓配置、KB 状态、证据与未执行项,说明覆盖范围。只请求检查则结束;已授权实现且无阻断项时进入 apply。修复文档后再检查相关依赖,禁止携带旧结论直接通过;不把 Capability 局部评审写成全 Change 通过。
|
|
107
109
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Check 结果记录(主 Agent 在评审完成后读取)
|
|
2
2
|
|
|
3
|
+
新流程优先使用 SKILL.md 中的 check-record 与 [review-template.json](review-template.json):工具计算统计、补任务状态、校验评审输入是否过期,并可一次结束阶段。以下完整字段和 record --strict 保留给已有脚本,不要求新流程手填。
|
|
4
|
+
|
|
3
5
|
收到实际评审结果后,必须把结果转换为 `check_result` 事件,并在 `stage_end` 之前执行成功。禁止用 stage_end 代替已执行评审的证据。程序预检阻断且未开展评审时,只记录阶段 failure 与真实原因,不伪造 reviewer 或零项评审。
|
|
4
6
|
|
|
5
7
|
字段口径:
|
|
@@ -21,7 +23,7 @@
|
|
|
21
23
|
- `categories`: 必须包含 `completeness`、`consistency`、`executability`、`tdd_compliance`;四类 total 合计等于顶层 total,四类未通过数合计等于 errors。算法正确性计入 consistency,文字报告单列,避免重复计数。
|
|
22
24
|
- `task_completion`: 复用本轮 `semantic-check --include-tasks` 的输出(使用 tasks-status 同一扫描器),只取模板中的计数字段;未进入 apply 时 `checked_for_archive_readiness=false`。
|
|
23
25
|
|
|
24
|
-
将评审结果写为 UTF-8 JSON:`skywalk-sdd/state/<变更名称>-check-<run-id>.json`,结构见 [result-template.json](result-template.json)。其中 `0` 是待替换位置,执行前换成本轮实测值,顶层 `total` 必须是大于 0 的整数。不要直接把安装目录中的模板传给命令(details
|
|
26
|
+
将评审结果写为 UTF-8 JSON:`skywalk-sdd/state/<变更名称>-check-<run-id>.json`,结构见 [result-template.json](result-template.json)。其中 `0` 是待替换位置,执行前换成本轮实测值,顶层 `total` 必须是大于 0 的整数。不要直接把安装目录中的模板传给命令(details 文件仅在校验、记录和投影成功后清理,失败保留)。
|
|
25
27
|
|
|
26
28
|
```bash
|
|
27
29
|
node "<spec-package>/skywalk-sdd/log.cjs" record --strict --type=check_result --command=check --project="<spec-package>" --change=<变更名称> --capability=<可选capability-name> --run-id=<本轮Check稳定ID> --agent=<Agent类型> --source=opsx-command --session-id=<父会话ID> --result=success/partial/failure --summary="检查结果摘要" --details-file=skywalk-sdd/state/<变更名称>-check-<run-id>.json
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"reviewer": {
|
|
3
|
+
"reviewer": "<实际评审者>",
|
|
4
|
+
"review_execution_mode": "subagent",
|
|
5
|
+
"reviewer_agent_id": "<真实子代理ID>",
|
|
6
|
+
"parent_session_id": "<主会话ID>",
|
|
7
|
+
"review_session_id": "<评审会话ID>",
|
|
8
|
+
"author_session_id": "<作者会话ID>",
|
|
9
|
+
"reviewer_independence": "independent-review",
|
|
10
|
+
"fallback_reason_code": null,
|
|
11
|
+
"fallback_reason": null
|
|
12
|
+
},
|
|
13
|
+
"items": [
|
|
14
|
+
{
|
|
15
|
+
"id": "<唯一检查项ID>",
|
|
16
|
+
"category": "consistency",
|
|
17
|
+
"status": "passed",
|
|
18
|
+
"evidence": "<实际文件:行号或锚点及检查依据>"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"warning_dispositions": []
|
|
22
|
+
}
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
#### 4.1 完整性检查
|
|
17
17
|
|
|
18
|
-
- [ ] proposal.md
|
|
18
|
+
- [ ] proposal.md 存在,实际业务意图、能力、范围与约束完整;不要求无关空章节
|
|
19
19
|
- [ ] 每个 Capability 都有 spec.md
|
|
20
20
|
- [ ] Full 模式每个 spec.md 都有对应 design.md,每个 design.md 都有对应 tasks.md;Simple 未生成这些文档不误报缺失
|
|
21
|
-
- [ ]
|
|
21
|
+
- [ ] 所有文档保留解析需要的 frontmatter、身份、锚点与关系,内容规模匹配实际变更
|
|
22
22
|
|
|
23
23
|
#### 4.2 一致性检查
|
|
24
24
|
|
|
@@ -93,8 +93,8 @@
|
|
|
93
93
|
|
|
94
94
|
## 返回给主 Agent
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
一次返回 [review-template.json](review-template.json) 的 items、检查范围和必要问题说明;身份由主 Agent 根据真实工具结果补齐。每项包含唯一 id、category、status、evidence。算法归入 consistency,不重复计数;不手算总数,不复述所有通过项,不复制文档全文。
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
至少有一个实际适用项。未执行项使用 na 并写原因,不能为计数填“全部通过”。任务状态由工具读取,不能伪造 reviewer 或独立性。主 Agent 无需为统计不匹配重新委派评审。
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
评审期间若发现文件变化,返回受影响路径。只读检查不修文档、不改代码。
|