@xulthekl/team-flow 0.62.0 → 0.64.0
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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/marketplace.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.github/plugin/marketplace.json +2 -2
- package/.github/workflows/ci.yml +2 -0
- package/CHANGELOG.md +67 -0
- package/GEMINI.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +1 -1
- package/docs/README_en.md +1 -1
- package/docs/decision-points.md +8 -0
- package/docs/state-machine.md +4 -1
- package/docs/team-flow /344/275/277/347/224/250/350/257/264/346/230/216/357/274/210/347/240/224/345/217/221/345/233/242/351/230/237/347/211/210/357/274/211.md" +4 -4
- package/gemini-extension.json +1 -1
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/guard/checks/_fs-utils.mjs +18 -0
- package/scripts/guard/checks/arch-design-light.mjs +39 -0
- package/scripts/guard/checks/arch-merged-light.mjs +67 -0
- package/scripts/guard/checks/arch-snapshot-light.mjs +30 -0
- package/scripts/guard/checks/artifacts-planned.mjs +38 -0
- package/scripts/guard/checks/compound-writeback-light.mjs +45 -0
- package/scripts/guard/checks/contract-fresh.mjs +48 -4
- package/scripts/guard/checks/cross-change-consistency-light.mjs +75 -0
- package/scripts/guard/checks/direct-short-path.mjs +52 -0
- package/scripts/guard/checks/direct-test-result.mjs +30 -0
- package/scripts/guard/checks/execution-plan-ready.mjs +7 -1
- package/scripts/guard/checks/execution-reviews-passed-light.mjs +28 -0
- package/scripts/guard/checks/gates-probed.mjs +175 -0
- package/scripts/guard/checks/lightweight-completion-evidence.mjs +27 -0
- package/scripts/guard/checks/specs-merged.mjs +25 -1
- package/scripts/guard/checks/test-matrix-complete.mjs +27 -1
- package/scripts/guard/checks/test-matrix-ready.mjs +28 -1
- package/scripts/guard/checks/test-merged-light.mjs +36 -0
- package/scripts/guard/guard.mjs +119 -14
- package/scripts/infer-workflow.mjs +35 -4
- package/scripts/lib/arch-merge.mjs +20 -4
- package/scripts/lib/cmd-execution.mjs +44 -1
- package/scripts/lib/cmd-state.mjs +98 -4
- package/scripts/lib/execution-plan.mjs +3 -1
- package/scripts/lib/state-loader.mjs +55 -0
- package/scripts/lib/surface-scan.mjs +156 -0
- package/scripts/lib/test-merge.mjs +10 -2
- package/scripts/team-flow.mjs +3 -3
- package/skills/build-executor/SKILL.md +6 -11
- package/skills/build-executor/references/wave-delivery-selfcheck.md +92 -0
- package/skills/clean-code/SKILL.md +1 -1
- package/skills/code-reviewer/SKILL.md +4 -0
- package/skills/contract-builder/SKILL.md +21 -0
- package/skills/contract-builder/references/bridging-gate-dry-run.md +89 -0
- package/skills/contract-builder/references/freeze-and-errata.md +81 -0
- package/skills/jarvis/SKILL.md +2 -0
- package/skills/release-archivist/SKILL.md +48 -13
- package/skills/session-handoff/SKILL.md +1 -0
- package/skills/spec-writer/SKILL.md +3 -0
- package/skills/spec-writer/references/facts-referencing.md +64 -0
- package/skills/test-strategy/SKILL.md +1 -1
- package/skills/workflow-start/SKILL.md +64 -5
- package/skills/workflow-start/references/routing-rules.md +4 -4
|
@@ -15,6 +15,21 @@ export const VALID_STATES = [
|
|
|
15
15
|
const BUILTIN_DEFAULTS = {
|
|
16
16
|
state: 'exploring',
|
|
17
17
|
workflow: 'auto',
|
|
18
|
+
// spec-superflow 2.0 双维度(v0.64.0 P0;实施计划 §3.1):
|
|
19
|
+
// workflow 仍是内部档位 full|hotfix|tweak|quick|lightweight(+auto 归一化前);
|
|
20
|
+
// workflow_variant 是用户前门意图 null|direct|planned|legacy——两者不可混用。
|
|
21
|
+
// 旧 yaml 缺字段 → null,路由语义 = legacy 分支(见 workflow-start SKILL)。
|
|
22
|
+
workflow_variant: null,
|
|
23
|
+
// 升档标记(§5.3):variant_source ∈ null|start|upgrade;direction ∈ null|up|down。
|
|
24
|
+
// guard fail-closed 校验数据源——非 exploring 改 variant 必须 source=upgrade 且 direction=up。
|
|
25
|
+
variant_source: null,
|
|
26
|
+
variant_direction: null,
|
|
27
|
+
// planned 是否走轻架构表(arch-design-light + arch-snapshot-light,G3)
|
|
28
|
+
planned_arch: false,
|
|
29
|
+
// 角色级模型分配档(config-loader MODEL_PROFILES),仅解析不改流程(§3.5)
|
|
30
|
+
model_profile: 'standard',
|
|
31
|
+
// 架构 surface 扫描基线(§4):tf state init 打戳 git HEAD;缺失时扫描退化参照
|
|
32
|
+
base_sha: null,
|
|
18
33
|
revision: null,
|
|
19
34
|
artifacts_hash: null,
|
|
20
35
|
contract_hash: null,
|
|
@@ -83,6 +98,17 @@ const BUILTIN_DEFAULTS = {
|
|
|
83
98
|
// `change:<name>`,若不给跳过键则 guard 永久 FAIL 无出路)。
|
|
84
99
|
arch_merge_skipped: null,
|
|
85
100
|
arch_merge_skip_reason: null,
|
|
101
|
+
// Bridging gates dry-run gate (v0.63.0;feedback 20260923-013114 S2)
|
|
102
|
+
// gates-probed 挂 full 的 bridging→approved-for-build;hotfix 走 WORKFLOW_TRANSITION_CHECKS
|
|
103
|
+
// 自有覆盖自动豁免;**tweak 无该键的覆盖条目 → 回落继承本维度**,故 tweak 必须靠
|
|
104
|
+
// gates_probed_skipped 放行——缺此键则 tweak 硬卡死(三处管道缺一不可)。
|
|
105
|
+
gates_probed_skipped: null,
|
|
106
|
+
gates_probed_skip_reason: null,
|
|
107
|
+
gates_probed_na: null,
|
|
108
|
+
// v0.64.0(§4 arch-design-light):轻架构说明的显式跳过键(skip-with-reason 模式,
|
|
109
|
+
// 与 arch_merge_skipped / test_matrix_skipped 同型:跳过必须附理由留痕)
|
|
110
|
+
arch_design_light_skipped: null,
|
|
111
|
+
arch_design_light_skip_reason: null,
|
|
86
112
|
// 注意:schema_version 故意不在 BUILTIN_DEFAULTS 中(v0.13 §48.1)——
|
|
87
113
|
// 它只由 `tf state init` 在 change 创建时打戳,字段缺失本身就是"存量 change"信号。
|
|
88
114
|
};
|
|
@@ -128,6 +154,26 @@ export function writeState(changeDir, state) {
|
|
|
128
154
|
lines.push('# === Core state ===');
|
|
129
155
|
lines.push(`state: ${state.state || 'exploring'}`);
|
|
130
156
|
lines.push(`workflow: ${state.workflow || 'auto'}`);
|
|
157
|
+
// v0.64.0 P0:前门双维度字段。条件序列化(同 schema_version 模式)——
|
|
158
|
+
// 存量 change 无这些字段时不追加,避免全量 churn;readState 缺失回退 BUILTIN_DEFAULTS。
|
|
159
|
+
if (state.workflow_variant != null) {
|
|
160
|
+
lines.push(`workflow_variant: ${state.workflow_variant}`);
|
|
161
|
+
}
|
|
162
|
+
if (state.variant_source != null) {
|
|
163
|
+
lines.push(`variant_source: ${state.variant_source}`);
|
|
164
|
+
}
|
|
165
|
+
if (state.variant_direction != null) {
|
|
166
|
+
lines.push(`variant_direction: ${state.variant_direction}`);
|
|
167
|
+
}
|
|
168
|
+
if (state.planned_arch === true || state.planned_arch === 'true') {
|
|
169
|
+
lines.push(`planned_arch: true`);
|
|
170
|
+
}
|
|
171
|
+
if (state.model_profile != null && state.model_profile !== 'standard') {
|
|
172
|
+
lines.push(`model_profile: ${state.model_profile}`);
|
|
173
|
+
}
|
|
174
|
+
if (state.base_sha != null) {
|
|
175
|
+
lines.push(`base_sha: ${state.base_sha}`);
|
|
176
|
+
}
|
|
131
177
|
lines.push(`revision: ${state.revision ?? 'null'}`);
|
|
132
178
|
// v0.13 §48.1:schema_version 仅由 tf state init 在 change 创建时打戳;
|
|
133
179
|
// 缺失 = 存量 change(测试门禁豁免键)。rebuild/set 不追加,故条件序列化。
|
|
@@ -213,6 +259,15 @@ export function writeState(changeDir, state) {
|
|
|
213
259
|
lines.push('# === Arch merge gate (v0.53.0 §110.2) ===');
|
|
214
260
|
lines.push(`arch_merge_skipped: ${state.arch_merge_skipped ?? 'null'}`);
|
|
215
261
|
lines.push(`arch_merge_skip_reason: ${state.arch_merge_skip_reason ?? 'null'}`);
|
|
262
|
+
lines.push('');
|
|
263
|
+
lines.push('# === Bridging gates dry-run gate (v0.63.0) ===');
|
|
264
|
+
lines.push(`gates_probed_skipped: ${state.gates_probed_skipped ?? 'null'}`);
|
|
265
|
+
lines.push(`gates_probed_skip_reason: ${state.gates_probed_skip_reason ?? 'null'}`);
|
|
266
|
+
lines.push(`gates_probed_na: ${state.gates_probed_na ?? 'null'}`);
|
|
267
|
+
lines.push('');
|
|
268
|
+
lines.push('# === Light architecture design gate (v0.64.0) ===');
|
|
269
|
+
lines.push(`arch_design_light_skipped: ${state.arch_design_light_skipped ?? 'null'}`);
|
|
270
|
+
lines.push(`arch_design_light_skip_reason: ${state.arch_design_light_skip_reason ?? 'null'}`);
|
|
216
271
|
|
|
217
272
|
fs.writeFileSync(filePath, lines.join('\n') + '\n', 'utf-8');
|
|
218
273
|
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// scripts/lib/surface-scan.mjs — 架构 surface 扫描共享层(v0.64.0,实施计划 §4)
|
|
2
|
+
//
|
|
3
|
+
// 唯一真相源:direct-short-path / arch-merged-light / test-merged-light /
|
|
4
|
+
// cross-change-consistency-light 都从这里取「本次变更碰了哪些文件、是否命中架构 surface」。
|
|
5
|
+
// 判据统一为「架构 surface = API / DB / 聚合」(R2 A-17 统一,禁止各 check 自造变体)。
|
|
6
|
+
//
|
|
7
|
+
// 三源合并(B-05/B-06):已提交 diff + 工作区修改 + untracked;基线 = state.base_sha,
|
|
8
|
+
// 缺失退化 origin/<default> merge-base,再无 → no-baseline(fail-closed,禁 merge-base HEAD HEAD 空过)。
|
|
9
|
+
// 聚合清单(B-04):.team-flow/aggregate-dirs.txt 机器清单(每行一个目录前缀,# 注释,
|
|
10
|
+
// 空文件 = 显式确认无聚合);与 docs/architecture/baseline.md 皆缺失 → missing(fail-closed)。
|
|
11
|
+
import { execFileSync } from 'node:child_process';
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { dirname, join } from 'node:path';
|
|
14
|
+
|
|
15
|
+
const GIT_TIMEOUT_MS = 2_000; // §4 扫描预算 ≤2s(cmd-state spawnSync 10s 总超时)
|
|
16
|
+
|
|
17
|
+
// API/DB surface 路径模式(§4 路径模式表)——聚合只认清单目录,不做词义解析
|
|
18
|
+
const SURFACE_PATH_RE = /(^|\/)(api|apis|routes|controllers?)(\/|$)|mapper|migrations?(\/|$)|(^|\/)schema[._/-]|\.(sql)$/i;
|
|
19
|
+
// 测试文件(test-merged-light 用)
|
|
20
|
+
const TEST_PATH_RE = /(^|\/)(tests?|__tests__|spec)(\/|$)|\.(test|spec)\.[jt]sx?$|Test\.java$/i;
|
|
21
|
+
|
|
22
|
+
function git(args, cwd) {
|
|
23
|
+
return execFileSync('git', args, {
|
|
24
|
+
cwd,
|
|
25
|
+
encoding: 'utf-8',
|
|
26
|
+
timeout: GIT_TIMEOUT_MS,
|
|
27
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
28
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** 由 changes/<name> 推项目根:优先含 changes/ 或 docs/ 的祖先 */
|
|
33
|
+
export function findProjectRoot(changeDir) {
|
|
34
|
+
const a = dirname(dirname(changeDir));
|
|
35
|
+
if (existsSync(join(a, 'changes')) || existsSync(join(a, 'docs'))) return a;
|
|
36
|
+
const b = dirname(changeDir);
|
|
37
|
+
if (existsSync(join(b, 'changes')) || existsSync(join(b, 'docs'))) return b;
|
|
38
|
+
return a;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 解析聚合清单。返回 { missing, dirs[] }。
|
|
43
|
+
* missing=true 表示两处皆无 → 调用方 fail-closed。
|
|
44
|
+
*/
|
|
45
|
+
export function readAggregateList(projectRoot) {
|
|
46
|
+
const txt = join(projectRoot, '.team-flow', 'aggregate-dirs.txt');
|
|
47
|
+
const baseline = join(projectRoot, 'docs', 'architecture', 'baseline.md');
|
|
48
|
+
const txtExists = existsSync(txt);
|
|
49
|
+
const baselineExists = existsSync(baseline);
|
|
50
|
+
if (!txtExists && !baselineExists) return { missing: true, dirs: [] };
|
|
51
|
+
if (!txtExists) return { missing: false, dirs: [] }; // 有 baseline 但无机器清单:清单维度放行,聚合匹配按空表(见设计 §4)
|
|
52
|
+
const dirs = readFileSync(txt, 'utf-8')
|
|
53
|
+
.split('\n')
|
|
54
|
+
.map(l => l.trim())
|
|
55
|
+
.filter(l => l && !l.startsWith('#'));
|
|
56
|
+
return { missing: false, dirs };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readScanIgnore(projectRoot) {
|
|
60
|
+
const p = join(projectRoot, '.team-flow', 'scan-ignore');
|
|
61
|
+
if (!existsSync(p)) return [];
|
|
62
|
+
return readFileSync(p, 'utf-8')
|
|
63
|
+
.split('\n')
|
|
64
|
+
.map(l => l.trim())
|
|
65
|
+
.filter(l => l && !l.startsWith('#'));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 三源合并的变更文件清单。
|
|
70
|
+
* 返回 { error: null|'no-baseline'|'diff-failed', files: string[], base }
|
|
71
|
+
*/
|
|
72
|
+
export function gitChangedFiles(changeDir, state) {
|
|
73
|
+
const files = new Set();
|
|
74
|
+
let base = state?.base_sha || null;
|
|
75
|
+
|
|
76
|
+
// 退化:base_sha 缺失 → origin/<default> merge-base(B-05:参照对象写死)
|
|
77
|
+
if (!base) {
|
|
78
|
+
try {
|
|
79
|
+
const ref = git(['symbolic-ref', 'refs/remotes/origin/HEAD'], changeDir).trim();
|
|
80
|
+
const remoteBranch = ref.replace('refs/remotes/', '');
|
|
81
|
+
base = git(['merge-base', 'HEAD', remoteBranch], changeDir).trim();
|
|
82
|
+
} catch {
|
|
83
|
+
return { error: 'no-baseline', files: [], base: null };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 源①:已提交 diff(base...HEAD)
|
|
88
|
+
try {
|
|
89
|
+
for (const f of git(['diff', '--name-only', `${base}...HEAD`], changeDir).split('\n')) {
|
|
90
|
+
if (f.trim()) files.add(f.trim());
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
return { error: 'diff-failed', files: [], base };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 源②:工作区已修改
|
|
97
|
+
try {
|
|
98
|
+
for (const f of git(['diff', '--name-only', 'HEAD'], changeDir).split('\n')) {
|
|
99
|
+
if (f.trim()) files.add(f.trim());
|
|
100
|
+
}
|
|
101
|
+
} catch { /* 无 HEAD 时忽略 */ }
|
|
102
|
+
|
|
103
|
+
// 源③:untracked(porcelain -uall;B-06:新建未 add 的文件只有此源可见)
|
|
104
|
+
try {
|
|
105
|
+
for (const line of git(['status', '--porcelain', '-uall'], changeDir).split('\n')) {
|
|
106
|
+
if (!line) continue;
|
|
107
|
+
let p = line.slice(3);
|
|
108
|
+
const arrow = p.indexOf(' -> ');
|
|
109
|
+
if (arrow !== -1) p = p.slice(arrow + 4); // rename 取新名
|
|
110
|
+
p = p.trim().replace(/^"|"$/g, '');
|
|
111
|
+
if (p) files.add(p);
|
|
112
|
+
}
|
|
113
|
+
} catch { /* 忽略 */ }
|
|
114
|
+
|
|
115
|
+
// 排除清单(B-06:防无关 WIP 误报)
|
|
116
|
+
const ignore = readScanIgnore(findProjectRoot(changeDir));
|
|
117
|
+
const out = [...files].filter(f => !ignore.some(prefix => f.startsWith(prefix)));
|
|
118
|
+
return { error: null, files: out, base };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 文件 → 架构 surface 分类。
|
|
123
|
+
* 返回 { architectureSurface, apiFiles, dbFiles, aggregateFiles, testFiles }
|
|
124
|
+
*/
|
|
125
|
+
export function classifyFiles(files, aggregateDirs) {
|
|
126
|
+
const apiFiles = [];
|
|
127
|
+
const dbFiles = [];
|
|
128
|
+
const aggregateFiles = [];
|
|
129
|
+
const testFiles = [];
|
|
130
|
+
for (const f of files) {
|
|
131
|
+
if (TEST_PATH_RE.test(f)) testFiles.push(f);
|
|
132
|
+
if (SURFACE_PATH_RE.test(f)) {
|
|
133
|
+
apiFiles.push(f);
|
|
134
|
+
if (/migrations?(\/|$)|schema[._/-]|\.(sql)$/i.test(f)) dbFiles.push(f);
|
|
135
|
+
}
|
|
136
|
+
if (aggregateDirs.some(d => {
|
|
137
|
+
const norm = d.replace(/\/+$/, '');
|
|
138
|
+
return f === norm || f.startsWith(`${norm}/`);
|
|
139
|
+
})) {
|
|
140
|
+
aggregateFiles.push(f);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const architectureSurface = [...new Set([...apiFiles, ...aggregateFiles])];
|
|
144
|
+
return { architectureSurface, apiFiles, dbFiles, aggregateFiles, testFiles };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** 便捷组合:扫描 + 清单 + 分类(各 light runner 统一入口) */
|
|
148
|
+
export function scanArchitectureSurface(changeDir, state) {
|
|
149
|
+
const changed = gitChangedFiles(changeDir, state);
|
|
150
|
+
if (changed.error) return { error: changed.error, projectRoot: findProjectRoot(changeDir) };
|
|
151
|
+
const projectRoot = findProjectRoot(changeDir);
|
|
152
|
+
const agg = readAggregateList(projectRoot);
|
|
153
|
+
if (agg.missing) return { error: 'aggregate-list-missing', projectRoot };
|
|
154
|
+
const cls = classifyFiles(changed.files, agg.dirs);
|
|
155
|
+
return { error: null, projectRoot, files: changed.files, ...cls };
|
|
156
|
+
}
|
|
@@ -40,6 +40,8 @@ function parseArgv(argv) {
|
|
|
40
40
|
parsed.projectRoot = argv[++i];
|
|
41
41
|
} else if (argv[i] === '--dry-run') {
|
|
42
42
|
parsed.dryRun = true;
|
|
43
|
+
} else if (argv[i] === '--light') {
|
|
44
|
+
parsed.light = true;
|
|
43
45
|
} else if (!argv[i].startsWith('--')) {
|
|
44
46
|
parsed._.push(argv[i]);
|
|
45
47
|
}
|
|
@@ -584,11 +586,13 @@ export async function run(args) {
|
|
|
584
586
|
async function main(argv, projectRoot) {
|
|
585
587
|
const changeDir = argv._[0];
|
|
586
588
|
const dryRun = argv.dryRun || false;
|
|
589
|
+
const light = argv.light || false; // v0.64.0 §4:planned 轻回写入口(同 rewriteIndex 单写)
|
|
587
590
|
|
|
588
591
|
if (!changeDir) {
|
|
589
|
-
console.error('Usage: tf test-merge <change-dir> [--project-root <path>] [--dry-run]');
|
|
592
|
+
console.error('Usage: tf test-merge <change-dir> [--project-root <path>] [--dry-run] [--light]');
|
|
590
593
|
process.exit(2);
|
|
591
594
|
}
|
|
595
|
+
if (light) console.log(' Mode: LIGHT(增量条目 + change:<name> 归因锚写入 changelog)');
|
|
592
596
|
|
|
593
597
|
const absChangeDir = resolve(changeDir);
|
|
594
598
|
const changeName = extractChangeName(absChangeDir);
|
|
@@ -643,7 +647,11 @@ async function main(argv, projectRoot) {
|
|
|
643
647
|
console.log(`${mark} Step 3: resolveDeferred — ${deferredResult.resolved} items resolved`);
|
|
644
648
|
|
|
645
649
|
// Step 4: appendChangelog
|
|
646
|
-
|
|
650
|
+
// v0.64.0 §4:light 模式在 changelog 首行写入归因锚 `change:<name>`——
|
|
651
|
+
// arch-merged-light 同型的 guard 归因判据(test-merged-light)依赖该锚,
|
|
652
|
+
// full 模式文件名即含 changeName,锚为显式加固不改变既有内容。
|
|
653
|
+
const changelogContent = light ? `<!-- change:${changeName} -->\n${matrixContent}` : matrixContent;
|
|
654
|
+
const changelogPath = appendChangelog(ledgerDir, changeName, changelogContent, dryRun);
|
|
647
655
|
console.log(`${mark} Step 4: appendChangelog — ${relative(projectRoot, changelogPath)}`);
|
|
648
656
|
|
|
649
657
|
// Step 5: rewriteIndex
|
package/scripts/team-flow.mjs
CHANGED
|
@@ -71,9 +71,9 @@ Commands:
|
|
|
71
71
|
arch scaffold Scaffold global docs/architecture/ ledger in generator format (v0.53.0 §102)
|
|
72
72
|
arch precheck <change-dir> [--json]
|
|
73
73
|
Emit deterministic architecture-gate evidence (v0.22 §88; evidence only, exit 0)
|
|
74
|
-
arch-merge <change-dir> [--project-root <path>] [--dry-run]
|
|
74
|
+
arch-merge <change-dir> [--project-root <path>] [--dry-run] [--light]
|
|
75
75
|
Merge architecture delta into global docs/architecture/
|
|
76
|
-
test-merge <change-dir> [--project-root <path>] [--dry-run]
|
|
76
|
+
test-merge <change-dir> [--project-root <path>] [--dry-run] [--light]
|
|
77
77
|
Merge test matrix results into global docs/test-ledger/
|
|
78
78
|
test-matrix-export <input.json> <output.md> [--change-id <id>]
|
|
79
79
|
Convert glaf4 test-matrix.json to team-flow test-matrix.md
|
|
@@ -90,7 +90,7 @@ Commands:
|
|
|
90
90
|
pytest: terminal summary or junit XML (--junitxml)
|
|
91
91
|
config [options] Display or modify configuration
|
|
92
92
|
config --resolve-model <profile> Resolve a configured model profile without switching models
|
|
93
|
-
state <sub> <dir> Manage .team-flow.yaml state (init|check|transition|get|rebuild)
|
|
93
|
+
state <sub> <dir> Manage .team-flow.yaml state (init|check|transition|get|rebuild|set|upgrade)
|
|
94
94
|
inject <dir> Generate phase-guard artifacts; use --platforms <name|all> when platform is ambiguous
|
|
95
95
|
audit <dir> Generate decision-point-audit.md from .team-flow.yaml
|
|
96
96
|
checkpoint save <change-dir> --task <id> --next <text>
|
|
@@ -131,18 +131,9 @@ For full/hotfix by default. Execute waves as dispatched by workflow-start.
|
|
|
131
131
|
1. Read the current plan with `tf execution show <change-dir> --json`; only waves shown with `current: true` and `eligible: true` may start. A `retryable: true` wave may only be repaired and re-reviewed; do not dispatch its dependents until its replacement receipt is `pass`. The CLI encodes dependencies in `--wave <id>:<strategy>:<tasks>[:<depends-on,...>]` and rejects a review receipt for a wave whose prerequisites lack current `pass` receipts.
|
|
132
132
|
2. A `parallel` wave may dispatch independent tasks simultaneously only when the platform supports concurrent dispatch. If it does not, disclose the unavailable capability and execute the same wave one task at a time without changing its stored strategy.
|
|
133
133
|
3. A `serial` wave dispatches one task at a time in listed order.
|
|
134
|
-
4.
|
|
134
|
+
4. **case↔test 对账(v0.63.0;feedback 20260923-013114 S4,MUST,不过不许报完成)**:产出 `.superpowers/test-evidence/<wave>-case-test-reconciliation.md`——口径见下方 `### Wave Case↔Test Reconciliation (v0.63.0)
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
Notify with:
|
|
139
|
-
- Wave ID
|
|
140
|
-
- Worktree path
|
|
141
|
-
- Branch
|
|
142
|
-
- Repositories and commit SHAs (base + head)
|
|
143
|
-
- Summary of changes
|
|
144
|
-
5. **Do not** attempt to dispatch code-reviewer or write review receipts — that is workflow-start's responsibility.
|
|
145
|
-
6. Critical/Important findings require a `fail` receipt, a focused repair, re-review, then a replacement `pass` receipt. Never advance or close with a missing or failed receipt.
|
|
136
|
+
**交付自检(MUST,不过不许报完成)**:每个 wave 完成时产出 `.superpowers/test-evidence/<wave>-case-test-reconciliation.md`(case id → 测试文件 → 方法名 → 断言点)。**完成门 = 机械层(case_id↔文件)+ 半机械层(方法名)通过即放行**;**断言点层归 code-reviewer Step 5b,不构成本步条件**(防卡死、防自填假证据)。不进 receipt JSON / 不进 test-matrix hash / 不新增 guard 维度。三层判据表、无脚本降级模板、N/A 落盘、升级路径与复用评估见 `references/wave-delivery-selfcheck.md`。
|
|
146
137
|
|
|
147
138
|
### Wave Verify: Actual Test Count (v0.43.1)
|
|
148
139
|
|
|
@@ -152,6 +143,10 @@ For full/hotfix by default. Execute waves as dispatched by workflow-start.
|
|
|
152
143
|
2. 对照 test-matrix 当前 wave 覆盖的用例数(**分母排除 `test_tier=e2e`**——E2E case 由 Playwright 执行,不进入 `mvn test`/`npm test` 的 `Tests run: N`,口径与 code-reviewer Step 5b / release-archivist Step 2b 一致):实际执行数明显低于预期(< 70%)→ **警告 + 调查**(@Nested 静默跳过、测试未被发现、编译期跳过等),未查明前不得报告 "N tests pass"。
|
|
153
144
|
3. 报告引用实际执行数(按 runner 的计数口径),而非 BUILD SUCCESS 或编译通过数量。
|
|
154
145
|
|
|
146
|
+
### Gate-Only Wave Receipt Protocol (v0.63.0)
|
|
147
|
+
|
|
148
|
+
**零代码/纯闸门波次**的 receipt 范围:以根仓 planning commit(`tf publish --changes` 产物)作 base..head(`base` = 其父提交、`head` = 该 commit 本身)。**⚠️ 执行者 = workflow-start**(本 agent 不得自行写 receipt)。**若 G4 尚未执行:先按 G4 纪律完成 AskUserQuestion → 再 publish → 再建 receipt**,不得静默代替用户选择。**⛔ 有代码的波次不得借用。** 细则见 `references/wave-delivery-selfcheck.md`。
|
|
149
|
+
|
|
155
150
|
### Per-Task Loop
|
|
156
151
|
1. **Dispatch implementer**: Load the template with `tf runtime asset read skills/build-executor/implementer-prompt.md`. Extract task brief with `scripts/task-brief PLAN_FILE N`. Include: where task fits, brief path, interfaces from prior tasks, report file path.
|
|
157
152
|
2. **Handle response**: DONE → generate review package + dispatch reviewer. DONE_WITH_CONCERNS → assess. NEEDS_CONTEXT → provide context. BLOCKED → re-dispatch with better model or escalate.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# 波次交付自检(v0.63.0;feedback 20260923-013114 S4 + E2)
|
|
2
|
+
|
|
3
|
+
本文件承载 build-executor SKILL 中两个「每次波次都要执行」的流程细节。SKILL 保留 MUST 与指针,细则在此。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 一、case↔test 对账(S4)
|
|
8
|
+
|
|
9
|
+
**来源**:v2-C2 实测——矩阵↔测试两份手写文本漂移(I-1 测试缺矩阵 expected 子断言 / M-1 方法名漂移 /
|
|
10
|
+
M-2 expected 与实测矛盾)**全部在 code-reviewer 才抓出**,引发修复 + 复审一整轮。本步把「事后抓漂移」前移为「交付自检」。
|
|
11
|
+
|
|
12
|
+
**产出**:`.superpowers/test-evidence/<wave>-case-test-reconciliation.md`,本 wave 覆盖的每个矩阵 case 一行:
|
|
13
|
+
|
|
14
|
+
```markdown
|
|
15
|
+
| case_id | 测试文件 | 方法名 | 断言点 | 备注 |
|
|
16
|
+
|---|---|---|---|---|
|
|
17
|
+
| Svc-create-001 | src/test/java/.../XxxServiceTest.java | shouldCreate_whenValid() | assertThat(status).isEqualTo(...) | — |
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 三层判据(按可判定性分层,不搞一刀切)
|
|
21
|
+
|
|
22
|
+
| 层 | 判据 | 谁判 | 是否构成本步完成条件 |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `case_id` ↔ 测试文件 | **机械**——矩阵 12 列格式本就含 `test_file` / `test_method_name` 列 | 脚本比对 | **是** |
|
|
25
|
+
| 方法名 | **半机械**——可 grep 校验;矩阵一行对多测试时须在备注注明拆分;`@ParameterizedTest` 一方法对多 case 时 grep 仍命中文件,case↔参数行语义归审查侧 | 脚本提示 + 人工确认 | **是** |
|
|
26
|
+
| 断言点 | **审查侧**——语义对应,机器不可判 | code-reviewer Step 5b | **否**——归审查侧,**不构成本步的完成条件**,本步不得因它卡住或自证 |
|
|
27
|
+
|
|
28
|
+
> **完成门(防卡死/防造假)**:**机械层 + 半机械层两层通过 → 本步放行**(可进入下一步通知 wave 完成)。
|
|
29
|
+
> 断言点层由 code-reviewer 独立复核,实施方**不需要也不得**为其自证——否则会逼出「自填断言点」的假自证。
|
|
30
|
+
|
|
31
|
+
### 硬边界(MUST NOT 越界)
|
|
32
|
+
|
|
33
|
+
- **不进 receipt JSON**(`execution-plan.mjs` 的 `savedReceipt` 字段白名单会静默丢弃);
|
|
34
|
+
- **不进 test-matrix hash**(`hash.mjs computeTestMatrixHash` 防自循环设计);
|
|
35
|
+
- **不新增 guard 维度**——走「evidence 文件 + 报告引用」的既有哲学。
|
|
36
|
+
|
|
37
|
+
**反向回填限缩**:允许**仅方法名**从测试回同步矩阵;**expected 禁止由测试反生成**(防 oracle 循环)。
|
|
38
|
+
|
|
39
|
+
### N/A 与无脚本降级
|
|
40
|
+
|
|
41
|
+
- **N/A 落盘位置**:无矩阵的 change(hotfix/tweak,legacy 豁免)→ 在**同一 evidence 文件**内写
|
|
42
|
+
`N/A: <理由>`(文件仍须存在,保持「有产物可查」的一致性),**不得**静默跳过。
|
|
43
|
+
- **机械层脚本不存在时**(team-flow 不内置,脚本由项目侧提供):降级为人工执行同口径比对——
|
|
44
|
+
```bash
|
|
45
|
+
# 矩阵 test_file 列 → 文件存在性
|
|
46
|
+
command grep -nE '^\|' test-matrix.md | … # 逐行取 case_id / test_file
|
|
47
|
+
test -s <test_file> # 存在且非空
|
|
48
|
+
# test_method_name 列 → 源文件内 grep
|
|
49
|
+
command grep -rn "<method_name>" <test_file>
|
|
50
|
+
```
|
|
51
|
+
**原始输出先落文件**再计数(判据四条),并在对账表末尾注明「机械层为人工降级执行」。
|
|
52
|
+
- **升级**:对账反复不过(≥2 轮)→ 根因属纯文本订正走 doc-only 收口波次;**根因属矩阵 expected/方法名本身错**
|
|
53
|
+
→ 走契约勘误的 gate-affecting 通道(rebuild→revise),**不得**以 doc-only 绕过。
|
|
54
|
+
|
|
55
|
+
**复用评估(已做,勿重复)**:glaf4-dev 的 case 级对账实现
|
|
56
|
+
(`glaf4-dev/0.6.2/scripts/gates/spring_contract_check.py`——case_id ↔ 测试方法「恰一个」匹配 + fail-closed 报告结构)
|
|
57
|
+
**算法与报告形态可借鉴,实现不可直接复用**:其硬绑 Java/Spring(`.java` 后缀、surefire 报告),
|
|
58
|
+
而 team-flow 的 change 跨 JS/Java/Kotlin 多栈,须泛化重写。
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 二、Gate-Only 波次 receipt 协议(E2)
|
|
63
|
+
|
|
64
|
+
> **执行者 = workflow-start,不是本 agent。** receipt 由 workflow-start 组装并写入
|
|
65
|
+
> (见 SKILL `### Planned-Wave Loop` 第 6 条:build-executor **不得**自行 dispatch reviewer 或写 receipt)。
|
|
66
|
+
> 本文件记录该协议,**供 workflow-start 在组装 `--base/--head` 时遵循**;build-executor 只需在报告中提供
|
|
67
|
+
> 「本波次无代码提交」这一事实,**不自行构造范围**。
|
|
68
|
+
|
|
69
|
+
**现状**:`tf execution review` 的 `validateResolvedRange` 拒绝 `base == head`(**防伪设计,非缺陷**)——
|
|
70
|
+
但纯闸门/制品型波次**没有代码提交**,每次都要人肉发明一个范围(v2-C1 wave4 与 v2-C2 w3 已重复 ≥2 次)。
|
|
71
|
+
|
|
72
|
+
**固化协议**:纯闸门 / 零代码波次,以**根仓 planning commit**(`tf publish --changes` 的产物)作 receipt 范围:
|
|
73
|
+
|
|
74
|
+
| 项 | 取值 |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `base` | planning commit 的**父提交** |
|
|
77
|
+
| `head` | planning commit **本身** |
|
|
78
|
+
|
|
79
|
+
**若该波次的 G4(阶段产物同步门禁点,§68.2)尚未执行**:G4 本身是一个**阻塞 AskUserQuestion**
|
|
80
|
+
(A 提交并推送 / B 仅提交不推送 / C 暂不同步),**不得静默代替用户选择**。故此处不是「选 C 直接补 publish」,
|
|
81
|
+
而是:
|
|
82
|
+
|
|
83
|
+
1. **按 G4 纪律完成询问**(本场景通常倾向 B「仅提交不推送」——planning commit 只需落地为 receipt 基线,未必需要推送);
|
|
84
|
+
2. 用户批复后,按其选择执行 `tf publish --changes`;
|
|
85
|
+
3. **再**以该 commit 组装 receipt 的 base..head。
|
|
86
|
+
|
|
87
|
+
> 若跳过询问静默执行,等于替用户决定了 G4 的结果——**收据先于闸门 = 伪绿方向**。
|
|
88
|
+
> 反过来把 G4 延到下一波次同样脱节。所以唯一正确顺序是「先问 → 再 publish → 再建 receipt」。
|
|
89
|
+
|
|
90
|
+
- **⛔ 有代码的波次不得借用本协议**——它不是放宽范围校验的口子,只为消掉「每次重新发明」的浪费。
|
|
91
|
+
- **命名空间提示**:本协议的 `G4` 属**团队同步点编号 G1–G5**;契约 `## Gate Registry` 里的 `G-1`/`G-2`
|
|
92
|
+
是**命令型质量闸门**编号——**两套编号互不相干**,不要混用。
|
|
@@ -107,6 +107,8 @@ Run `tf solutions inject --phase review --limit 15` (never blocks on failure)
|
|
|
107
107
|
3. Read `design.md` to understand architectural decisions
|
|
108
108
|
4. Get the list of changed files: `git diff --name-only BASE..HEAD` or from the change directory
|
|
109
109
|
|
|
110
|
+
5. **根仓 planning 制品 diff 单列(v0.63.0;S3 例外 2 判定,MUST)**:多仓场景下 `BASE..HEAD` 解析到**子仓**,而 planning 四件在**根仓** `changes/<change-name>/`——子仓 diff 里**看不到它们是否被改**。故须额外单列 `proposal.md` / `specs/` / `design.md` / `tasks.md` / `execution-contract.md` 的 diff(相对 DP-3 批准时点)。**基线获取**:优先取 G4 publish 产生的 planning commit;无则 `git log --format=%H --before='<dp_3_timestamp>' -- <paths>` 取最后提交;仍无(未跟踪文件)则以 `state.artifacts_hash` 不匹配为触发信号,diff 工作区 vs HEAD 并在报告注明「基线降级」。判定:有改动 + 已登记 `## Errata Register` 且判定依据成立 → 通过;有改动 + 未登记,或实为 gate-affecting(矩阵 `expected`/方法名、闸门基线数字、`## Test Matrix` 段)→ **Critical finding**(`frozen-artifact-modified`)。**不采信实施方对「陈述性」的自判**——判定权在本步。
|
|
111
|
+
|
|
110
112
|
### Step 1b: File Existence Check (前置, v0.43.1)
|
|
111
113
|
|
|
112
114
|
在 spec-compliance 之前校验 tasks.md 声明的文件是否实际落地(设计增强方案 v0.18 §75,来源:workflow-feedback 2026-08-06——build-executor 标记 Task 完成但文件未创建,审查未发现直到 closing):
|
|
@@ -160,6 +162,8 @@ Check for:
|
|
|
160
162
|
|
|
161
163
|
If `test-matrix.md` exists in the change directory, audit the implementation against it:
|
|
162
164
|
|
|
165
|
+
> **与 build-executor 对账表的关系(v0.63.0,S4)**:build-executor 的 `.superpowers/test-evidence/<wave>-case-test-reconciliation.md` 是**交付自检**(左移)。**本步独立复核权不减免**(审查侧不采信实施方自查);对账表可作交叉线索,但**不得**以它「已过」替代逐 case 核验。两者是「左移 + 复核」两条路径,非重复劳动。
|
|
166
|
+
|
|
163
167
|
1. **Case-by-case verification**: For each case in the matrix:
|
|
164
168
|
- Check if the test implementation exists (`test_file` + `test_method_name` match)
|
|
165
169
|
- Verify assertions match the matrix's `expected` output
|
|
@@ -36,6 +36,10 @@ Before finalizing:
|
|
|
36
36
|
|
|
37
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.
|
|
38
38
|
|
|
39
|
+
**`## Errata Register`(勘误登记段,v0.63.0 新增)**:DP-3 批准后 planning 四件默认**冻结**,陈述性订正改记入契约的 `## Errata Register` 段(不改 planning 原文),以减少 `artifacts_hash` 漂移 → rebuild → revise 回路。段模板、六条冻结例外、三分处方表(matrix→rebuild / 契约段→refresh-hash / wave→revise)、**勘误写入后 MUST `tf execution refresh-hash`** 的操作序、以及例外 2 的判定升格与呈报纪律——**详见 `references/freeze-and-errata.md`(MUST 按该文件执行)**。
|
|
40
|
+
|
|
41
|
+
**`## Gate Registry`(闸门登记段,v0.63.0 新增,MUST)**:列 `| id | phase | command | expected |`,声明本 change 全部 G 类闸门(`id` 形如 `G-1`),`gates-probed` 门禁按此逐 id 核对 dry-run 留档。**段存在性是硬要求**——缺段/解析失败 = FAIL(缺段与「零闸门」不可区分,v0.13 RC-1 内容型豁免已删除);确无闸门写 `N/A: <理由>` 一行。`G-<n>`(命令型闸门)与团队同步点 G1–G5 是两套编号。模板与判定规则见 `references/bridging-gate-dry-run.md`。
|
|
42
|
+
|
|
39
43
|
## UI UX Delta Prototype Reference (v0.37.0 §68.5)
|
|
40
44
|
|
|
41
45
|
When the change involves UI (design.md has a `## UI Contract` section), the execution-contract's `## UX 增量` section (consumed by `tf prototype-sync`) must **state the prototype version worktree path** in its first line:
|
|
@@ -181,6 +185,8 @@ Still requires DP-3 approval.
|
|
|
181
185
|
|
|
182
186
|
**`tasks.md` 归属(v0.22 §85)**:hotfix/tweak 默认跳过(上条),但若该 change 确实需要任务记录,`tasks.md` 由本 skill 一并产出——归属 contract-builder(本 skill 已有 `tasks.md → Execution Batches` 的 Artifact Mapping,反向生成成本最低);任务文本不再经 spec-writer(hotfix/tweak 已跳过它)。
|
|
183
187
|
|
|
188
|
+
**该路径同样强制 `- [ ]` 形态(v0.63.0;feedback 20260923-013114 E1 横展)**:本 skill 产出的 `tasks.md`,**任务行 MUST 为 `- [ ]` checkbox 形态**——与 `spec-writer` 校验清单同口径,**hotfix/tweak 路径不因轻量而豁免**(否则零 checkbox → `tasks-complete` closing 死锁原样复现,且事后补勾选同样触发 `artifacts_hash` 漂移)。
|
|
189
|
+
|
|
184
190
|
## Guardrails
|
|
185
191
|
|
|
186
192
|
- **状态字段禁写(v0.30.0;v0.22 §85 澄清写入白名单)**:仅写本 skill 的 `dp_3_*` 决策字段,以及本 skill 职责内的门禁豁免键——`test_matrix_skipped` / `test_matrix_skip_reason`(v0.13 §50)、`tasks_skipped` / `tasks_skip_reason`(v0.22 §85);**MUST NOT** 修改 `state`/`workflow` 核心字段——状态转换由主代理经 `tf state transition` 执行。`tf state init` 只创建状态文件,不改 `state` 值(来源:workflow-feedback 2026-08-01)。
|
|
@@ -192,6 +198,21 @@ Still requires DP-3 approval.
|
|
|
192
198
|
|
|
193
199
|
## Post-Generation
|
|
194
200
|
|
|
201
|
+
### 契约 post-generation 两动作(v0.63.0,MUST,均在 `tf state init` 之前)
|
|
202
|
+
|
|
203
|
+
**① Facts Recheck**:对 `facts.json` 中契约将引用的键复测一次(防 specifying→bridging 漂移),差异写 `facts.bridging_recheck`。
|
|
204
|
+
**位置**:契约初稿完成后、dry-run 之前(复测可能改变闸门 `expected` 基线数字,草稿态回写成本最低)。
|
|
205
|
+
**差异(含超口径项)MUST 并入 DP-3 批准 ask 呈报**,裁决权归 LT——不得由实施方自行解释掉(错判即伪绿)。
|
|
206
|
+
|
|
207
|
+
**② Bridging Gate Dry-Run**:对每个 **pre-build** 闸门在主工作区当前态跑一次(预期 FAIL = RED 基线),落
|
|
208
|
+
`.superpowers/test-evidence/bridging-gates-red.txt`。硬要求:首行逐字 `EXPECTED: FAIL (RED baseline)` /
|
|
209
|
+
必须含 `CONTRACT_HASH: sha256:…` 行(新鲜度按**内容**判,不用 mtime)/ 每个注册 id 一个 `[G-<id>]` 分节 /
|
|
210
|
+
原始输出先落文件 / 多仓逐仓分节 cwd / `post-build` 闸门只做语法可执行性 probe。
|
|
211
|
+
若某闸门意外 PASS → 复核契约声明(它不是有效基线),不要改 evidence。
|
|
212
|
+
**Rewind 或契约重生成后 evidence 失效,须重跑。**
|
|
213
|
+
|
|
214
|
+
> 两动作的完整模板与理由见 `references/bridging-gate-dry-run.md`。
|
|
215
|
+
|
|
195
216
|
Run `tf state init <change-dir>` to create `.team-flow.yaml` with hashes.
|
|
196
217
|
|
|
197
218
|
For hotfix, after writing the minimal contract, run `tf state init <change-dir>` or `tf state rebuild <change-dir>` so `contract_hash` is recorded. DP-3 remains mandatory before build.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# bridging 闸门登记与 dry-run 留档(v0.63.0;feedback 20260923-013114 S2 + S1 复测)
|
|
2
|
+
|
|
3
|
+
本文件承载契约 post-generation 的两个动作细则。SKILL 保留 MUST 与指针,细则在此。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 一、`## Gate Registry`(闸门登记段,MUST)
|
|
8
|
+
|
|
9
|
+
声明本 change 的全部 G 类闸门,`gates-probed` 门禁按此逐 id 核对 dry-run 留档。列固定为 `| id | phase | command | expected |`:
|
|
10
|
+
|
|
11
|
+
```markdown
|
|
12
|
+
## Gate Registry
|
|
13
|
+
|
|
14
|
+
| id | phase | command | expected |
|
|
15
|
+
|----|-------|---------|----------|
|
|
16
|
+
| G-1 | pre-build | `npx eslint src/` | 0 errors |
|
|
17
|
+
| G-2 | pre-build | `npm run test:unit -- --coverage` | covered 132 |
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- `id` 形如 `G-1`/`G-2`,须与契约内各闸门小节**一一对应**(审查侧会核对)。
|
|
21
|
+
- **`G-<n>` 是命令型质量闸门编号**,与团队同步点编号 **G1–G5**(§68.2 等)是**两套命名空间**,勿混用。
|
|
22
|
+
- `phase: post-build` 类闸门同样登记,其 dry-run 只做**语法/路径可执行性 probe**(不预跑结果)。
|
|
23
|
+
- 契约改动(含勘误段)后须**重跑 dry-run**(evidence 的 `CONTRACT_HASH` 比对会判陈旧)。
|
|
24
|
+
|
|
25
|
+
### 段存在性是硬要求(fail-closed)
|
|
26
|
+
|
|
27
|
+
**缺段 = `gates-probed` FAIL**——缺段与「零闸门」不可区分,v0.13 RC-1 的内容型豁免已删除。
|
|
28
|
+
|
|
29
|
+
> **workflow 限定**:本维度只挂 **full** 的 `bridging→approved-for-build`。**hotfix** 走 `WORKFLOW_TRANSITION_CHECKS` 自有覆盖、**天然不挂本维度**(无需注册该段);**tweak** 会回落继承本维度,须靠 `gates_probed_skipped` + 理由放行。
|
|
30
|
+
|
|
31
|
+
**两种「无闸门」表达的判定规则**:
|
|
32
|
+
|
|
33
|
+
| 情形 | 写法 | 结果 |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| 确无 G 类闸门 | 段存在 + `N/A: <理由>` 一行 | PASS(N/A 记录) |
|
|
36
|
+
| 临时豁免(不想写段) | `tf state set <dir> gates_probed_skipped true` + `gates_probed_skip_reason '<理由>'` | PASS(可审计豁免) |
|
|
37
|
+
| 忘写段 / 表解析失败 | — | **FAIL**(不得落 N/A) |
|
|
38
|
+
|
|
39
|
+
> 优先用**段内 `N/A: <理由>`**(理由随契约入库、随 hash 冻结);state 键是备用通道,仅在段写法不便时使用。
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 二、Bridging Gate Dry-Run(MUST,在 `tf state init` 之前)
|
|
44
|
+
|
|
45
|
+
契约产出后,对 `## Gate Registry` 声明的每个 **pre-build** 闸门,在**主工作区当前态**跑一次
|
|
46
|
+
——此时实现尚未开始,**预期结果是 FAIL**,这个 FAIL 就是 RED 基线(与 TDD 的红证据同源)。
|
|
47
|
+
|
|
48
|
+
**产出**:`.superpowers/test-evidence/bridging-gates-red.txt`
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
EXPECTED: FAIL (RED baseline)
|
|
52
|
+
CONTRACT_HASH: sha256:<64 位十六进制>
|
|
53
|
+
|
|
54
|
+
[G-1] npx eslint src/
|
|
55
|
+
<闸门原始输出,不得摘要或改写>
|
|
56
|
+
exit=1
|
|
57
|
+
|
|
58
|
+
[G-2] npm run test:unit -- --coverage
|
|
59
|
+
<闸门原始输出>
|
|
60
|
+
exit=1
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**六条硬要求**:
|
|
64
|
+
|
|
65
|
+
1. **首行逐字** `EXPECTED: FAIL (RED baseline)`;
|
|
66
|
+
2. **必须有 `CONTRACT_HASH: sha256:…` 行**,取当前 `execution-contract.md` 的 hash——新鲜度按**内容**判(不用 mtime:契约字节等价重生成、或 git 恢复会让 mtime 变新而内容未变,会误卡);
|
|
67
|
+
3. **每个注册 id 都要有 `[G-<id>]` 分节**——缺 id 会被门禁点出;
|
|
68
|
+
4. **原始输出先落文件**再写本 evidence(不写管道中间结果);
|
|
69
|
+
5. **多仓**:逐仓声明执行 cwd,evidence 内逐仓分节;
|
|
70
|
+
6. **`phase: post-build` 的闸门**只做语法/路径可执行性 probe,不预跑结果。
|
|
71
|
+
|
|
72
|
+
> 本步把 `design.md` R-7「闸门命令已实测可跑」的文字自证物化为机械证据。
|
|
73
|
+
> 若某闸门在此步**意外 PASS**,说明它不是有效基线(已实现/已满足),须复核契约声明而非改 evidence。
|
|
74
|
+
> **Rewind 或契约重生成后,既存 evidence 失效**,须重跑(`CONTRACT_HASH` 比对可兜底,但纪律须遵守)。
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 三、Facts Recheck(MUST,在 dry-run 之前)
|
|
79
|
+
|
|
80
|
+
对 `<change-dir>/.superpowers/facts.json` 中**契约将要引用的键**复测一次(防 specifying→bridging 期间漂移),
|
|
81
|
+
差异写入 `facts.bridging_recheck` 段。
|
|
82
|
+
|
|
83
|
+
**位置说明(避免与 §3.1 的「生成前」表述混淆)**:复测动作在**契约初稿完成后、dry-run 之前**执行——
|
|
84
|
+
因为复测结果可能改变契约为闸门声明的基线数字(`expected` 列),此时契约尚在草稿态、回写成本最低。
|
|
85
|
+
**DP-3 批准 ask 必须晚于本复测**(差异摘要要并入那次 ask)。
|
|
86
|
+
|
|
87
|
+
**差异呈报(MUST)**:差异摘要(含**超出口径声明**的项)**并入 DP-3 批准 ask 一并呈报**,裁决权归 LT。
|
|
88
|
+
**不得**由实施方(含主会话)自行解释掉——错判方向即伪绿(把超口径差异解释为「口径问题」→ 闸门基线数字错)。
|
|
89
|
+
无法在声明口径内解释的差异 → 触发**契约侧重签判断**,不要带着已知漂移进入执行。
|