@xulthekl/team-flow 0.30.0 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/always/phase-guard.md +1 -1
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +2 -2
- package/.cursor-plugin/marketplace.json +2 -2
- package/.cursor-plugin/plugin.json +2 -2
- package/.github/plugin/marketplace.json +2 -2
- package/AGENTS.md +5 -4
- package/CHANGELOG.md +85 -0
- package/GEMINI.md +1 -1
- package/HANDOFF.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +3 -3
- package/agents/build-executor.md +1 -0
- package/agents/contract-builder.md +6 -1
- package/docs/README_en.md +1 -1
- package/docs/solutions/INDEX.md +2 -0
- package/docs/solutions/cross-phase/2026-08-01-no-summary.md +17 -0
- package/docs/solutions/cross-phase/2026-08-03-no-summary.md +17 -0
- package/gemini-extension.json +2 -2
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +6 -2
- package/plugin.json +2 -2
- package/scripts/guard/checks/test-gate-exemptions.mjs +53 -0
- package/scripts/guard/checks/test-matrix-complete.mjs +91 -0
- package/scripts/guard/checks/test-matrix-ready.mjs +60 -0
- package/scripts/guard/checks/tests-passing.mjs +112 -24
- package/scripts/guard/guard.mjs +10 -2
- package/scripts/lib/cmd-doctor.mjs +43 -1
- package/scripts/lib/cmd-execution.mjs +24 -1
- package/scripts/lib/cmd-state.mjs +33 -5
- package/scripts/lib/cmd-validate.mjs +42 -0
- package/scripts/lib/execution-plan.mjs +23 -0
- package/scripts/lib/hash.mjs +11 -0
- package/scripts/lib/state-loader.mjs +26 -1
- package/scripts/lib/test-matrix-export.mjs +231 -0
- package/scripts/lib/test-merge.mjs +540 -0
- package/scripts/lib/test-record.mjs +212 -0
- package/scripts/team-flow.mjs +9 -0
- package/skills/build-executor/implementer-prompt.md +38 -3
- package/skills/code-reviewer/SKILL.md +28 -1
- package/skills/code-reviewer/code-reviewer-prompt.md +10 -0
- package/skills/contract-builder/SKILL.md +75 -0
- package/skills/release-archivist/SKILL.md +50 -10
- package/skills/session-handoff/SKILL.md +1 -0
- package/skills/spec-writer/SKILL.md +3 -1
- package/skills/test-strategy/SKILL.md +70 -0
- package/skills/test-strategy/references/adversarial-patterns.md +0 -0
- package/skills/test-strategy/references/complexity-grading.md +137 -0
- package/skills/test-strategy/references/design-methods-detail.md +183 -0
- package/skills/workflow-orchestrator/references/s1-path-router.md +4 -0
- package/skills/workflow-start/SKILL.md +5 -3
- package/skills/workflow-start/references/routing-rules.md +21 -0
- package/tests/e2e.test.mjs +0 -266
- package/tests/lib/cmd-audit.test.mjs +0 -202
- package/tests/lib/cmd-checkpoint.test.mjs +0 -98
- package/tests/lib/cmd-config.test.mjs +0 -101
- package/tests/lib/cmd-doctor.test.mjs +0 -450
- package/tests/lib/cmd-execution.test.mjs +0 -647
- package/tests/lib/cmd-handoff.test.mjs +0 -137
- package/tests/lib/cmd-inject.test.mjs +0 -218
- package/tests/lib/cmd-install-workbuddy.test.mjs +0 -113
- package/tests/lib/cmd-install-zcode.test.mjs +0 -42
- package/tests/lib/cmd-isolate.test.mjs +0 -68
- package/tests/lib/cmd-list.test.mjs +0 -127
- package/tests/lib/cmd-runtime.test.mjs +0 -83
- package/tests/lib/cmd-state-missing.test.mjs +0 -65
- package/tests/lib/cmd-state.test.mjs +0 -365
- package/tests/lib/cmd-sync-paths.test.mjs +0 -84
- package/tests/lib/cmd-validate-paths.test.mjs +0 -90
- package/tests/lib/config-loader.test.mjs +0 -175
- package/tests/lib/ensure-branch.test.mjs +0 -110
- package/tests/lib/execution-control-plane.test.mjs +0 -168
- package/tests/lib/execution-plan.test.mjs +0 -474
- package/tests/lib/guard-compound-captured.test.mjs +0 -92
- package/tests/lib/guard-specs-merged.test.mjs +0 -110
- package/tests/lib/guard-tests-passing.test.mjs +0 -114
- package/tests/lib/guard-transitions.test.mjs +0 -262
- package/tests/lib/guard.test.mjs +0 -613
- package/tests/lib/hash.test.mjs +0 -138
- package/tests/lib/infer-workflow.test.mjs +0 -161
- package/tests/lib/install-git-hooks.test.mjs +0 -20
- package/tests/lib/marketplace-release-docs.test.mjs +0 -31
- package/tests/lib/minimality-discipline.test.mjs +0 -37
- package/tests/lib/model-profiles-docs.test.mjs +0 -33
- package/tests/lib/node20-compatibility.test.mjs +0 -73
- package/tests/lib/node20-test-entry.test.mjs +0 -17
- package/tests/lib/platform-runtime-distribution.test.mjs +0 -157
- package/tests/lib/raw-mode-smoke.test.mjs +0 -42
- package/tests/lib/sdd-overlay.test.mjs +0 -118
- package/tests/lib/solutions-capture.test.mjs +0 -108
- package/tests/lib/solutions-index-gen.test.mjs +0 -147
- package/tests/lib/solutions-inject.test.mjs +0 -115
- package/tests/lib/solutions-promote.test.mjs +0 -200
- package/tests/lib/spec-paths.test.mjs +0 -80
- package/tests/lib/state-loader.test.mjs +0 -251
- package/tests/lib/token-baseline.test.mjs +0 -72
- package/tests/lib/token-rules.test.mjs +0 -94
- package/tests/lib/verify-marketplace-release.test.mjs +0 -128
- package/tests/tsconfig.json +0 -12
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// scripts/lib/test-record.mjs — tf test record:程序化测试证据记录(v0.13 §50)
|
|
2
|
+
//
|
|
3
|
+
// 设计增强方案 v0.13 §50(BUG-A 政策修正):tests-passing 门禁锚定客观证据,
|
|
4
|
+
// 不再锚定 LLM 自述。本命令解析主流测试 runner 的输出,把结构化结果写入
|
|
5
|
+
// state.test_result(recorded-by=tf-test-record),并把原始输出落盘为证据文件。
|
|
6
|
+
// 不提供手工自述通道(--manual):确无自动化测试的 change 的合法出路是
|
|
7
|
+
// 显式 skip(test_matrix_skipped=true + test_matrix_skip_reason),可审计、可巡检。
|
|
8
|
+
//
|
|
9
|
+
// 扩展性:新增 runner 只需在 PARSERS 注册表加一个解析器(零依赖)。
|
|
10
|
+
import { parseArgs } from 'node:util';
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import path, { join } from 'node:path';
|
|
13
|
+
import { readState, writeState } from './state-loader.mjs';
|
|
14
|
+
|
|
15
|
+
export const SUPPORTED_RUNNERS = ['maven-surefire', 'jest', 'pytest'];
|
|
16
|
+
|
|
17
|
+
// ── 解析器(全部返回 { total, passed, failed, skipped } 或 null)────────────
|
|
18
|
+
|
|
19
|
+
/** maven surefire 控制台汇总行(多模块累加):"Tests run: 42, Failures: 0, Errors: 0, Skipped: 2" */
|
|
20
|
+
export function parseMavenSurefire(text) {
|
|
21
|
+
const re = /Tests run:\s*(\d+),\s*Failures:\s*(\d+),\s*Errors:\s*(\d+),\s*Skipped:\s*(\d+)/g;
|
|
22
|
+
let m;
|
|
23
|
+
let total = 0; let failures = 0; let errors = 0; let skipped = 0;
|
|
24
|
+
let found = false;
|
|
25
|
+
while ((m = re.exec(text)) !== null) {
|
|
26
|
+
found = true;
|
|
27
|
+
total += parseInt(m[1], 10);
|
|
28
|
+
failures += parseInt(m[2], 10);
|
|
29
|
+
errors += parseInt(m[3], 10);
|
|
30
|
+
skipped += parseInt(m[4], 10);
|
|
31
|
+
}
|
|
32
|
+
if (!found) return null;
|
|
33
|
+
return { total, passed: total - failures - errors - skipped, failed: failures + errors, skipped };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** maven surefire XML 报告目录(target/surefire-reports):累加 <testsuite> 属性。 */
|
|
37
|
+
export function parseSurefireReportDir(dir) {
|
|
38
|
+
let total = 0; let failures = 0; let errors = 0; let skipped = 0;
|
|
39
|
+
let found = false;
|
|
40
|
+
for (const name of readdirSync(dir)) {
|
|
41
|
+
if (!name.endsWith('.xml')) continue;
|
|
42
|
+
const content = readFileSync(join(dir, name), 'utf-8');
|
|
43
|
+
for (const tag of content.matchAll(/<testsuite\b[^>]*>/g)) {
|
|
44
|
+
const attrs = tag[0];
|
|
45
|
+
const pick = (key) => {
|
|
46
|
+
const am = attrs.match(new RegExp(`\\b${key}="(\\d+)"`));
|
|
47
|
+
return am ? parseInt(am[1], 10) : 0;
|
|
48
|
+
};
|
|
49
|
+
found = true;
|
|
50
|
+
total += pick('tests');
|
|
51
|
+
failures += pick('failures');
|
|
52
|
+
errors += pick('errors');
|
|
53
|
+
skipped += pick('skipped');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!found) return null;
|
|
57
|
+
return { total, passed: total - failures - errors - skipped, failed: failures + errors, skipped };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** jest --json 输出。 */
|
|
61
|
+
export function parseJest(text) {
|
|
62
|
+
let data;
|
|
63
|
+
try { data = JSON.parse(text); } catch { return null; }
|
|
64
|
+
if (typeof data?.numTotalTests !== 'number') return null;
|
|
65
|
+
const total = data.numTotalTests;
|
|
66
|
+
const failed = data.numFailedTests ?? 0;
|
|
67
|
+
const passed = data.numPassedTests ?? 0;
|
|
68
|
+
const skipped = (data.numPendingTests ?? 0) + (data.numTodoTests ?? 0);
|
|
69
|
+
return { total, passed, failed, skipped };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** pytest terminal summary:"== 5 passed, 2 failed, 1 skipped in 3.21s ==" */
|
|
73
|
+
export function parsePytest(text) {
|
|
74
|
+
const lines = text.split('\n');
|
|
75
|
+
const summaryLine = [...lines].reverse().find(l => /=+\s.*(passed|failed|error|no tests ran)/.test(l));
|
|
76
|
+
if (!summaryLine) return null;
|
|
77
|
+
const pick = (label) => {
|
|
78
|
+
const m = summaryLine.match(new RegExp(`(\\d+)\\s+${label}`));
|
|
79
|
+
return m ? parseInt(m[1], 10) : 0;
|
|
80
|
+
};
|
|
81
|
+
if (/no tests ran/.test(summaryLine)) return { total: 0, passed: 0, failed: 0, skipped: 0 };
|
|
82
|
+
const passed = pick('passed') + pick('xpassed');
|
|
83
|
+
const failed = pick('failed') + pick('error');
|
|
84
|
+
const skipped = pick('skipped') + pick('xfailed');
|
|
85
|
+
const total = passed + failed + skipped;
|
|
86
|
+
if (total === 0) return null;
|
|
87
|
+
return { total, passed, failed, skipped };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const PARSERS = {
|
|
91
|
+
'maven-surefire': parseMavenSurefire,
|
|
92
|
+
jest: parseJest,
|
|
93
|
+
pytest: parsePytest,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/** auto 识别:按内容特征匹配 runner。 */
|
|
97
|
+
export function detectRunner(text) {
|
|
98
|
+
const trimmed = text.trim();
|
|
99
|
+
if (trimmed.startsWith('{') && parseJest(trimmed)) return 'jest';
|
|
100
|
+
if (/Tests run:\s*\d+,\s*Failures:/.test(trimmed)) return 'maven-surefire';
|
|
101
|
+
if (parsePytest(trimmed)) return 'pytest';
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── CLI ─────────────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
export async function run(args) {
|
|
108
|
+
const { positionals, values } = parseArgs({
|
|
109
|
+
args,
|
|
110
|
+
options: {
|
|
111
|
+
from: { type: 'string' },
|
|
112
|
+
runner: { type: 'string', default: 'auto' },
|
|
113
|
+
json: { type: 'boolean', default: false },
|
|
114
|
+
},
|
|
115
|
+
allowPositionals: true,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const usageMsg = 'Usage: tf test record <change-dir> --from <runner-output-file|surefire-report-dir> [--runner auto|maven-surefire|jest|pytest] [--json]';
|
|
119
|
+
if (positionals[0] !== 'record') {
|
|
120
|
+
console.error(usageMsg);
|
|
121
|
+
process.exit(2);
|
|
122
|
+
}
|
|
123
|
+
const changeDirArg = positionals[1];
|
|
124
|
+
if (!changeDirArg) {
|
|
125
|
+
console.error(usageMsg);
|
|
126
|
+
process.exit(2);
|
|
127
|
+
}
|
|
128
|
+
const changeDir = path.resolve(changeDirArg);
|
|
129
|
+
if (!existsSync(join(changeDir, '.team-flow.yaml'))) {
|
|
130
|
+
console.error(`No state file at ${join(changeDir, '.team-flow.yaml')}. Run 'tf state init <change-dir>' first.`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
if (!values.from) {
|
|
134
|
+
console.error(usageMsg);
|
|
135
|
+
process.exit(2);
|
|
136
|
+
}
|
|
137
|
+
const fromPath = path.resolve(values.from);
|
|
138
|
+
if (!existsSync(fromPath)) {
|
|
139
|
+
console.error(`Runner output not found: ${fromPath}`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
const validRunners = ['auto', ...SUPPORTED_RUNNERS];
|
|
143
|
+
if (!validRunners.includes(values.runner)) {
|
|
144
|
+
console.error(`--runner must be one of: ${validRunners.join(', ')}`);
|
|
145
|
+
process.exit(2);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 解析 runner 输出
|
|
149
|
+
let stats = null;
|
|
150
|
+
let runner = values.runner;
|
|
151
|
+
const fromStat = statSync(fromPath);
|
|
152
|
+
if (fromStat.isDirectory()) {
|
|
153
|
+
if (runner !== 'auto' && runner !== 'maven-surefire') {
|
|
154
|
+
console.error('Directory input is only supported for maven-surefire XML report directories');
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
runner = 'maven-surefire';
|
|
158
|
+
stats = parseSurefireReportDir(fromPath);
|
|
159
|
+
} else {
|
|
160
|
+
const text = readFileSync(fromPath, 'utf-8');
|
|
161
|
+
if (runner === 'auto') {
|
|
162
|
+
runner = detectRunner(text);
|
|
163
|
+
if (!runner) {
|
|
164
|
+
console.error(
|
|
165
|
+
`Could not auto-detect a supported test runner in ${fromPath}.\n`
|
|
166
|
+
+ `Supported runners: ${SUPPORTED_RUNNERS.join(', ')} (or pass --runner explicitly).\n`
|
|
167
|
+
+ '手工自述通道已关闭(v0.13 §50):确无自动化测试的 change 请显式跳过:\n'
|
|
168
|
+
+ " tf state set <dir> test_matrix_skipped true + test_matrix_skip_reason '<理由>'"
|
|
169
|
+
);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
stats = PARSERS[runner](text);
|
|
174
|
+
}
|
|
175
|
+
if (!stats) {
|
|
176
|
+
console.error(`Could not parse ${runner} output in ${fromPath} — no recognizable test summary found.`);
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 判定:failed==0 且 total>0 才算 pass(total=0 空真拒绝,v0.13 §50.2)
|
|
181
|
+
const verdict = stats.failed === 0 && stats.total > 0 ? 'pass' : 'fail';
|
|
182
|
+
const ts = new Date().toISOString();
|
|
183
|
+
const record = `${verdict}: total=${stats.total} passed=${stats.passed} failed=${stats.failed} skipped=${stats.skipped} runner=${runner} recorded-by=tf-test-record ts=${ts}`;
|
|
184
|
+
|
|
185
|
+
// 原始证据落盘(tests-passing 门禁与 doctor 巡检都要求该文件存在)
|
|
186
|
+
const evidenceDir = join(changeDir, '.superpowers', 'test-evidence');
|
|
187
|
+
mkdirSync(evidenceDir, { recursive: true });
|
|
188
|
+
const safeTs = ts.replace(/[:.]/g, '-');
|
|
189
|
+
const evidenceRel = join('.superpowers', 'test-evidence', `${safeTs}-${runner}.txt`).split(path.sep).join('/');
|
|
190
|
+
const raw = fromStat.isFile()
|
|
191
|
+
? readFileSync(fromPath, 'utf-8')
|
|
192
|
+
: `(maven-surefire XML report directory: ${fromPath})`;
|
|
193
|
+
const MAX_EVIDENCE = 512 * 1024;
|
|
194
|
+
writeFileSync(join(changeDir, evidenceRel), raw.length > MAX_EVIDENCE ? `${raw.slice(0, MAX_EVIDENCE)}\n...[truncated]` : raw, 'utf-8');
|
|
195
|
+
|
|
196
|
+
// 程序化写入状态(test_result 不在 SETTABLE_FIELDS,只能经本命令写入)
|
|
197
|
+
const state = readState(changeDir);
|
|
198
|
+
state.test_result = record;
|
|
199
|
+
state.test_evidence_path = evidenceRel;
|
|
200
|
+
writeState(changeDir, state);
|
|
201
|
+
|
|
202
|
+
if (values.json) {
|
|
203
|
+
console.log(JSON.stringify({ ok: true, verdict, ...stats, runner, test_result: record, test_evidence_path: evidenceRel }));
|
|
204
|
+
} else {
|
|
205
|
+
console.log(`${verdict === 'pass' ? '✅' : '❌'} test_result recorded (${runner}): total=${stats.total} passed=${stats.passed} failed=${stats.failed} skipped=${stats.skipped}`);
|
|
206
|
+
console.log(` evidence: ${evidenceRel}`);
|
|
207
|
+
if (verdict === 'fail') {
|
|
208
|
+
console.log(' closing 将被 tests-passing 门禁阻断:修复失败后重新运行测试套件并再次 tf test record。');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
process.exit(verdict === 'pass' ? 0 : 1);
|
|
212
|
+
}
|
package/scripts/team-flow.mjs
CHANGED
|
@@ -34,6 +34,9 @@ const COMMANDS = {
|
|
|
34
34
|
'install-zcode': () => import('./lib/cmd-install-zcode.mjs'),
|
|
35
35
|
'prototype-sync': () => import('./lib/prototype-sync.mjs'),
|
|
36
36
|
'arch-merge': () => import('./lib/arch-merge.mjs'),
|
|
37
|
+
'test-merge': () => import('./lib/test-merge.mjs'),
|
|
38
|
+
'test-matrix-export': () => import('./lib/test-matrix-export.mjs'),
|
|
39
|
+
test: () => import('./lib/test-record.mjs'),
|
|
37
40
|
};
|
|
38
41
|
|
|
39
42
|
const HELP = `team-flow (tf) — Unified workflow plugin CLI
|
|
@@ -50,6 +53,12 @@ Commands:
|
|
|
50
53
|
Merge UX delta into global prototype/ + design-system.md
|
|
51
54
|
arch-merge <change-dir> [--project-root <path>] [--dry-run]
|
|
52
55
|
Merge architecture delta into global docs/architecture/
|
|
56
|
+
test-merge <change-dir> [--project-root <path>] [--dry-run]
|
|
57
|
+
Merge test matrix results into global docs/test-ledger/
|
|
58
|
+
test-matrix-export <input.json> <output.md> [--change-id <id>]
|
|
59
|
+
Convert glaf4 test-matrix.json to team-flow test-matrix.md
|
|
60
|
+
test record <dir> --from <runner-output> [--runner auto|maven-surefire|jest|pytest]
|
|
61
|
+
Record programmatic test evidence (v0.13 §50; feeds tests-passing gate)
|
|
53
62
|
config [options] Display or modify configuration
|
|
54
63
|
config --resolve-model <profile> Resolve a configured model profile without switching models
|
|
55
64
|
state <sub> <dir> Manage .team-flow.yaml state (init|check|transition|get|rebuild)
|
|
@@ -40,13 +40,42 @@ Subagent (general-purpose):
|
|
|
40
40
|
## Your Job
|
|
41
41
|
|
|
42
42
|
Once you're clear on requirements:
|
|
43
|
-
1.
|
|
44
|
-
2.
|
|
45
|
-
3. Verify implementation works
|
|
43
|
+
1. Read test-matrix.md for this task's module section (if it exists)
|
|
44
|
+
2. Implement exactly what the task specifies, following the Test Matrix Protocol below
|
|
45
|
+
3. Verify implementation works (all matrix cases pass)
|
|
46
46
|
4. Commit your work
|
|
47
47
|
5. Self-review (see below)
|
|
48
48
|
6. Report back
|
|
49
49
|
|
|
50
|
+
## Test Matrix Protocol (v0.12 §44.2)
|
|
51
|
+
|
|
52
|
+
If `test-matrix.md` exists, read the module section relevant to your task.
|
|
53
|
+
For each case in the matrix, follow the protocol matching its `work_mode`:
|
|
54
|
+
|
|
55
|
+
**work_mode=TDD** (new behavior):
|
|
56
|
+
1. RED: Write failing test matching `case_id` + `test_method_name`, confirm failure
|
|
57
|
+
2. GREEN: Implement minimum code to pass
|
|
58
|
+
3. REFACTOR: Clean up, suite stays green
|
|
59
|
+
4. Report TDD Evidence: RED command + failure output, GREEN command + pass output
|
|
60
|
+
|
|
61
|
+
**work_mode=CHARACTERIZATION** (legacy behavior capture):
|
|
62
|
+
1. Write test capturing current behavior — do NOT change production code
|
|
63
|
+
2. Report: `current_behavior_note` + test output
|
|
64
|
+
3. `production_change_allowed=false` — if test reveals a bug, report it but do NOT fix
|
|
65
|
+
|
|
66
|
+
**work_mode=REGRESSION** (defect reproduction + fix):
|
|
67
|
+
1. Write failing test reproducing the defect
|
|
68
|
+
2. Fix production code, confirm green
|
|
69
|
+
3. Report: defect reproduction + fix evidence
|
|
70
|
+
|
|
71
|
+
After all cases: self-check matrix coverage = passed cases / total cases in matrix for your module.
|
|
72
|
+
|
|
73
|
+
**两不原则 (Two Prohibitions)**:
|
|
74
|
+
- ⛔ DO NOT write production code and test code simultaneously — RED first, then GREEN
|
|
75
|
+
- ⛔ DO NOT skip the RED failure confirmation — you must see the test fail before implementing
|
|
76
|
+
|
|
77
|
+
If `test-matrix.md` does NOT exist, fall back to standard TDD (Law 2): write tests first, then implement.
|
|
78
|
+
|
|
50
79
|
Work from: [directory]
|
|
51
80
|
|
|
52
81
|
**While you work:** If you encounter something unexpected or unclear, **ask questions**.
|
|
@@ -109,6 +138,8 @@ Subagent (general-purpose):
|
|
|
109
138
|
- Did I follow TDD if required?
|
|
110
139
|
- Are tests comprehensive?
|
|
111
140
|
- Is the test output pristine (no stray warnings or noise)?
|
|
141
|
+
- If test-matrix.md exists: matrix coverage = passed cases / total cases for my module
|
|
142
|
+
- Each case's `design_method` matches the actual test approach (boundary case uses real boundary values, not happy-path disguised as boundary)
|
|
112
143
|
|
|
113
144
|
If you find issues during self-review, fix them now before reporting.
|
|
114
145
|
|
|
@@ -126,6 +157,10 @@ Subagent (general-purpose):
|
|
|
126
157
|
- **TDD Evidence** (if TDD was required for this task):
|
|
127
158
|
- RED: command run, relevant failing output before implementation, and why the failure was expected
|
|
128
159
|
- GREEN: command run and relevant passing output after implementation
|
|
160
|
+
- **Test Matrix Coverage** (if test-matrix.md exists):
|
|
161
|
+
- Cases implemented: N/M (list case_ids)
|
|
162
|
+
- Cases deferred: N (list case_ids + reason)
|
|
163
|
+
- Any case where expected_red did not match actual failure — report mismatch
|
|
129
164
|
- Files changed
|
|
130
165
|
- Self-review findings (if any)
|
|
131
166
|
- Any issues or concerns
|
|
@@ -134,6 +134,31 @@ Check for:
|
|
|
134
134
|
- **Edge cases**: Tests cover boundary conditions, error cases
|
|
135
135
|
- **Test quality**: Tests are meaningful (not just "it works"), assertions are specific
|
|
136
136
|
|
|
137
|
+
### Step 5b: Test Matrix Compliance (v0.12 §44.3)
|
|
138
|
+
|
|
139
|
+
If `test-matrix.md` exists in the change directory, audit the implementation against it:
|
|
140
|
+
|
|
141
|
+
1. **Case-by-case verification**: For each case in the matrix:
|
|
142
|
+
- Check if the test implementation exists (`test_file` + `test_method_name` match)
|
|
143
|
+
- Verify assertions match the matrix's `expected` output
|
|
144
|
+
- Verify `design_method` matches actual test approach (a `boundary` case must use real boundary values, not a happy-path disguised as boundary)
|
|
145
|
+
|
|
146
|
+
2. **Coverage calculation**:
|
|
147
|
+
- Matrix coverage = implemented cases / total cases in matrix
|
|
148
|
+
- Matrix coverage < 100% → **Critical finding** (test-matrix-gap)
|
|
149
|
+
- List missing case_ids
|
|
150
|
+
|
|
151
|
+
3. **Candidate Coverage Ledger audit**:
|
|
152
|
+
- Entries with `decision=deferred` have a reasonable `reason`?
|
|
153
|
+
- Entries with `decision=covered` actually have corresponding tests?
|
|
154
|
+
|
|
155
|
+
4. **Pyramid ratio check**:
|
|
156
|
+
- unit cases: 70-80% of total
|
|
157
|
+
- integration cases: ≤30% of total
|
|
158
|
+
- Significant deviation → **Important finding** (test-pyramid-imbalance)
|
|
159
|
+
|
|
160
|
+
If `test-matrix.md` does NOT exist, skip this step silently (legacy change compatibility).
|
|
161
|
+
|
|
137
162
|
### Step 6: Documentation Review
|
|
138
163
|
|
|
139
164
|
Check for:
|
|
@@ -156,7 +181,9 @@ Check for:
|
|
|
156
181
|
|---------|-----------|
|
|
157
182
|
| **PASS** | No Critical or Important findings |
|
|
158
183
|
| **PASS_WITH_WARNINGS** | No Critical, but Important findings exist |
|
|
159
|
-
| **FAIL** | Any Critical finding |
|
|
184
|
+
| **FAIL** | Any Critical finding (including Test Matrix Compliance gaps — v0.12 §44.3) |
|
|
185
|
+
|
|
186
|
+
Test Matrix Compliance Critical findings carry the same weight as Spec Compliance violations — matrix gaps are always Critical, never Important.
|
|
160
187
|
|
|
161
188
|
## Calibration Rules
|
|
162
189
|
|
|
@@ -68,6 +68,16 @@ Subagent (general-purpose):
|
|
|
68
68
|
- Integration tests where they matter?
|
|
69
69
|
- All tests passing?
|
|
70
70
|
|
|
71
|
+
**Test Matrix Compliance (v0.12 §44.3):**
|
|
72
|
+
If `test-matrix.md` exists, audit against it:
|
|
73
|
+
- Each case has a corresponding test implementation (test_file + test_method_name match)?
|
|
74
|
+
- Assertions match the matrix's `expected` output?
|
|
75
|
+
- `design_method` matches actual test approach (boundary case uses real boundary values)?
|
|
76
|
+
- Matrix coverage < 100% → Critical finding (test-matrix-gap)
|
|
77
|
+
- Candidate Coverage Ledger: deferred items have reasonable reasons?
|
|
78
|
+
- Pyramid ratio: unit 70-80%, integration ≤30%?
|
|
79
|
+
If `test-matrix.md` does NOT exist, skip this section silently.
|
|
80
|
+
|
|
71
81
|
**Production readiness:**
|
|
72
82
|
- Migration strategy if schema changed?
|
|
73
83
|
- Backward compatibility considered?
|
|
@@ -11,6 +11,8 @@ Read before generating: `proposal.md`, `specs/`, `design.md`, `tasks.md`, then l
|
|
|
11
11
|
|
|
12
12
|
**Architecture Design Outputs (v0.9 §26)**: 若 `architecture/` 目录存在,同时读取 `architecture/architecture.md` / `database.md` / `api.md`,作为执行契约的架构约束补充输入——确保 execution-contract.md 的 Implementation Constraints 段包含架构设计的关键约束(聚合边界/CQRS 分流/API 契约/schema 变更)。`architecture/` 不存在时跳过。
|
|
13
13
|
|
|
14
|
+
**Test Ledger Injection (v0.12 §43.5)**: 若 `docs/test-ledger/` 存在,读取 `INDEX.md`(模块覆盖概览 coverage_status)+ `baselines/{module}.md`(已有 case 避免重复设计;Deferred Items 评估本次是否可解决),作为 test-matrix.md 生成的增量输入。不存在时跳过(首次使用或无历史数据)。
|
|
15
|
+
|
|
14
16
|
## Artifact Mapping
|
|
15
17
|
|
|
16
18
|
| Source | Extract |
|
|
@@ -34,6 +36,77 @@ Before finalizing:
|
|
|
34
36
|
|
|
35
37
|
Must make obvious: approved behavior, out-of-scope, constraints, batches, test obligations, review gates, and conditions that force a rewind to planning. Prefer compression over repeating planning details.
|
|
36
38
|
|
|
39
|
+
## Test Matrix Generation (v0.12 §42, v0.13 §52 B1 强制化)
|
|
40
|
+
|
|
41
|
+
`test-matrix.md` 是 `execution-contract.md` 的**附属产物**(不是独立第 6 核心产物),在 contract 的 `## Test Matrix` 段引用。
|
|
42
|
+
|
|
43
|
+
**full workflow 必须生成(MUST,非建议)**:契约声明 `## Test Matrix` 段 ∧ `test-matrix.md` 存在非空 ∧ `tf state rebuild` 捕获 hash。缺契约段或矩阵文件 → `test-matrix-ready` 阻断进入 executing(入口不查 hash);三者任一缺失或 hash 不一致 → `test-matrix-complete` 阻断 closing(v0.13 §48/§49;C1-domain-policy 事件教训:矩阵生成曾是建议级,导致零测试通过全部门禁)。确无测试需求的 change 只有一条出路:显式 skip 并留理由(见 Hotfix/Tweak Exemption)。
|
|
44
|
+
|
|
45
|
+
### Generation Protocol
|
|
46
|
+
|
|
47
|
+
1. **输入来源**:specs/(Scenario + Unit/Integration 标签)、tasks.md(batch + file structure)、test-strategy skill(design_method 规则)、test-ledger baselines(增量输入)
|
|
48
|
+
2. **按模块分组**:为每个有业务逻辑的模块(Service/Controller/Repository 等)生成 case 列表
|
|
49
|
+
3. **复杂度分级**:每个模块标注 trivial/medium/complex,作为用例数下限判据(test-strategy §2)
|
|
50
|
+
4. **design_method 覆盖**:每个模块至少 1 个 `{boundary, equivalence}` case + 1 个 `{error, exception, reject}` case(test-strategy §6 schema 强制覆盖)
|
|
51
|
+
5. **对抗验证**:矩阵生成后执行三招回检(test-strategy §4),缺失则追加 adversarial case
|
|
52
|
+
6. **候选覆盖台账**:列出所有被测候选(方法/类),标注 decision(covered/deferred/not_applicable)
|
|
53
|
+
|
|
54
|
+
### 12-Column Format
|
|
55
|
+
|
|
56
|
+
| case_id | behavior | design_method | input | expected | test_kind | test_tier | mock | work_mode | test_file | test_method_name | run_command |
|
|
57
|
+
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
58
|
+
|
|
59
|
+
字段说明见 test-strategy skill 的 `references/design-methods-detail.md`。`test_tier` 从 `test_kind` 派生(unit/integration)。
|
|
60
|
+
|
|
61
|
+
### Structure
|
|
62
|
+
|
|
63
|
+
```markdown
|
|
64
|
+
# Test Matrix — {change-name}
|
|
65
|
+
|
|
66
|
+
## Summary
|
|
67
|
+
- Total cases: {N}
|
|
68
|
+
- Modules covered: {N} (complexity: trivial×{n}, medium×{n}, complex×{n})
|
|
69
|
+
- Unit cases: {N} ({percent}%)
|
|
70
|
+
- Integration cases: {N} ({percent}%)
|
|
71
|
+
- Deferred items: {N}
|
|
72
|
+
- Matrix revision: 1
|
|
73
|
+
|
|
74
|
+
## Candidate Coverage Ledger
|
|
75
|
+
| candidate | category | decision | case_ids | reason |
|
|
76
|
+
|
|
77
|
+
## Cases
|
|
78
|
+
### {module-name}
|
|
79
|
+
| case_id | behavior | design_method | input | expected | test_kind | test_tier | mock | work_mode | test_file | test_method_name | run_command |
|
|
80
|
+
|
|
81
|
+
## Adversarial Cases
|
|
82
|
+
| case_id | behavior | design_method | input | expected | test_kind | test_tier | mock | work_mode | test_file | test_method_name | run_command |
|
|
83
|
+
|
|
84
|
+
## Deferred Items
|
|
85
|
+
| case_id | behavior | design_method | reason | deferred_since |
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Post-Generation
|
|
89
|
+
|
|
90
|
+
写入 `test-matrix.md` 后,在 `execution-contract.md` 中添加引用段:
|
|
91
|
+
```markdown
|
|
92
|
+
## Test Matrix
|
|
93
|
+
See `test-matrix.md` for the full test case matrix (附属产物, 独立 hash).
|
|
94
|
+
- Total cases: {N}, Unit: {N}, Integration: {N}, Deferred: {N}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
然后执行 `tf state rebuild <change-dir>` 更新 `test_matrix_hash`。
|
|
98
|
+
|
|
99
|
+
### Hotfix/Tweak Exemption
|
|
100
|
+
|
|
101
|
+
hotfix/tweak workflow 不生成 test-matrix.md(guard 豁免);full workflow 确无自动化测试需求的特例(纯文档/纯配置)同理。设置显式 skip + 理由(v0.13 §48.2 可审计豁免,**不允许静默不生成**):
|
|
102
|
+
```bash
|
|
103
|
+
tf state set <change-dir> test_matrix_skipped true && tf state set <change-dir> test_matrix_skip_reason "<一句话说明>"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### GLAF4 Java 路由
|
|
107
|
+
|
|
108
|
+
当项目技术栈为 GLAF4 Java(Spring Boot / JUnit 5 / Mockito)时,提示用户是否调用 `glaf4-test:glaf4-tests` 做精细矩阵设计。用户同意后:`glaf4-tests-design` 生成 `test-matrix.json` → `glaf4-tests-validate` 校验 → `tf test-matrix-export <test-matrix.json> <change-dir>/test-matrix.md` 转换为 team-flow 格式。完整 7 步协议见 workflow-start `references/routing-rules.md`「Route to glaf4-tests」。
|
|
109
|
+
|
|
37
110
|
## Approval Model (DP-3)
|
|
38
111
|
|
|
39
112
|
After drafting: summarize handoff rules, identify ambiguity, flag unmapped requirements, ask user to approve explicitly. After approval:
|
|
@@ -51,6 +124,8 @@ Refresh if: scope changed in proposal, requirements changed in specs, constraint
|
|
|
51
124
|
|
|
52
125
|
Generate minimal contract: Intent Lock (one sentence), Task List (numbered), Approval Gate (DP-3). Skip Scope Fence, Build Rules, Review Gates, Test Evidence. Still requires DP-3 approval.
|
|
53
126
|
|
|
127
|
+
**非存量 hotfix/tweak 必须设置显式 skip(v0.13 §50)**:hotfix/tweak 不生成矩阵,但 closing 的 tests-passing 门禁仍考核非存量 change——生成最小契约后立即执行 Hotfix/Tweak Exemption 段的两条 `tf state set`(`test_matrix_skipped=true` + 理由),否则 release-archivist 轻量收尾会被门禁阻断。
|
|
128
|
+
|
|
54
129
|
## Guardrails
|
|
55
130
|
|
|
56
131
|
- **状态字段禁写(v0.30.0)**:仅写本 skill 的 `dp_3_*` 决策字段;**MUST NOT** 修改 `state`/`workflow` 核心字段——状态转换由主代理经 `tf state transition` 执行。`tf state init` 只创建状态文件,不改 `state` 值(来源:workflow-feedback 2026-08-01)。
|
|
@@ -29,11 +29,36 @@ Claiming work is complete without verification is dishonesty, not efficiency. Be
|
|
|
29
29
|
## Verification Steps
|
|
30
30
|
|
|
31
31
|
### Step 1: Test Suite
|
|
32
|
-
Run full test suite. Record total/passed/failed/skipped. Zero failures = PASS
|
|
32
|
+
Run full test suite fresh (e.g. `mvn test` / `npm test`). Record total/passed/failed/skipped. **Zero failures AND total > 0 = PASS.**
|
|
33
|
+
|
|
34
|
+
**⛔ 空真拒绝(v0.13 §50,C1-domain-policy 事件修复)**:0 个测试时"0 失败"在逻辑上为真,但不是证据——**0 tests ≠ PASS**。发现测试套件为空或项目无测试文件时:要么回 build-executor 补测试(按 test-matrix.md),要么该 change 本应在 bridging 阶段显式 skip(`test_matrix_skipped=true` + 理由);两种情况都不得写 pass。
|
|
35
|
+
|
|
36
|
+
**程序化记录(v0.13 §50)**:跑完测试套件后,把 runner 输出落盘并用命令写入证据(`test_result` 已不可手工 `tf state set`):
|
|
37
|
+
```bash
|
|
38
|
+
tf test record <change-dir> --from <runner-output-file> # 支持 maven-surefire/jest/pytest,auto 识别
|
|
39
|
+
```
|
|
40
|
+
该命令写入结构化 `test_result`(recorded-by=tf-test-record)+ 证据文件(`.superpowers/test-evidence/`),是 `tests-passing` 门禁对非存量 change 的唯一合法凭证。
|
|
33
41
|
|
|
34
42
|
### Step 2: Completeness
|
|
35
43
|
Compare contract batches against actual diff. Every SHALL/MUST must have implementation evidence. Missing = Critical severity.
|
|
36
44
|
|
|
45
|
+
### Step 2b: Test Matrix Reconciliation (conditional, v0.12 §44.4)
|
|
46
|
+
|
|
47
|
+
If `test-matrix.md` exists:
|
|
48
|
+
1. **Statistics**: total cases / implemented / passed
|
|
49
|
+
2. **Candidate Coverage Ledger audit**: any `decision=deferred` without reasonable reason?
|
|
50
|
+
3. **Complexity tier check**: cases per module meet minimum (trivial≥3 / medium≥5 / complex≥7)?
|
|
51
|
+
4. **Verdict**:
|
|
52
|
+
- Matrix coverage = 100% AND all cases pass → **PASS**
|
|
53
|
+
- Matrix coverage ≥ 90% with reasonable deferred items → **CONDITIONAL (WARN)**
|
|
54
|
+
- Matrix coverage < 90% OR unexplained gaps → **FAIL**
|
|
55
|
+
|
|
56
|
+
If `test-matrix.md` does NOT exist(v0.13 §52 B2 修订):
|
|
57
|
+
- legacy change(.team-flow.yaml 无 `schema_version` 字段)或 `test_matrix_skipped=true` → **SKIP**
|
|
58
|
+
- 非存量且未 skip → **FAIL**(矩阵缺失即验证失败;删除静默 SKIP——C1-domain-policy 事件教训)
|
|
59
|
+
|
|
60
|
+
Add a report row: `| Test Matrix | PASS/FAIL/WARN/SKIP | [reconciliation summary] |`
|
|
61
|
+
|
|
37
62
|
### Step 3: Coherence
|
|
38
63
|
Compare design decisions against code. Check naming consistency. Inconsistencies = IMPORTANT.
|
|
39
64
|
|
|
@@ -67,7 +92,7 @@ If an `e2e/` suite exists for the change, fold its report into verification (see
|
|
|
67
92
|
|
|
68
93
|
## Final Checks
|
|
69
94
|
|
|
70
|
-
**⛔ 状态字段禁写(v0.30.0)**:仅写本 skill 的 `dp_6_*`/`dp_7_*`
|
|
95
|
+
**⛔ 状态字段禁写(v0.30.0 + v0.13 §50)**:仅写本 skill 的 `dp_6_*`/`dp_7_*` 决策字段;测试证据经 `tf test record` 程序化写入(不再手工 set `test_result`);**MUST NOT** 修改 `.team-flow.yaml` 的 `state`/`workflow` 核心字段——closing 转换由主代理经 `tf state transition` 执行(来源:workflow-feedback 2026-08-01)。
|
|
71
96
|
|
|
72
97
|
- Tests passing? (cite command and output)
|
|
73
98
|
- All batches complete? (cite batch status)
|
|
@@ -83,12 +108,7 @@ tf state set <change-dir> dp_6_timestamp $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
|
83
108
|
```
|
|
84
109
|
If FAIL, do NOT proceed to DP-7. Route back or ask about abandonment.
|
|
85
110
|
|
|
86
|
-
|
|
87
|
-
`executing → closing` transition is allowed (the guard accepts either
|
|
88
|
-
`test_result: pass` or a `dp_6_result` starting with `pass`):
|
|
89
|
-
```bash
|
|
90
|
-
tf state set <change-dir> test_result pass
|
|
91
|
-
```
|
|
111
|
+
**测试门禁凭证(v0.13 §50 修订)**:`dp_6_result` 只是决策点记录,不再是 `tests-passing` 门禁的证据(BUG-A 等价通道仅对存量 change 保留)。非存量 change 的 `executing → closing` 放行凭证是 Step 1 中 `tf test record` 写入的结构化 `test_result`(+ 证据文件)。若 Step 1 尚未执行 `tf test record`,先补跑测试套件并记录,再守 DP-6。
|
|
92
112
|
|
|
93
113
|
### DP-7 (Archive Confirmation)
|
|
94
114
|
```bash
|
|
@@ -115,7 +135,7 @@ tf arch-merge <change-dir>
|
|
|
115
135
|
|
|
116
136
|
This merges `architecture/{architecture,database,api}.md` and `architecture/sql/` into the global architecture docs. Skip silently when `architecture/` does not exist (architecture-design was `skipped`).
|
|
117
137
|
|
|
118
|
-
**Execution order (mandatory)**: `arch-merge` → `prototype-sync` → `compound promotion`. Do not parallelise — global docs must not be in a half-updated state.
|
|
138
|
+
**Execution order (mandatory, v0.12 §43.4)**: `arch-merge` → `prototype-sync` → `test-merge` → `compound promotion`. Do not parallelise — global docs must not be in a half-updated state.
|
|
119
139
|
|
|
120
140
|
### Prototype Sync (v0.5)
|
|
121
141
|
|
|
@@ -125,12 +145,30 @@ After `arch-merge` completes, run prototype-sync to merge UX deltas back to the
|
|
|
125
145
|
tf prototype-sync <change-dir>
|
|
126
146
|
```
|
|
127
147
|
|
|
128
|
-
**Write-back order (mandatory)**: `arch-merge` → `prototype-sync` → `compound promotion` must be executed **sequentially** within the same change closing. Do not run them in parallel — the global `docs/architecture
|
|
148
|
+
**Write-back order (mandatory, v0.12 §43.4)**: `arch-merge` → `prototype-sync` → `test-merge` → `compound promotion` must be executed **sequentially** within the same change closing. Do not run them in parallel — the global `docs/architecture/`, `prototype/`, and `docs/test-ledger/` must not be in a half-updated state when the next change grounds on them.
|
|
129
149
|
|
|
130
150
|
If `prototype-sync` reports conflicts, list them in the closing summary and flag for manual resolution. Do not block closing on prototype-sync conflicts (advisory level).
|
|
131
151
|
|
|
132
152
|
**Execution verification(v0.24.0)**:`prototype-sync` 命令执行后,检查其 stdout 输出确认合并完成(输出含 `merged`/`no UX delta`/`conflicts` 之一)。若命令未执行或执行失败,Step 5 Report 的 `Prototype sync` 行必须标注 `SKIPPED` 或 `FAILED`,并在 closing summary 中说明原因。**禁止在 prototype-sync 未执行时将 Prototype sync 行标注为已完成**。
|
|
133
153
|
|
|
154
|
+
### Test Merge (v0.12 §43)
|
|
155
|
+
|
|
156
|
+
After `prototype-sync` completes, run test-merge to write test matrix results back to the global test ledger:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
tf test-merge <change-dir>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This merges `test-matrix.md` into `docs/test-ledger/`:
|
|
163
|
+
- **mergeBaselines**: extract cases by module, incrementally update `baselines/{module}.md`
|
|
164
|
+
- **resolveDeferred**: new cases covering old deferred items → remove from Deferred
|
|
165
|
+
- **appendChangelog**: archive test-matrix.md → `changelog/{change-id}.md`
|
|
166
|
+
- **rewriteIndex**: recalculate module/case/deferred counts, rewrite `INDEX.md`
|
|
167
|
+
|
|
168
|
+
Skip silently when `test-matrix.md` does not exist (legacy change or test_matrix_skipped=true).
|
|
169
|
+
|
|
170
|
+
**Execution verification**: check stdout output for `test-merge complete` confirmation. If the command did not execute or failed, Step 5 Report's `Test Matrix` row (from Step 2b) must note the reason.
|
|
171
|
+
|
|
134
172
|
### Compound Promotion (v0.5)
|
|
135
173
|
|
|
136
174
|
During closing, promote change-level learnings to the global solutions library:
|
|
@@ -175,6 +213,8 @@ This check is advisory — skip if the user declines. If the user reports issues
|
|
|
175
213
|
|
|
176
214
|
Verify files exist and are non-empty, run `node --check` on code files, skip 5-step verification. Still record DP-6 and DP-7.
|
|
177
215
|
|
|
216
|
+
**⚠️ tests-passing 门禁不因轻量收尾而豁免(v0.13 §50)**:hotfix/tweak 的 `executing→closing` guard 同样挂 `tests-passing`。非存量 change 仅记 DP-6/DP-7 不足以放行——必须二选一:① `test_matrix_skipped=true` + `test_matrix_skip_reason` 已由 contract-builder 设置(hotfix/tweak 常规路径,先 `tf state get` 核实);② 有代码变更时补跑测试套件并 `tf test record <change-dir> --from <输出>`。
|
|
217
|
+
|
|
178
218
|
## Exception Handling
|
|
179
219
|
|
|
180
220
|
- **Parse failures**: Report exact file and section
|
|
@@ -95,6 +95,7 @@ argument-hint: "[下一个会话的关注点描述]"
|
|
|
95
95
|
3. **必须脱敏**:所有凭据值替换为 `${PLACEHOLDER}`
|
|
96
96
|
4. **不替代状态恢复**:`.team-flow/` yaml 的跨 session 恢复是自动的,handoff 补充非结构化隐性知识
|
|
97
97
|
5. **handoffs/ 目录加入 .gitignore**:交接文档是临时性质
|
|
98
|
+
6. **重构报告必须现场核对(v0.13 §52 B5)**:凡从会话转录(JSONL)重构的执行报告/交接摘要,其中引用的文件、大小、行数、时间戳、决策点记录,**采信前必须对照磁盘现场与状态文件核对**;无法核对的条目显式标注"未现场核对"。教训:C1-domain-policy 执行报告存在 10+ 处重构失真(虚构文件与数字),未核对的报告不能作为根因证据
|
|
98
99
|
|
|
99
100
|
## Output
|
|
100
101
|
|
|
@@ -88,6 +88,8 @@ Every requirement must be testable. Use SHALL or MUST. Every requirement must ha
|
|
|
88
88
|
|
|
89
89
|
Optional structured AC tags under a Scenario are supported for E2E extraction (v0.4, design spec ch.16): `##### Exception:` (→ EX AC, ×2), `##### State:` (→ ST AC, ×2), `##### Boundary:` (→ BND AC, ×1). These are **OPTIONAL** — omitting them does NOT fail validation. The `e2e` skill applies dimension-conditional gating (absent dimension = N/A, not 0%) plus keyword fallback (error/invalid/fail/边界), so no spec is forced to add tags.
|
|
90
90
|
|
|
91
|
+
Optional test-dimension tags under a Scenario are supported for test-matrix extraction (v0.12 §44.1): `##### Unit:` (→ unit test hints: equivalence classes, boundary values), `##### Integration:` (→ integration test hints: cross-module, transaction boundaries). These are **OPTIONAL** — omitting them does NOT fail validation. The `contract-builder` extracts matrix skeletons from these tags when present, but does not require them.
|
|
92
|
+
|
|
91
93
|
### design.md
|
|
92
94
|
Must have: Context (current state, constraints, stakeholders), Goals, Decisions (Choice + Rationale + Alternatives considered), Risks And Trade-Offs.
|
|
93
95
|
|
|
@@ -127,7 +129,7 @@ Generate one at a time. Confirm each before next. This prevents scope drift —
|
|
|
127
129
|
- `## Why` > 50 chars, `## What Changes`, `## Scope` (In/Out), `## Impact`, `## Capabilities`, no TBD/TODO
|
|
128
130
|
|
|
129
131
|
### specs/
|
|
130
|
-
- SHALL/MUST for required behavior, `#### Scenario:` with WHEN/THEN per requirement, grouped under delta headers, no contradictions; optional `##### Exception:/State:/Boundary:` sub-tags allowed but NOT required (absent dimension = N/A, not 0%). Regression: a spec containing `##### Exception:` must still pass `npm run validate` (validateDeltaSpec must not reject unknown sub-headings).
|
|
132
|
+
- SHALL/MUST for required behavior, `#### Scenario:` with WHEN/THEN per requirement, grouped under delta headers, no contradictions; optional `##### Exception:/State:/Boundary:` sub-tags allowed but NOT required (absent dimension = N/A, not 0%); optional `##### Unit:/Integration:` sub-tags allowed but NOT required (test-matrix hints for contract-builder). Regression: a spec containing `##### Exception:` must still pass `npm run validate` (validateDeltaSpec must not reject unknown sub-headings).
|
|
131
133
|
|
|
132
134
|
### design.md
|
|
133
135
|
- `## Context`, `## Goals`, `## Decisions` (≥1, with Choice+Rationale+Alternatives), `## Risks And Trade-Offs`
|