kld-sdd 2.6.14 → 2.6.15
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 +7 -5
- package/lib/init.js +6 -0
- package/package.json +2 -2
- package/skywalk-sdd/index.cjs +936 -109
- package/skywalk-sdd/metrics-v3.cjs +103 -15
- package/skywalk-sdd/reporting/change-report-markdown.cjs +294 -0
- package/skywalk-sdd/reporting/change-report-model.cjs +170 -27
- package/skywalk-sdd/reporting/change-report-renderer.cjs +78 -154
- package/skywalk-sdd/reporting/change-report-view-model.cjs +340 -0
- package/templates/skills/kld-sdd/opsx-apply/reference.md +4 -2
- package/templates/skills/kld-sdd/opsx-archive/SKILL.md +1 -1
- package/templates/skills/kld-sdd/opsx-propose/SKILL.md +3 -3
- package/templates/skills/kld-sdd/opsx-propose/reference.md +6 -7
- package/templates/skills/kld-sdd/tdd-core/reference.md +3 -1
- package/templates/skills/kld-sdd/tdd-rules/rules/test-skeleton-telemetry.md +1 -1
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared change-report view model for Markdown / HTML / parity digests.
|
|
7
|
+
* Four desktop tabs: 概览 / 指标与阶段 / 问题与证据 / 产物与追溯
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const SECTION_ORDER = [
|
|
11
|
+
'overview',
|
|
12
|
+
'metrics-stages',
|
|
13
|
+
'issues-evidence',
|
|
14
|
+
'artifacts-trace',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const SECTION_TITLES = {
|
|
18
|
+
overview: '概览',
|
|
19
|
+
'metrics-stages': '指标与阶段',
|
|
20
|
+
'issues-evidence': '问题与证据',
|
|
21
|
+
'artifacts-trace': '产物与追溯',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function fractionText(verified, total) {
|
|
25
|
+
if (verified == null || total == null) return '暂无数据';
|
|
26
|
+
return `${verified}/${total}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function percentText(value, digits = 2) {
|
|
30
|
+
return Number.isFinite(Number(value))
|
|
31
|
+
? `${(Number(value) * 100).toFixed(digits)}%`
|
|
32
|
+
: '暂无数据';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function durationText(value) {
|
|
36
|
+
if (!Number.isFinite(Number(value))) return '暂无数据';
|
|
37
|
+
const totalSeconds = Math.round(Number(value) / 1000);
|
|
38
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
39
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
40
|
+
const seconds = totalSeconds % 60;
|
|
41
|
+
return [hours ? `${hours}小时` : '', minutes ? `${minutes}分` : '', `${seconds}秒`]
|
|
42
|
+
.filter(Boolean)
|
|
43
|
+
.join('');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function localTimeText(value) {
|
|
47
|
+
if (!value) return '—';
|
|
48
|
+
const parsed = new Date(value);
|
|
49
|
+
return Number.isNaN(parsed.getTime())
|
|
50
|
+
? '—'
|
|
51
|
+
: parsed.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function buildSemanticDigestInput(report, sections) {
|
|
55
|
+
const audit = report.task_evidence_audit || {};
|
|
56
|
+
const tdd = report.tdd_pair_audit || {};
|
|
57
|
+
const changed = report.changed_files || {};
|
|
58
|
+
const evidence = report.change_summary?.evidence || {};
|
|
59
|
+
const artifacts = report.artifacts?.files || {};
|
|
60
|
+
return {
|
|
61
|
+
schema_version: report.schema_version || null,
|
|
62
|
+
metrics_contract: report.metrics_contract || null,
|
|
63
|
+
change: report.change || null,
|
|
64
|
+
section_ids: SECTION_ORDER.slice(),
|
|
65
|
+
conclusion_status: report.conclusion?.status || null,
|
|
66
|
+
tasks: {
|
|
67
|
+
document: report.change_summary?.tasks?.document || null,
|
|
68
|
+
direct_test_backlink: audit.direct_test_backlink || null,
|
|
69
|
+
strict_test_coverage: audit.strict_test_coverage || null,
|
|
70
|
+
traceability: report.change_summary?.tasks?.traceability || null,
|
|
71
|
+
},
|
|
72
|
+
tdd_pairs: {
|
|
73
|
+
required: tdd.required ?? null,
|
|
74
|
+
complete: tdd.complete ?? null,
|
|
75
|
+
},
|
|
76
|
+
tests: report.change_summary?.tests || null,
|
|
77
|
+
evidence: {
|
|
78
|
+
category_count: evidence.category_count ?? null,
|
|
79
|
+
occurrence_count: evidence.occurrence_count ?? null,
|
|
80
|
+
issues: (evidence.issues || []).map((issue) => ({
|
|
81
|
+
issue_id: issue.issue_id,
|
|
82
|
+
code: issue.code,
|
|
83
|
+
status: issue.status,
|
|
84
|
+
verdict: issue.verdict,
|
|
85
|
+
subject: issue.subject,
|
|
86
|
+
expected: issue.expected,
|
|
87
|
+
actual: issue.actual,
|
|
88
|
+
root_cause: issue.root_cause,
|
|
89
|
+
remediation: issue.remediation,
|
|
90
|
+
evidence_event_ids: issue.evidence_event_ids,
|
|
91
|
+
disposition: issue.disposition,
|
|
92
|
+
})),
|
|
93
|
+
},
|
|
94
|
+
changed_files: {
|
|
95
|
+
task_event_files_changed: changed.task_event_files_changed ?? null,
|
|
96
|
+
final_output_files_changed: changed.final_output_files_changed ?? null,
|
|
97
|
+
added_lines: changed.added_lines ?? null,
|
|
98
|
+
deleted_lines: changed.deleted_lines ?? null,
|
|
99
|
+
diff_source: changed.diff_source ?? null,
|
|
100
|
+
reconciliation_status: changed.reconciliation_status ?? null,
|
|
101
|
+
},
|
|
102
|
+
attribution: report.attribution_audit || null,
|
|
103
|
+
artifact_sizes: Object.fromEntries(
|
|
104
|
+
Object.entries(artifacts).map(([name, item]) => [name, item?.size_bytes ?? null]),
|
|
105
|
+
),
|
|
106
|
+
section_summaries: Object.fromEntries(
|
|
107
|
+
SECTION_ORDER.map((id) => [id, sections[id]?.summary || null]),
|
|
108
|
+
),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function buildChangeReportViewModel(report = {}) {
|
|
113
|
+
const summary = report.change_summary || {};
|
|
114
|
+
const audit = report.task_evidence_audit || {};
|
|
115
|
+
const tdd = report.tdd_pair_audit || {};
|
|
116
|
+
const changed = report.changed_files || {};
|
|
117
|
+
const evidence = summary.evidence || { categories: [], category_count: 0, occurrence_count: 0 };
|
|
118
|
+
const artifacts = report.artifacts?.files || {};
|
|
119
|
+
const metrics = report.metrics || {};
|
|
120
|
+
const efficiency = metrics.efficiency || {};
|
|
121
|
+
const quality = metrics.quality || {};
|
|
122
|
+
const process = metrics.process || {};
|
|
123
|
+
const telemetry = metrics.telemetry_health || {};
|
|
124
|
+
const minSet = report.minimum_metric_set || {};
|
|
125
|
+
const openIssueCount = (report.evidence_alerts?.open || []).length;
|
|
126
|
+
const totalDurationMs = efficiency.total_duration_ms
|
|
127
|
+
?? efficiency.effective_stage_duration_including_rework_ms
|
|
128
|
+
?? efficiency.e1_lead_time_ms
|
|
129
|
+
?? null;
|
|
130
|
+
const e1 = efficiency.e1_scenario_delivery_efficiency_ms ?? null;
|
|
131
|
+
const e2 = efficiency.e2_coding_time_ratio_including_rework
|
|
132
|
+
?? efficiency.e2_coding_time_ratio
|
|
133
|
+
?? null;
|
|
134
|
+
const e3 = efficiency.e3_spec_time_ratio_including_rework
|
|
135
|
+
?? efficiency.e3_spec_time_ratio
|
|
136
|
+
?? null;
|
|
137
|
+
const metricCards = [
|
|
138
|
+
{
|
|
139
|
+
name: '每个场景平均用时',
|
|
140
|
+
code: 'E1',
|
|
141
|
+
value: Number.isFinite(e1) ? `${durationText(e1)} / 场景` : '暂无数据',
|
|
142
|
+
state: (
|
|
143
|
+
minSet.evidence_status?.e1 === 'trusted'
|
|
144
|
+
|| minSet.trusted_metrics?.includes?.('e1')
|
|
145
|
+
|| minSet.trusted?.includes?.('e1')
|
|
146
|
+
) ? '可信' : '需补证',
|
|
147
|
+
explanation: '七个标准阶段总耗时(含返工)÷ 验收场景数。',
|
|
148
|
+
source: `公式:标准阶段总耗时 ÷ 场景数。场景数:${efficiency.scenario_count ?? '未知'};当前值:${e1 ?? '不可计算'} ms。`,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: '规约检查得分',
|
|
152
|
+
code: 'Q3',
|
|
153
|
+
value: quality.q3_spec_quality_score == null ? '暂无数据' : `${quality.q3_spec_quality_score} / 100`,
|
|
154
|
+
state: quality.q3_score_status === 'verified' ? '已验证' : '临时',
|
|
155
|
+
explanation: '最新规约检查结果;独立复核后才标记为已验证。',
|
|
156
|
+
source: `评审独立性:${quality.q3_reviewer_independence || '未知'};证据状态:${quality.q3_score_status || '未知'}。`,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: '编码前是否先检查',
|
|
160
|
+
code: 'P4',
|
|
161
|
+
value: percentText(process.p4_quality_gate_enforcement_rate),
|
|
162
|
+
state: Number.isFinite(process.p4_quality_gate_enforcement_rate) ? '可计算' : '需补证',
|
|
163
|
+
explanation: '首次进入编码前,是否存在已配对且成功或部分通过的检查。',
|
|
164
|
+
source: '只接受能与 check 开始事件配对、且发生在首次 apply 之前的成功或部分通过结果。',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: '阶段重复次数',
|
|
168
|
+
code: 'P-R',
|
|
169
|
+
value: process.rework_summary?.total_rework_attempts == null
|
|
170
|
+
? '暂无数据'
|
|
171
|
+
: `${process.rework_summary.total_rework_attempts} 次`,
|
|
172
|
+
state: process.rework_summary ? '可计算' : '需补证',
|
|
173
|
+
explanation: '七个标准阶段中,首次执行之后的重复尝试次数。',
|
|
174
|
+
source: '辅助 test / explore 阶段不计入标准阶段重复总数。',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: '执行记录是否完整',
|
|
178
|
+
code: 'P-H',
|
|
179
|
+
value: telemetry.p_h_telemetry_health_score == null
|
|
180
|
+
? '暂无数据'
|
|
181
|
+
: `${telemetry.p_h_telemetry_health_score} / 100`,
|
|
182
|
+
state: telemetry.p_h_telemetry_health_score == null ? '需补证' : '可计算',
|
|
183
|
+
explanation: '标准阶段的身份、开始结束配对和数据质量综合评分。',
|
|
184
|
+
source: '沿用既有权重,但只以 propose、spec、design、task、check、apply、archive 七阶段为计算范围。',
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
const sections = {
|
|
189
|
+
overview: {
|
|
190
|
+
id: 'overview',
|
|
191
|
+
title: SECTION_TITLES.overview,
|
|
192
|
+
summary: report.conclusion?.text || '当前证据不足,暂不能形成可信结论。',
|
|
193
|
+
scope_duration: durationText(totalDurationMs),
|
|
194
|
+
cards: [
|
|
195
|
+
{
|
|
196
|
+
key: 'final_tests',
|
|
197
|
+
label: '最终测试',
|
|
198
|
+
value: fractionText(summary.tests?.passed, summary.tests?.total),
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
key: 'document_tasks',
|
|
202
|
+
label: '文档任务完成',
|
|
203
|
+
value: fractionText(summary.tasks?.document?.completed, summary.tasks?.document?.total),
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
key: 'direct_backlink',
|
|
207
|
+
label: '直接测试回链',
|
|
208
|
+
value: fractionText(
|
|
209
|
+
audit.direct_test_backlink?.verified,
|
|
210
|
+
audit.direct_test_backlink?.total,
|
|
211
|
+
),
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
key: 'strict_coverage',
|
|
215
|
+
label: '严格测试覆盖',
|
|
216
|
+
value: fractionText(
|
|
217
|
+
audit.strict_test_coverage?.verified ?? summary.tasks?.traceability?.verified,
|
|
218
|
+
audit.strict_test_coverage?.total ?? summary.tasks?.traceability?.total,
|
|
219
|
+
),
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
key: 'open_issues',
|
|
223
|
+
label: '开放证据问题',
|
|
224
|
+
value: String(openIssueCount),
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
metric_cards: metricCards,
|
|
228
|
+
},
|
|
229
|
+
'metrics-stages': {
|
|
230
|
+
id: 'metrics-stages',
|
|
231
|
+
title: SECTION_TITLES['metrics-stages'],
|
|
232
|
+
summary: '本次变更效率、质量、过程与阶段执行',
|
|
233
|
+
metrics: {
|
|
234
|
+
total_duration_ms: totalDurationMs,
|
|
235
|
+
e1,
|
|
236
|
+
e2,
|
|
237
|
+
e3,
|
|
238
|
+
q3: quality.q3_spec_quality_score ?? null,
|
|
239
|
+
p4: process.p4_quality_gate_enforcement_rate ?? null,
|
|
240
|
+
p_r: process.rework_summary?.total_rework_attempts ?? null,
|
|
241
|
+
p_h: telemetry.p_h_telemetry_health_score ?? null,
|
|
242
|
+
},
|
|
243
|
+
metric_cards: metricCards,
|
|
244
|
+
metric_rows: [
|
|
245
|
+
{ label: '七阶段总耗时', value: durationText(totalDurationMs) },
|
|
246
|
+
{ label: '每个场景平均用时', code: 'E1', value: metricCards[0].value },
|
|
247
|
+
{ label: '编码时间占比', code: 'E2', value: percentText(e2) },
|
|
248
|
+
{ label: '规划与规约时间占比', code: 'E3', value: percentText(e3) },
|
|
249
|
+
{ label: '阶段重复执行', code: 'P-R', value: metricCards[3].value },
|
|
250
|
+
],
|
|
251
|
+
stages: (report.stage_timeline?.nodes || []).map((node) => ({
|
|
252
|
+
...node,
|
|
253
|
+
display_stage: node.stage || node.command || '未知阶段',
|
|
254
|
+
display_round: node.round || 1,
|
|
255
|
+
display_start: localTimeText(node.start_ts),
|
|
256
|
+
display_end: localTimeText(node.end_ts),
|
|
257
|
+
display_duration: durationText(node.duration_ms),
|
|
258
|
+
display_result: node.result || '未知',
|
|
259
|
+
})),
|
|
260
|
+
tdd_pairs: {
|
|
261
|
+
required: tdd.required ?? null,
|
|
262
|
+
complete: tdd.complete ?? null,
|
|
263
|
+
pairs: tdd.pairs || [],
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
'issues-evidence': {
|
|
267
|
+
id: 'issues-evidence',
|
|
268
|
+
title: SECTION_TITLES['issues-evidence'],
|
|
269
|
+
summary: evidence.note
|
|
270
|
+
|| `${evidence.category_count || 0} 类问题,${evidence.occurrence_count || 0} 次规则命中`,
|
|
271
|
+
categories: evidence.categories || [],
|
|
272
|
+
issues: evidence.issues || [],
|
|
273
|
+
open_alerts: report.evidence_alerts?.open || [],
|
|
274
|
+
task_evidence_audit: audit,
|
|
275
|
+
apply_findings: report.apply_evidence_audit?.findings || [],
|
|
276
|
+
warning_dispositions: report.warning_dispositions || [],
|
|
277
|
+
},
|
|
278
|
+
'artifacts-trace': {
|
|
279
|
+
id: 'artifacts-trace',
|
|
280
|
+
title: SECTION_TITLES['artifacts-trace'],
|
|
281
|
+
summary: changed.reconciliation_note || '产物与文件对账',
|
|
282
|
+
changed_files: {
|
|
283
|
+
task_event_files_changed: changed.task_event_files_changed ?? null,
|
|
284
|
+
final_output_files_changed: changed.final_output_files_changed ?? null,
|
|
285
|
+
added_lines: changed.added_lines ?? null,
|
|
286
|
+
deleted_lines: changed.deleted_lines ?? null,
|
|
287
|
+
diff_source: changed.diff_source || null,
|
|
288
|
+
reconciliation_status: changed.reconciliation_status ?? null,
|
|
289
|
+
reconciliation_note: changed.reconciliation_note || null,
|
|
290
|
+
final_output_files: changed.final_output_files || changed.files || null,
|
|
291
|
+
only_in_task_events: changed.only_in_task_events || [],
|
|
292
|
+
only_in_final_output: changed.only_in_final_output || [],
|
|
293
|
+
},
|
|
294
|
+
artifacts: Object.entries(artifacts).map(([name, item]) => ({
|
|
295
|
+
name,
|
|
296
|
+
path: item?.path || null,
|
|
297
|
+
exists: Boolean(item?.exists),
|
|
298
|
+
size_bytes: item?.size_bytes ?? null,
|
|
299
|
+
size_display: item?.size_display || null,
|
|
300
|
+
sha256: item?.sha256 ?? null,
|
|
301
|
+
integrity_note: item?.integrity_note || null,
|
|
302
|
+
})),
|
|
303
|
+
attribution: report.attribution_audit || null,
|
|
304
|
+
attribution_summary: {
|
|
305
|
+
linked_source_event_count: report.attribution_audit?.linked_source_event_count ?? 0,
|
|
306
|
+
active_link_count: report.attribution_audit?.active_links?.length ?? 0,
|
|
307
|
+
unassigned_candidate_count: report.attribution_audit?.unassigned_candidate_event_ids?.length ?? 0,
|
|
308
|
+
rejected_collision_count: report.attribution_audit?.rejected_direct_collision_event_ids?.length ?? 0,
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
change: report.change || null,
|
|
315
|
+
schema_version: report.schema_version || null,
|
|
316
|
+
metrics_contract: report.metrics_contract || null,
|
|
317
|
+
generated_at: report.generated_at || null,
|
|
318
|
+
conclusion: report.conclusion || null,
|
|
319
|
+
minimum_metric_set: report.minimum_metric_set || null,
|
|
320
|
+
scheme_compliance: report.scheme_compliance || null,
|
|
321
|
+
known_risks: report.known_risks || null,
|
|
322
|
+
process_notes: report.process_notes || null,
|
|
323
|
+
telemetry_warnings: report.telemetry_warnings || null,
|
|
324
|
+
archive_result: report.archive_result || null,
|
|
325
|
+
report_scope: report.report_scope || null,
|
|
326
|
+
section_order: SECTION_ORDER.slice(),
|
|
327
|
+
sections,
|
|
328
|
+
semantic_digest_input: buildSemanticDigestInput(report, sections),
|
|
329
|
+
semantic_digest: crypto.createHash('sha256')
|
|
330
|
+
.update(JSON.stringify(buildSemanticDigestInput(report, sections)))
|
|
331
|
+
.digest('hex'),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
module.exports = {
|
|
336
|
+
SECTION_ORDER,
|
|
337
|
+
SECTION_TITLES,
|
|
338
|
+
buildChangeReportViewModel,
|
|
339
|
+
buildSemanticDigestInput,
|
|
340
|
+
};
|
|
@@ -17,10 +17,12 @@ description: opsx-apply 的详细模板:telemetry 命令、worktree 全套策
|
|
|
17
17
|
### task_update(每完成一个任务记录)
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=task_update --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --run-id=<本次任务更新稳定ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=completed --result=success --summary="<TASK-ID> 完成" --details-json="{\"task_update\":{\"test_event_id\":\"<同一change内成功test_result的event_id>\",\"tdd_required\":<true|false
|
|
20
|
+
node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=task_update --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --run-id=<本次任务更新稳定ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=completed --result=success --summary="<TASK-ID> 完成" --details-json="{\"task_update\":{\"test_event_id\":\"<同一change内成功test_result的event_id>\",\"tdd_required\":<true|false>,\"tdd_pair_id\":\"<pair-N>\",\"tdd_role\":\"green\"},\"files_changed\":[]}"
|
|
21
|
+
|
|
22
|
+
也可互斥使用 `test_run_id`(同 change、覆盖当前任务、唯一严格完成候选);解析成功后会补齐规范化 `test_event_id`。
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
**⚠️ 注意**:`--task-id=<TASK-ID>` 必须替换为实际任务 ID。完成任务必须引用同一 change 内、`tdd_phase` 为 green/refactor/regression、退出码为 0、`failure_type=none` 的 `test_result.event_id
|
|
25
|
+
**⚠️ 注意**:`--task-id=<TASK-ID>` 必须替换为实际任务 ID。完成任务必须引用同一 change 内、`tdd_phase` 为 green/refactor/regression、退出码为 0、`failure_type=none` 的 `test_result.event_id`(或可唯一解析的 `test_run_id`),并明确填写 `tdd_required=true/false`;TDD 任务应写同一 `tdd_pair_id` 与 `tdd_role`;禁止把测试计数复制进 `task_update`。
|
|
24
26
|
|
|
25
27
|
只有文档、纯配置说明等确实不适用测试的任务,才能显式声明:
|
|
26
28
|
|
|
@@ -112,7 +112,7 @@ node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" tasks-status --project=. --chan
|
|
|
112
112
|
```json
|
|
113
113
|
{
|
|
114
114
|
"maturity_evidence": {
|
|
115
|
-
"change_type": "config|
|
|
115
|
+
"change_type": "config|transaction|report|composite",
|
|
116
116
|
"e1_actual_ms": 500,
|
|
117
117
|
"e1_target_ms": 600,
|
|
118
118
|
"e1_type_target_met": true,
|
|
@@ -272,7 +272,7 @@ Read openspec/changes/archive/*/ontology/ontology-identities.json
|
|
|
272
272
|
|
|
273
273
|
**❗ 必须主动询问用户,不得默认选择**。在模式与测试策略选择附近,基于需求给出 `change-type` **推荐**并让用户确认;Auto 只能推荐,**禁止无提示静默写入**。
|
|
274
274
|
|
|
275
|
-
允许值固定为:`config |
|
|
275
|
+
允许值固定为:`config | transaction | report | composite`(写入 proposal.md YAML frontmatter 的 `change-type` 字段)。AskUserQuestion 文案与类型说明见 `./reference.md`「§7.5 变更类型选择」。
|
|
276
276
|
|
|
277
277
|
### 8. 【交互引导】测试策略选择
|
|
278
278
|
|
|
@@ -340,11 +340,11 @@ Read openspec/changes/archive/*/ontology/ontology-identities.json
|
|
|
340
340
|
- **⛔ 阶段边界**:本阶段禁止执行任何代码创建/修改操作。若用户要求处理代码,回复:「当前处于 Propose 阶段,代码操作请在完成文档后使用 `/opsx-apply` 执行。」
|
|
341
341
|
- **⛔ 单阶段原则**:完成 proposal.md 后必须立即停止。仅提示用户下一步可运行 `/opsx-spec`,绝对禁止自动执行 spec/design/task 等后续阶段。每个阶段必须由用户主动触发。
|
|
342
342
|
- **⛔ Frontmatter 规范(L7)**:YAML frontmatter 中禁止写 `#` 注释(YAML 注释在 frontmatter 中可能导致解析问题)。如需说明,在 frontmatter 之前或之后用正文描述。
|
|
343
|
-
- **⛔ change-type 必采**:frontmatter 必须含 `change-type`,取值仅限 `config |
|
|
343
|
+
- **⛔ change-type 必采**:frontmatter 必须含 `change-type`,取值仅限 `config | transaction | report | composite`;Agent 可推荐但须经用户确认后写入,禁止静默默认。
|
|
344
344
|
|
|
345
345
|
---
|
|
346
346
|
|
|
347
347
|
## 渐进披露
|
|
348
348
|
|
|
349
349
|
- Read `checklist.md` 仅在执行 propose 需要校验时 — 含阶段边界⛔(Propose 阶段约束)、§6 需求完整性检查、Guardrails ⛔ 强制项勾选表。
|
|
350
|
-
- Read `reference.md` 仅在需要参考详细模板时 — 含 📊 Telemetry 命令模板(start/end)、§7 文档拆分模式(Full/Simple/Auto)、§7.5 变更类型(config/
|
|
350
|
+
- Read `reference.md` 仅在需要参考详细模板时 — 含 📊 Telemetry 命令模板(start/end)、§7 文档拆分模式(Full/Simple/Auto)、§7.5 变更类型(config/transaction/report/composite)、§8 测试策略(TDD/Impl-First/None)、§10 质量红线自检清单(8 项)。
|
|
@@ -56,20 +56,19 @@ description: opsx-propose 的详细模板:telemetry 命令、文档拆分模
|
|
|
56
56
|
|
|
57
57
|
> "📊 **变更类型(用于 V3 指标分层统计)**
|
|
58
58
|
>
|
|
59
|
-
> 根据本次需求,推荐类型:**[config |
|
|
59
|
+
> 根据本次需求,推荐类型:**[config | transaction | report | composite]** — [一句话理由]
|
|
60
60
|
>
|
|
61
61
|
> 请选择或确认:
|
|
62
62
|
> - **config** — 配置/开关/环境/依赖调整,几乎不改业务逻辑
|
|
63
|
-
> - **
|
|
64
|
-
> - **report** —
|
|
63
|
+
> - **transaction** — 单据类:业务流程、状态流转、CRUD/交易路径变更
|
|
64
|
+
> - **report** — 报表类:报表查询、度量展示、采集契约(不是“度量报告工具”本身的专属类型)
|
|
65
65
|
> - **composite** — 跨多类能力的组合变更
|
|
66
|
-
> - **other** — 以上均不合适时使用
|
|
67
66
|
>
|
|
68
67
|
> A) 采用推荐 B) 手动选择其他类型"
|
|
69
68
|
|
|
70
|
-
根据用户确认,在 proposal.md YAML frontmatter 写入 `change-type: <值>`。允许值固定:`config |
|
|
69
|
+
根据用户确认,在 proposal.md YAML frontmatter 写入 `change-type: <值>`。允许值固定:`config | transaction | report | composite`。
|
|
71
70
|
|
|
72
|
-
> 历史 proposal
|
|
71
|
+
> 历史 proposal 的 `document`/`other` 读取侧迁移为 `unknown` 并告警,不写入新 proposal;本阶段不得替用户猜测补写。
|
|
73
72
|
|
|
74
73
|
---
|
|
75
74
|
|
|
@@ -107,6 +106,6 @@ description: opsx-propose 的详细模板:telemetry 命令、文档拆分模
|
|
|
107
106
|
- [ ] 前置依赖使用 checkbox 格式
|
|
108
107
|
- [ ] 文档末尾包含质量红线检查清单
|
|
109
108
|
- [ ] 能力分解章节已明确(决定后续 specs 文件夹结构)
|
|
110
|
-
- [ ] frontmatter 含 `change-type`,取值为 `config |
|
|
109
|
+
- [ ] frontmatter 含 `change-type`,取值为 `config | transaction | report | composite` 之一且经用户确认
|
|
111
110
|
|
|
112
111
|
**如有任意一项未满足,重新生成对应章节,直至全部通过。**
|
|
@@ -129,7 +129,9 @@ node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=test_res
|
|
|
129
129
|
**实现任务**(不带 `task_kind`):
|
|
130
130
|
|
|
131
131
|
```bash
|
|
132
|
-
node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=task_update --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --run-id=<任务更新稳定ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=completed --result=success --summary="<TASK-ID> 完成" --details-json='{"files_changed":[],"task_update":{"test_event_id":"<成功的green/refactor测试event_id>","tdd_required":true}}'
|
|
132
|
+
node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=task_update --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --run-id=<任务更新稳定ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=completed --result=success --summary="<TASK-ID> 完成" --details-json='{"files_changed":[],"task_update":{"test_event_id":"<成功的green/refactor测试event_id>","tdd_required":true,"tdd_pair_id":"<pair-N>","tdd_role":"green"}}'
|
|
133
|
+
|
|
134
|
+
> RED/GREEN 同对必须写相同 `tdd_pair_id`;也可用互斥的 `test_run_id`(唯一严格完成候选)代替 `test_event_id`。
|
|
133
135
|
```
|
|
134
136
|
|
|
135
137
|
## §9 单元测试真实执行
|
|
@@ -15,5 +15,5 @@ node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=test_res
|
|
|
15
15
|
实现任务不带 `task_kind`(默认 implementation),按真实测试结果记录。
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=task_update --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --run-id=<任务更新稳定ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=completed --result=success --summary="<TASK-ID> 完成" --details-json='{"files_changed":[],"task_update":{"test_event_id":"<成功的green/refactor测试event_id>","tdd_required":true}}'
|
|
18
|
+
node "$(cat .sdd-spec-root)/skywalk-sdd/log.cjs" record --strict --type=task_update --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --run-id=<任务更新稳定ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=completed --result=success --summary="<TASK-ID> 完成" --details-json='{"files_changed":[],"task_update":{"test_event_id":"<成功的green/refactor测试event_id>","tdd_required":true,"tdd_pair_id":"<pair-N>","tdd_role":"green"}}'
|
|
19
19
|
```
|