@xulthekl/team-flow 0.48.0 → 0.50.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.
Files changed (75) hide show
  1. package/.claude/always/phase-guard.md +1 -1
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/.cursor-plugin/marketplace.json +1 -1
  6. package/.cursor-plugin/plugin.json +1 -1
  7. package/.github/plugin/marketplace.json +2 -2
  8. package/AGENTS.md +2 -2
  9. package/CHANGELOG.md +76 -0
  10. package/GEMINI.md +1 -1
  11. package/INSTALL.md +3 -3
  12. package/README.md +3 -3
  13. package/agents/architecture-design.md +1 -1
  14. package/agents/code-reviewer.md +1 -1
  15. package/docs/README_en.md +2 -2
  16. package/docs/artifact-contract.md +2 -0
  17. package/docs/decision-points.md +23 -0
  18. package/docs/solutions/INDEX.md +0 -14
  19. package/docs/state-machine.md +1 -1
  20. package/docs/usage-guide.md +7 -4
  21. package/gemini-extension.json +1 -1
  22. package/hooks/session-start +2 -2
  23. package/llms.txt +1 -1
  24. package/package.json +2 -1
  25. package/plugin.json +1 -1
  26. package/scripts/guard/checks/compound-captured.mjs +6 -3
  27. package/scripts/guard/checks/tasks-complete.mjs +39 -3
  28. package/scripts/guard/checks/tasks-gate-exemptions.mjs +49 -0
  29. package/scripts/lib/arch-precheck.mjs +190 -0
  30. package/scripts/lib/cmd-arch.mjs +5 -1
  31. package/scripts/lib/cmd-doctor.mjs +9 -2
  32. package/scripts/lib/cmd-runtime.mjs +1 -0
  33. package/scripts/lib/cmd-state.mjs +2 -0
  34. package/scripts/lib/execution-plan.mjs +72 -25
  35. package/scripts/lib/execution-recommendation.mjs +4 -18
  36. package/scripts/lib/hash.mjs +41 -2
  37. package/scripts/lib/prototype-sync.mjs +2 -1
  38. package/scripts/lib/sdd-overlay.mjs +3 -2
  39. package/scripts/lib/solutions-capture.mjs +2 -1
  40. package/scripts/lib/solutions-index-gen.mjs +2 -1
  41. package/scripts/lib/solutions-inject.mjs +2 -1
  42. package/scripts/lib/solutions-promote.mjs +90 -12
  43. package/scripts/lib/state-loader.mjs +7 -0
  44. package/scripts/lib/test-record.mjs +67 -21
  45. package/scripts/lint/rules/behavior-consistency.mjs +3 -1
  46. package/scripts/team-flow.mjs +8 -1
  47. package/skills/architecture-design/SKILL.md +17 -3
  48. package/skills/build-executor/SKILL.md +10 -4
  49. package/skills/build-executor/references/execution-modes.md +1 -1
  50. package/skills/build-executor/task-reviewer-prompt.md +5 -4
  51. package/skills/ce-compound/references/promotion-rules.md +1 -1
  52. package/skills/ce-compound/references/schema.yaml +10 -1
  53. package/skills/code-reviewer/SKILL.md +1 -1
  54. package/skills/code-reviewer/code-reviewer-prompt.md +5 -4
  55. package/skills/contract-builder/SKILL.md +35 -4
  56. package/skills/contract-builder/references/glaf4-delegation.md +5 -3
  57. package/skills/release-archivist/SKILL.md +18 -10
  58. package/skills/release-archivist/references/closing-procedures.md +7 -2
  59. package/skills/workflow-start/SKILL.md +19 -7
  60. package/skills/workflow-start/references/routing-rules.md +3 -1
  61. package/templates/learnings.md +51 -0
  62. package/docs/solutions/cross-phase/2026-07-28-no-summary.md +0 -17
  63. package/docs/solutions/cross-phase/2026-07-29-no-summary.md +0 -17
  64. package/docs/solutions/cross-phase/2026-07-30-no-summary.md +0 -17
  65. package/docs/solutions/cross-phase/2026-07-31-no-summary.md +0 -17
  66. package/docs/solutions/cross-phase/2026-08-01-no-summary.md +0 -17
  67. package/docs/solutions/cross-phase/2026-08-03-no-summary.md +0 -17
  68. package/docs/solutions/cross-phase/2026-08-04-no-summary.md +0 -17
  69. package/docs/solutions/cross-phase/2026-08-05-no-summary.md +0 -17
  70. package/docs/solutions/cross-phase/2026-08-06-no-summary.md +0 -17
  71. package/docs/solutions/cross-phase/2026-08-07-no-summary.md +0 -17
  72. package/docs/solutions/cross-phase/2026-08-17-no-summary.md +0 -17
  73. package/docs/solutions/cross-phase/2026-08-18-no-summary.md +0 -17
  74. package/docs/solutions/cross-phase/2026-08-19-no-summary.md +0 -17
  75. package/docs/solutions/cross-phase/2026-08-21-no-summary.md +0 -17
@@ -6,7 +6,8 @@
6
6
  * 用法:tf solutions promote <change-dir> [--dir <solutions-dir>]
7
7
  *
8
8
  * 功能:
9
- * 1. 读取 specs/<cap>/learnings.md
9
+ * 1. 读取 change 根 learnings.md(v0.49.0 §83.3.5:统一路径——此前注释误写 specs/<cap>/,
10
+ * 与本文件第 58 行的实际实现及 compound-captured guard 均不一致)
10
11
  * 2. 逐条检查晋升条件(severity ≥ medium 且 type = pitfall/pattern)
11
12
  * 3. 检查与全局 INDEX 是否重复(domain+type 匹配)
12
13
  * 4. 符合条件 → 写入全局 docs/solutions/
@@ -19,6 +20,7 @@
19
20
 
20
21
  import { readFileSync, writeFileSync, existsSync, appendFileSync, mkdirSync } from 'node:fs';
21
22
  import { join, basename } from 'node:path';
23
+ import { pathToFileURL } from 'node:url';
22
24
 
23
25
  function parseFrontmatter(content) {
24
26
  // learnings.md 中每个条目以 `## 标题` 开头,frontmatter 紧跟标题行之后;
@@ -43,7 +45,59 @@ function parseLearnings(content) {
43
45
  const title = lines[0]?.trim() || '';
44
46
  const fm = parseFrontmatter(s);
45
47
  return { title, fm, body: s.trim() };
46
- }).filter(e => e.title && e.title !== 'Learnings');
48
+ // v0.49.0 §83.3.5:排除文件级标题(`# Session Learnings` 会被 split 成首个 section),
49
+ // 否则它会被当成一条无 frontmatter 的条目计入 skipped
50
+ }).filter(e => e.title && e.title !== 'Learnings' && !e.title.startsWith('#'));
51
+ }
52
+
53
+ /**
54
+ * v0.49.0 §83.3.5:把解析出的条目重整为可写入全局文件的形式 ——
55
+ * ① 补回 `## ` 标题前缀(parseLearnings 按 `^## ` 分割,body 首行不含标记)
56
+ * ② 剔除 body 中已含的原 frontmatter 块(原实现直接写 body → 产出双 frontmatter)
57
+ */
58
+ function renderEntryBody(learning) {
59
+ const body = learning.body
60
+ .replace(/^[^\n]*\n?/, '')
61
+ .replace(/(?:^|\n)---\n[\s\S]*?\n---[ \t]*\n?/, '\n')
62
+ .trim();
63
+ return `## ${learning.title}\n\n${body}`;
64
+ }
65
+
66
+ const SEVERITY_LADDER = { low: 'medium', medium: 'high' };
67
+
68
+ /**
69
+ * v0.49.0 §83.3.5:重复命中时按 promotion-rules.md 承诺真正落盘(原实现只 `updated++`,
70
+ * 不更新 INDEX 行、不标记条目)——升级 INDEX 行 severity + 条目文件 confirmed 计数。
71
+ */
72
+ function confirmExistingEntry(solutionsDir, indexContent, domain, type) {
73
+ const lines = indexContent.split('\n');
74
+ for (let i = 0; i < lines.length; i += 1) {
75
+ // INDEX 列:| date | phase | domain | type | severity | summary | file |
76
+ const cols = lines[i].split('|').map(column => column.trim());
77
+ if (cols.length < 9 || cols[3] !== domain || cols[4] !== type) continue;
78
+
79
+ const currentSeverity = cols[5];
80
+ const nextSeverity = SEVERITY_LADDER[currentSeverity] ?? currentSeverity;
81
+ if (nextSeverity !== currentSeverity) {
82
+ lines[i] = lines[i].replace(`| ${currentSeverity} |`, `| ${nextSeverity} |`);
83
+ }
84
+ markEntryConfirmed(join(solutionsDir, cols[7]));
85
+ return { indexContent: lines.join('\n'), from: currentSeverity, to: nextSeverity, file: cols[7] };
86
+ }
87
+ return null;
88
+ }
89
+
90
+ function markEntryConfirmed(filePath) {
91
+ if (!existsSync(filePath)) return;
92
+ const content = readFileSync(filePath, 'utf-8');
93
+ const block = content.match(/^---\n([\s\S]*?)\n---/);
94
+ if (!block) return;
95
+ const counter = block[1].match(/^confirmed:\s*(\d+)\s*$/m);
96
+ const next = counter ? parseInt(counter[1], 10) + 1 : 2;
97
+ const frontmatter = counter
98
+ ? block[1].replace(/^confirmed:\s*\d+\s*$/m, `confirmed: ${next}`)
99
+ : `${block[1]}\nconfirmed: ${next}`;
100
+ writeFileSync(filePath, content.replace(block[0], `---\n${frontmatter}\n---`), 'utf-8');
47
101
  }
48
102
 
49
103
  export function run(args = {}) {
@@ -58,7 +112,7 @@ export function run(args = {}) {
58
112
  const learningsPath = join(changeDir, 'learnings.md');
59
113
  if (!existsSync(learningsPath)) {
60
114
  console.log(`No learnings.md found in ${changeDir}, nothing to promote`);
61
- return { promoted: 0, updated: 0 };
115
+ return { promoted: 0, updated: 0, skipped: 0 };
62
116
  }
63
117
 
64
118
  const content = readFileSync(learningsPath, 'utf-8');
@@ -66,15 +120,17 @@ export function run(args = {}) {
66
120
 
67
121
  if (learnings.length === 0) {
68
122
  console.log('No learning entries found');
69
- return { promoted: 0, updated: 0 };
123
+ return { promoted: 0, updated: 0, skipped: 0 };
70
124
  }
71
125
 
72
126
  // 读取全局 INDEX
73
127
  const indexPath = join(solutionsDir, 'INDEX.md');
74
- const indexContent = existsSync(indexPath) ? readFileSync(indexPath, 'utf-8') : '';
128
+ let indexContent = existsSync(indexPath) ? readFileSync(indexPath, 'utf-8') : '';
75
129
 
76
130
  let promoted = 0;
77
131
  let updated = 0;
132
+ // v0.49.0 §83.3.5:跳过原因可见化(原实现静默 continue,用户看不出为什么一条都没晋升)
133
+ const skipped = [];
78
134
 
79
135
  for (const learning of learnings) {
80
136
  const severity = learning.fm?.severity || 'low';
@@ -85,12 +141,27 @@ export function run(args = {}) {
85
141
  // 晋升条件:severity ≥ medium 且 type = pitfall/pattern
86
142
  const sevOk = severity === 'high' || severity === 'medium';
87
143
  const typeOk = type === 'pitfall' || type === 'pattern';
88
- if (!sevOk || !typeOk) continue;
144
+ if (!sevOk || !typeOk) {
145
+ skipped.push({
146
+ title: learning.title,
147
+ reason: learning.fm
148
+ ? `severity=${severity}, type=${type}(需 severity ≥ medium 且 type = pitfall|pattern)`
149
+ : 'no frontmatter(缺 severity/type,按默认 low/insight 处理)',
150
+ });
151
+ continue;
152
+ }
89
153
 
90
154
  // 检查重复:domain+type 匹配
91
155
  const dupRegex = new RegExp(`\\| ${domain} \\| ${type} \\|`);
92
156
  if (dupRegex.test(indexContent)) {
93
- console.log(`Duplicate found (${domain}/${type}), marking as confirmed pattern`);
157
+ const outcome = confirmExistingEntry(solutionsDir, indexContent, domain, type);
158
+ if (!outcome) {
159
+ skipped.push({ title: learning.title, reason: `duplicate ${domain}/${type} 但 INDEX 行无法定位` });
160
+ continue;
161
+ }
162
+ indexContent = outcome.indexContent;
163
+ writeFileSync(indexPath, indexContent, 'utf-8');
164
+ console.log(`Confirmed: ${domain}/${type} severity ${outcome.from} → ${outcome.to}(${outcome.file})`);
94
165
  updated++;
95
166
  continue;
96
167
  }
@@ -115,22 +186,29 @@ date: ${date}
115
186
  source: ${basename(changeDir)}
116
187
  ---
117
188
 
118
- ${learning.body}
189
+ ${renderEntryBody(learning)}
119
190
  `;
120
191
  writeFileSync(filePath, fileContent, 'utf-8');
121
192
 
122
193
  // 追加 INDEX
123
- appendFileSync(indexPath, `| ${date} | ${phase} | ${domain} | ${type} | ${severity} | ${learning.title.slice(0, 80)} | ${phase}/${fileName} |\n`, 'utf-8');
194
+ const indexRow = `| ${date} | ${phase} | ${domain} | ${type} | ${severity} | ${learning.title.slice(0, 80)} | ${phase}/${fileName} |\n`;
195
+ appendFileSync(indexPath, indexRow, 'utf-8');
196
+ indexContent += indexRow;
124
197
 
125
198
  console.log(`Promoted: ${phase}/${fileName}`);
126
199
  promoted++;
127
200
  }
128
201
 
129
- console.log(`\nPromotion complete: ${promoted} promoted, ${updated} updated as confirmed`);
130
- return { promoted, updated };
202
+ // v0.49.0 §83.3.5:解析/晋升/确认/跳过汇总(原实现只报 promoted/updated
203
+ console.log(`\nPromotion complete: ${promoted} promoted, ${updated} confirmed, ${skipped.length} skipped`);
204
+ if (skipped.length > 0) {
205
+ console.log('Skipped entries:');
206
+ for (const item of skipped) console.log(` - ${item.title}: ${item.reason}`);
207
+ }
208
+ return { promoted, updated, skipped: skipped.length };
131
209
  }
132
210
 
133
- if (process.env.NODE_ENV !== 'test' && process.argv[1]?.includes('solutions-promote')) {
211
+ if (process.env.NODE_ENV !== 'test' && process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
134
212
  const args = { _: [] };
135
213
  for (let i = 2; i < process.argv.length; i++) {
136
214
  if (process.argv[i].startsWith('--')) {
@@ -74,6 +74,9 @@ const BUILTIN_DEFAULTS = {
74
74
  test_matrix_skip_reason: null,
75
75
  // Test evidence (v0.13 §50:tf test record 落盘的 runner 输出证据路径)
76
76
  test_evidence_path: null,
77
+ // Tasks gate (v0.22 §85:hotfix/tweak 跳过 spec-writer 时显式跳过 tasks.md)
78
+ tasks_skipped: null,
79
+ tasks_skip_reason: null,
77
80
  // 注意:schema_version 故意不在 BUILTIN_DEFAULTS 中(v0.13 §48.1)——
78
81
  // 它只由 `tf state init` 在 change 创建时打戳,字段缺失本身就是"存量 change"信号。
79
82
  };
@@ -196,6 +199,10 @@ export function writeState(changeDir, state) {
196
199
  lines.push('');
197
200
  lines.push('# === Test evidence (v0.13 §50) ===');
198
201
  lines.push(`test_evidence_path: ${state.test_evidence_path ?? 'null'}`);
202
+ lines.push('');
203
+ lines.push('# === Tasks gate (v0.22 §85) ===');
204
+ lines.push(`tasks_skipped: ${state.tasks_skipped ?? 'null'}`);
205
+ lines.push(`tasks_skip_reason: ${state.tasks_skip_reason ?? 'null'}`);
199
206
 
200
207
  fs.writeFileSync(filePath, lines.join('\n') + '\n', 'utf-8');
201
208
  }
@@ -33,30 +33,54 @@ export function parseMavenSurefire(text) {
33
33
  return { total, passed: total - failures - errors - skipped, failed: failures + errors, skipped };
34
34
  }
35
35
 
36
- /** maven surefire XML 报告目录(target/surefire-reports):累加 <testsuite> 属性。 */
37
- export function parseSurefireReportDir(dir) {
36
+ /**
37
+ * 通用 junit XML 解析:累加 <testsuite> 的 tests/failures/errors/skipped 属性。
38
+ *
39
+ * v0.49.0 §83.3.6(来源:workflow-feedback 20260909):maven-surefire 与 pytest 的
40
+ * junit XML 结构同构(<testsuites>/<testsuite>)。此前该逻辑只服务 maven-surefire,
41
+ * pytest runner 只认 terminal summary —— 同一 CLI 对不同 runner 的结构化支持不对称。
42
+ */
43
+ export function parseJunitXml(text) {
38
44
  let total = 0; let failures = 0; let errors = 0; let skipped = 0;
39
45
  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
- }
46
+ for (const tag of text.matchAll(/<testsuite\b[^>]*>/g)) {
47
+ const attrs = tag[0];
48
+ const pick = (key) => {
49
+ const am = attrs.match(new RegExp(`\\b${key}="(\\d+)"`));
50
+ return am ? parseInt(am[1], 10) : 0;
51
+ };
52
+ found = true;
53
+ total += pick('tests');
54
+ failures += pick('failures');
55
+ errors += pick('errors');
56
+ skipped += pick('skipped');
55
57
  }
56
58
  if (!found) return null;
57
59
  return { total, passed: total - failures - errors - skipped, failed: failures + errors, skipped };
58
60
  }
59
61
 
62
+ /** junit XML 内容特征(用于嗅探;只检查头部,避免大报告全量扫描)。 */
63
+ function looksLikeJunitXml(text) {
64
+ return /<testsuites?\b/.test(text.slice(0, 512));
65
+ }
66
+
67
+ /** maven surefire XML 报告目录(target/surefire-reports):累加目录内所有 XML。 */
68
+ export function parseSurefireReportDir(dir) {
69
+ let aggregated = null;
70
+ for (const name of readdirSync(dir)) {
71
+ if (!name.endsWith('.xml')) continue;
72
+ const parsed = parseJunitXml(readFileSync(join(dir, name), 'utf-8'));
73
+ if (!parsed) continue;
74
+ aggregated = aggregated === null ? parsed : {
75
+ total: aggregated.total + parsed.total,
76
+ passed: aggregated.passed + parsed.passed,
77
+ failed: aggregated.failed + parsed.failed,
78
+ skipped: aggregated.skipped + parsed.skipped,
79
+ };
80
+ }
81
+ return aggregated;
82
+ }
83
+
60
84
  /** jest --json 输出。 */
61
85
  export function parseJest(text) {
62
86
  let data;
@@ -69,8 +93,18 @@ export function parseJest(text) {
69
93
  return { total, passed, failed, skipped };
70
94
  }
71
95
 
72
- /** pytest terminal summary:"== 5 passed, 2 failed, 1 skipped in 3.21s ==" */
96
+ /**
97
+ * pytest 输出:junit XML(`--junitxml=<path>`)或 terminal summary
98
+ * ("== 5 passed, 2 failed, 1 skipped in 3.21s ==")。
99
+ *
100
+ * v0.49.0 §83.3.6:XML 优先 —— 结构稳定,不受 `-q`/`-v`/颜色码/`--tb` 影响,
101
+ * 且 CI 流水线天然产出 XML(来源:workflow-feedback 20260909)。
102
+ */
73
103
  export function parsePytest(text) {
104
+ if (looksLikeJunitXml(text)) {
105
+ const xml = parseJunitXml(text);
106
+ if (xml) return xml;
107
+ }
74
108
  const lines = text.split('\n');
75
109
  const summaryLine = [...lines].reverse().find(l => /=+\s.*(passed|failed|error|no tests ran)/.test(l));
76
110
  if (!summaryLine) return null;
@@ -142,9 +176,16 @@ export function classifyFailure(text) {
142
176
  return 'unknown';
143
177
  }
144
178
 
145
- /** auto 识别:按内容特征匹配 runner。 */
179
+ /**
180
+ * auto 识别:按内容特征匹配 runner。
181
+ *
182
+ * v0.49.0 §83.3.6:junit XML 特征优先嗅探。surefire 与 pytest 的 XML 同构,auto 模式
183
+ * 统一归入 maven-surefire(解析结果相同);需要把 runner 记为 pytest 时显式传
184
+ * `--runner pytest`(同样支持 XML)。
185
+ */
146
186
  export function detectRunner(text) {
147
187
  const trimmed = text.trim();
188
+ if (looksLikeJunitXml(trimmed) && parseJunitXml(trimmed)) return 'maven-surefire';
148
189
  if (trimmed.startsWith('{') && parseJest(trimmed)) return 'jest';
149
190
  if (/Tests run:\s*\d+,\s*Failures:/.test(trimmed)) return 'maven-surefire';
150
191
  if (parsePytest(trimmed)) return 'pytest';
@@ -164,7 +205,8 @@ export async function run(args) {
164
205
  allowPositionals: true,
165
206
  });
166
207
 
167
- const usageMsg = 'Usage: tf test record <change-dir> --from <runner-output-file|surefire-report-dir> [--runner auto|maven-surefire|jest|pytest] [--json]';
208
+ const usageMsg = 'Usage: tf test record <change-dir> --from <runner-output-file|surefire-report-dir> [--runner auto|maven-surefire|jest|pytest] [--json]\n'
209
+ + ' maven-surefire: console summary, surefire XML dir/file; pytest: terminal summary or junit XML (--junitxml); jest: --json';
168
210
  if (positionals[0] !== 'record') {
169
211
  console.error(usageMsg);
170
212
  process.exit(2);
@@ -222,7 +264,11 @@ export async function run(args) {
222
264
  stats = PARSERS[runner](text);
223
265
  }
224
266
  if (!stats) {
225
- console.error(`Could not parse ${runner} output in ${fromPath} — no recognizable test summary found.`);
267
+ // v0.49.0 §83.3.6:错误信息附输入形态指引(原提示对"传了 XML"的用户无帮助)
268
+ const hint = runner === 'pytest'
269
+ ? 'pytest accepts a terminal summary or a junit XML report (pytest --junitxml=<path>).'
270
+ : `Supported runners: ${SUPPORTED_RUNNERS.join(', ')} (or pass --runner explicitly).`;
271
+ console.error(`Could not parse ${runner} output in ${fromPath} — no recognizable test summary found.\n${hint}`);
226
272
  process.exit(1);
227
273
  }
228
274
 
@@ -25,7 +25,9 @@ export default {
25
25
 
26
26
  // Check 2: "route to" consistency with workflow-start
27
27
  if (skillName !== 'workflow-start') {
28
- const routeRefs = [...content.matchAll(/[Rr]oute to [`""]?([a-z-]+)[`""]?/g)];
28
+ // v0.22 §90:加 `(?![a-z\/-])` 排除路径式目标——原正则把 "route to `references/xxx.md`"
29
+ // 捕获为 skill 名 "references",产生 error 级误报(ce-plan SKILL.md:64)。
30
+ const routeRefs = [...content.matchAll(/[Rr]oute to [`""]?([a-z-]+)[`""]?(?![a-z\/-])/g)];
29
31
  for (const [, target] of routeRefs) {
30
32
  // This skill says "route to X" — workflow-start should have a corresponding rule
31
33
  // We flag this for manual verification (can't easily cross-check without loading workflow-start)
@@ -67,6 +67,8 @@ Commands:
67
67
  arch init [--mode reconstruction|design] [--baseline-ref <prd/vN/>]
68
68
  Stamp project-level arch_baseline into .team-flow/arch-state.json (v0.35.0 §59.4)
69
69
  arch show Show current project architecture baseline state
70
+ arch precheck <change-dir> [--json]
71
+ Emit deterministic architecture-gate evidence (v0.22 §88; evidence only, exit 0)
70
72
  arch-merge <change-dir> [--project-root <path>] [--dry-run]
71
73
  Merge architecture delta into global docs/architecture/
72
74
  test-merge <change-dir> [--project-root <path>] [--dry-run]
@@ -81,6 +83,9 @@ Commands:
81
83
  Detect project layout (single/monorepo/multi-repo) + code repos, write repo_layout config (v1.0 §3)
82
84
  test record <dir> --from <runner-output> [--runner auto|maven-surefire|jest|pytest]
83
85
  Record programmatic test evidence (v0.13 §50; feeds tests-passing gate)
86
+ jest requires --json output (e.g. npx jest --json --outputFile=<path>);
87
+ maven-surefire: console summary or surefire XML dir/file;
88
+ pytest: terminal summary or junit XML (--junitxml)
84
89
  config [options] Display or modify configuration
85
90
  config --resolve-model <profile> Resolve a configured model profile without switching models
86
91
  state <sub> <dir> Manage .team-flow.yaml state (init|check|transition|get|rebuild)
@@ -109,7 +114,9 @@ Commands:
109
114
  execution revise <change-dir> --mode sdd --confirm --reason <text> --wave <id>:<strategy>:<task,...> [--acknowledge-recommendation]
110
115
  Upgrade inline/batch to SDD, or replan existing SDD waves, as a new revision
111
116
  execution review <change-dir> --wave <id> --base <sha> --head <sha> --report <path> --verdict pass|fail
112
- Record one review receipt for a planned wave
117
+ Record one review receipt for a planned wave.
118
+ --report must resolve inside <change-dir>/.superpowers/sdd/reviews/
119
+ (the change review overlay; other paths are rejected)
113
120
  deisolate <change-dir> [--merge] [--force] [--clean] [--json]
114
121
  Show worktree status / merge branch back / clean worktree
115
122
  runtime check-update Run a portable update check for canonical skills
@@ -67,7 +67,7 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
67
67
 
68
68
  - `change-brief.md`(scope / AC / 技术方向)
69
69
  - `requirement/vN/plan.md` 高阶技术设计段(模块边界/技术选型/数据流/关键聚合划分)
70
- - `docs/architecture/iterations/vN/architecture.md`(产品级架构快照,**主输入**,v0.35.0)——BC 边界/聚合所有权/全局契约的唯一事实源
70
+ - `docs/architecture/iterations/vN/architecture.md`(产品级架构快照,**主输入**,v0.35.0)——BC 边界/聚合所有权/全局契约的唯一事实源;**Fast Path 下不读**(见 `### Fast Path`)
71
71
  - 全局 `docs/architecture/`(As-Is 实际态基线,已落地部分)
72
72
  - 现有 `specs/`(若有)
73
73
 
@@ -81,6 +81,20 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
81
81
  4. **API 变更**:是否涉及 API 新增/变更(端点、方法签名、请求响应 schema)
82
82
  5. **DB schema 变更**:是否涉及数据库表结构、字段、索引变更
83
83
 
84
+ ### Fast Path:precheck 证据驱动(v0.22 §88.3.2)
85
+
86
+ > **术语区分**:本节的 Fast Path 专指**架构判断门的快路径**,与 workflow-start 的 Fast-Path Routing(hotfix/tweak 路由)无关。
87
+ > **优先级**:本节条件优先于下文「执行流程」与「上下文加载协议」——Fast Path 命中时,那两节的架构文件读取要求一律不适用。
88
+
89
+ **先跑证据工具**:`tf arch precheck <change-dir> --json` —— 输出确定性证据(架构关键词的**变更语境**命中 / 否定命中 / 仅提及;改动文件按表现层/后端/配置/脚本/测试分类)。**正常调用退出码恒 0(缺参数属用法错误 exit 2),它是证据不是判断**。
90
+
91
+ | precheck 输出 | 路径 | 行为 |
92
+ |---|---|---|
93
+ | `signal: none`(无正向架构关键词 ∧ 无后端文件 ∧ 无 `.sql` ∧ 有表现层文件) | **Fast Path** | 只读 `change-brief.md` + precheck 输出;本路径**不读 `docs/architecture/` 下任何文件(含 `INDEX.md`)**;执行五项检查后返回 `skipped`,reason 引用 precheck 证据 |
94
+ | `signal: weak` / `strong` | 完整路径 | 现状(读快照 + 全局基线 + 完整五项检查) |
95
+
96
+ **红线**:Fast Path 下若发现 precheck 证据与 brief 不符(如 brief 明确提到新增聚合但 precheck 未命中),**必须回退完整路径**——判断权始终在本子代理,precheck 只用于缩小输入范围。
97
+
84
98
  ### 路由分流(v0.35.0 新增)
85
99
 
86
100
  当产品级架构快照存在时(已建档项目),判定结果再按"产品级决策 vs change 内实现细节"分流:
@@ -103,7 +117,7 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
103
117
  ### 执行流程
104
118
 
105
119
  ```
106
- 1. 读取输入(brief + plan + specs + 全局 ARCHITECTURE.md
120
+ 1. 读取输入(brief + plan + specs + 全局 ARCHITECTURE.md)——**Fast Path 裁剪为「brief + precheck 输出」**
107
121
  2. 执行五项检查
108
122
  3. 全部为否:
109
123
  → decision: skipped
@@ -196,7 +210,7 @@ architecture-design 执行时的上下文组装:
196
210
  1. 执行 `tf solutions inject --phase architecture`(失败静默)——注入 `docs/solutions/` 中 phase=architecture 的历史架构决策经验(BC 边界取舍/聚合划分理由/事件投影设计踩坑)
197
211
  2. 读取失败 / 无条目 → 静默跳过,不阻断(advisory 级,与 S1 复利注入同语义)
198
212
 
199
- **始终加载**:
213
+ **始终加载**(**Fast Path 除外**——见上文 `### Fast Path`,该路径不读 `docs/architecture/` 下任何文件):
200
214
  1. `Read docs/architecture/INDEX.md`(~50行摘要)
201
215
  2. `Read changes/<name>/change-brief.md`(如有)
202
216
  3. `Read changes/<name>/proposal.md`(如有)
@@ -11,6 +11,8 @@ Controls the implementation phase. Uses `execution-contract.md` as the workflow
11
11
 
12
12
  Read: `execution-contract.md`, `tasks.md`, relevant `specs/`, relevant `design.md`. (Skip contract/spec requirements when workflow is `tweak`.)
13
13
 
14
+ **复利经验注入(v0.49.0 §83.3.5)**:运行 `tf solutions inject --phase cross-phase`(失败静默)——注入 `docs/solutions/` 中跨阶段可复用的历史经验(踩坑/模式),供实施时规避已知问题。注入内容是**经验提示而非约束**:与当前 change 的契约/规格冲突时以契约/规格为准,并把冲突回报给 workflow-start。
15
+
14
16
  When `architecture/sql/` exists, also read:
15
17
  - `architecture/sql/ddl/*.sql` — executable DDL scripts; reference directly for DB schema change tasks instead of hand-writing DDL
16
18
  - `architecture/sql/migration/*.sql` — data migration scripts; execute as-is for data transformation tasks
@@ -95,7 +97,7 @@ The recommendation uses task count, configured `execution.inlineThreshold`, and
95
97
  | **Inline** | Recommended for a single sequential task; always available for a user-confirmed choice |
96
98
  | **Batch Inline** | Recommended for a bounded sequential batch; it remains serial and is never presented as parallel |
97
99
 
98
- Do not transition to `executing` until `execution show` reports `current: true` and the phase guard passes. A revised plan must repeat `tf execution recommend` and use `tf execution revise --confirm`; it creates a new revision and invalidates receipts from the prior revision.
100
+ Do not transition to `executing` until `execution show` reports `current: true` and the phase guard passes. A revised plan must repeat `tf execution recommend` and use `tf execution revise --confirm`; it creates a new revision. Receipts carrying a `wave_fingerprint` stay valid while their wave definition is unchanged (v0.49.0 §83.3.2); legacy receipts without one still fall back to the plan-hash judgement and are invalidated by a revision.
99
101
 
100
102
  ## Batch Inline Execution
101
103
 
@@ -123,7 +125,11 @@ For full/hotfix by default. Execute waves as dispatched by workflow-start.
123
125
  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.
124
126
  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.
125
127
  3. A `serial` wave dispatches one task at a time in listed order.
126
- 4. After every wave, notify workflow-start via SendMessage that the wave is complete and needs review. Include:
128
+ 4. After every wave, write back the tasks.md checkboxes for that wave, then notify workflow-start via SendMessage that the wave is complete and needs review.
129
+
130
+ **tasks.md 勾选回写(v0.49.0 §83.3.4)**:按 `wave.tasks` 匹配 tasks.md 对应行,把 `- [ ]` 改为 `- [x]`(只改勾选标记,不动任务文本)。这是执行进度的权威登记——`tasks-complete` guard 在 closing 时要求零未勾选项,留到收尾轮必然遗忘。若该 change 的 tasks.md 不使用 checkbox 形态(如以 `### Task N.M` 标题组织),零 `- [x]` 会使该 guard 无条件 FAIL:此时与 workflow-start 确认改用 checkbox 形态或走显式豁免,不要静默跳过。A1 修复后勾选不再使 plan 过期(§83.3.1),因此不会阻塞本 wave 的 receipt 登记(receipt 由 workflow-start 写入)。
131
+
132
+ Notify with:
127
133
  - Wave ID
128
134
  - Worktree path
129
135
  - Branch
@@ -136,9 +142,9 @@ For full/hotfix by default. Execute waves as dispatched by workflow-start.
136
142
 
137
143
  每个 wave 完成、通知 workflow-start 审查前,验证测试**实际执行**的数量(设计增强方案 v0.18 §76,来源:workflow-feedback 2026-08-06——64% 测试静默跳过但报告全绿):
138
144
 
139
- 1. 运行测试套件后,用 `tf test record <change-dir> --from <runner-output-file>` 解析**实际执行数量**(`Tests run: N`)。
145
+ 1. 运行测试套件后,用 `tf test record <change-dir> --from <runner-output-file>` 解析**实际执行数量**。**证据文件的产出形态随 runner 而异(v0.22 §86)**:jest 必须 `--json`(如 `npx jest --json --outputFile=<path>`;控制台汇总行 `Tests: N passed` 不被解析);maven-surefire 用控制台汇总行(`Tests run: N`)或 surefire XML 目录/文件;pytest 用 terminal summary 或 junit XML(`--junitxml=<path>`)。解析规则以 `scripts/lib/test-record.mjs` 为准(新增 runner 需先在该处注册)。
140
146
  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"。
141
- 3. 报告引用实际执行数(`Tests run: N`),而非 BUILD SUCCESS 或编译通过数量。
147
+ 3. 报告引用实际执行数(按 runner 的计数口径),而非 BUILD SUCCESS 或编译通过数量。
142
148
 
143
149
  ### Per-Task Loop
144
150
  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.
@@ -35,7 +35,7 @@ Dispatch according to the persisted plan, review each planned wave, and run a fi
35
35
  1. Read the current plan with `tf execution show <change-dir> --json`; only waves with `current: true` and `eligible: true` may start.
36
36
  2. A `parallel` wave may dispatch independent tasks simultaneously only when the platform supports concurrent dispatch.
37
37
  3. A `serial` wave dispatches one task at a time in listed order.
38
- 4. After every wave, write a review report, then record one receipt:
38
+ 4. After every wave, write a review report **inside the change review overlay** `<change-dir>/.superpowers/sdd/reviews/` (v0.22 §86: other paths are rejected; the overlay is auto-created), then record one receipt:
39
39
  ```bash
40
40
  tf execution review <change-dir> \
41
41
  --wave <wave-id> --base <sha> --head <sha> --report <review-report-path> --verdict <pass|fail>
@@ -141,9 +141,10 @@ Subagent (general-purpose):
141
141
  ## Output Format
142
142
 
143
143
  Write your full review to [REVIEW_REPORT_FILE]. This distinct review report
144
- path must point to a non-empty, persisted review report before the
145
- controller records a receipt. After the verdict, provide the exact receipt
146
- command for the controller:
144
+ path must resolve inside `<change-dir>/.superpowers/sdd/reviews/` and point
145
+ to a non-empty, persisted review report before the controller records a
146
+ receipt. After the verdict, provide the exact receipt command for the
147
+ controller:
147
148
 
148
149
  ```bash
149
150
  tf execution review <change-dir> --wave [WAVE_ID] --base [BASE_SHA] --head [HEAD_SHA] --report [REVIEW_REPORT_FILE] --verdict <pass|fail>
@@ -184,7 +185,7 @@ Subagent (general-purpose):
184
185
  - `[BRIEF_FILE]` — REQUIRED: the task brief file (`scripts/task-brief PLAN N` prints the path; same file the implementer worked from)
185
186
  - `[GLOBAL_CONSTRAINTS]` — the binding requirements copied verbatim from the plan's Global Constraints section or the spec: exact values, formats, and stated relationships between components (not process rules — those are already in this template)
186
187
  - `[IMPLEMENTER_REPORT_FILE]` — REQUIRED: the file the implementer wrote its detailed report to
187
- - `[REVIEW_REPORT_FILE]` — REQUIRED: a distinct, persisted, non-empty file where the reviewer writes this review; this exact path is stored in the receipt
188
+ - `[REVIEW_REPORT_FILE]` — REQUIRED: a distinct, persisted, non-empty file under `<change-dir>/.superpowers/sdd/reviews/` (the overlay) where the reviewer writes this review; this exact path is stored in the receipt
188
189
  - `[BASE_SHA]` — commit before this task
189
190
  - `[HEAD_SHA]` — current commit
190
191
  - `[DIFF_FILE]` — REQUIRED: the path the controller wrote the review package to (`scripts/review-package BASE HEAD` prints the unique path it wrote; the package never enters the controller's context)
@@ -10,7 +10,7 @@ tf solutions promote <change-dir>
10
10
 
11
11
  ## 晋升来源
12
12
 
13
- 检查 `specs/<cap>/learnings.md` 中的经验。
13
+ 检查 change 根目录 `learnings.md` 中的经验(v0.49.0 §83.3.5 统一路径:代码与 guard 均只认 change 根,`specs/<cap>/` 下从未落地)。
14
14
 
15
15
  ## 晋升条件
16
16
 
@@ -1,5 +1,14 @@
1
1
  # Documentation schema for learnings written by ce-compound
2
- # Treat this as the canonical frontmatter contract for docs/solutions/.
2
+ # Treat this as the canonical frontmatter contract for docs/solutions/ entries
3
+ # written by ce-compound.
4
+ #
5
+ # v0.49.0 §83.3.5(来源:workflow-feedback 20260909):docs/solutions/ 有两条产出通道,
6
+ # frontmatter 契约不同 ——
7
+ # ① ce-compound 手工条目:使用本文件的 schema(module / problem_type / component / ...)
8
+ # ② tf solutions promote 自动晋升条目:phase / domain / type / severity / date / source
9
+ # (见 scripts/lib/solutions-promote.mjs,字段源自 change 根 learnings.md)
10
+ # 共同消费面 = docs/solutions/INDEX.md(tf solutions inject 只读该文件,不读条目 frontmatter)。
11
+ # 下方 schema 仅适用于通道 ①。
3
12
  #
4
13
  # The schema has two tracks based on problem_type:
5
14
  # Bug track — problem_type is a defect or failure (build_error, test_failure, etc.)
@@ -16,7 +16,7 @@ Two responsibilities: requesting review (dispatching a reviewer subagent) and re
16
16
  1. Get SHAs: `BASE_SHA=$(git rev-parse HEAD~1)` and `HEAD_SHA=$(git rev-parse HEAD)`
17
17
  2. Dispatch `general-purpose` subagent using template at `skills/code-reviewer/code-reviewer-prompt.md`
18
18
  3. Fill placeholders: `[DESCRIPTION]` (what was built), `[PLAN_OR_REQUIREMENTS]` (contract/spec reference), `[BASE_SHA]`, `[HEAD_SHA]`, `[WAVE_ID]`, and a distinct `[REVIEW_REPORT_FILE]`.
19
- 4. Require the reviewer to write a non-empty persisted review report at `[REVIEW_REPORT_FILE]`, then record that exact path in the wave receipt: `tf execution review <change-dir> --wave <id> --base <sha> --head <sha> --report <review-report-path> --verdict <pass|fail>`.
19
+ 4. Require the reviewer to write a non-empty persisted review report at `[REVIEW_REPORT_FILE]` **inside the change review overlay** `<change-dir>/.superpowers/sdd/reviews/` (v0.22 §86: other paths are rejected by the CLI; the overlay directory is auto-created). Then record that exact path in the wave receipt: `tf execution review <change-dir> --wave <id> --base <sha> --head <sha> --report <review-report-path> --verdict <pass|fail>`.
20
20
  5. Act on feedback: Critical/Important findings require a `fail` receipt, focused repair, re-review, and replacement `pass` receipt before a dependent wave or closing can proceed. Note Minor for later, push back with reasoning if reviewer is wrong.
21
21
 
22
22
  ### Minimality And Scope
@@ -105,9 +105,10 @@ Subagent (general-purpose):
105
105
  ## Output Format
106
106
 
107
107
  Write your full verdict to [REVIEW_REPORT_FILE]. This review report path
108
- must point to a non-empty, persisted review report before the controller
109
- records a receipt. Include the wave ID, base SHA, head SHA, and that review
110
- report path. End with the exact receipt command:
108
+ must resolve inside `<change-dir>/.superpowers/sdd/reviews/` and point to a
109
+ non-empty, persisted review report before the controller records a receipt.
110
+ Include the wave ID, base SHA, head SHA, and that review report path. End
111
+ with the exact receipt command:
111
112
 
112
113
  ```bash
113
114
  tf execution review <change-dir> --wave [WAVE_ID] --base [BASE_SHA] --head [HEAD_SHA] --report [REVIEW_REPORT_FILE] --verdict <pass|fail>
@@ -169,7 +170,7 @@ Subagent (general-purpose):
169
170
  - `[BASE_SHA]` — starting commit
170
171
  - `[HEAD_SHA]` — ending commit
171
172
  - `[WAVE_ID]` — planned execution wave under review
172
- - `[REVIEW_REPORT_FILE]` — REQUIRED: distinct, persisted, non-empty review report path stored in the execution receipt
173
+ - `[REVIEW_REPORT_FILE]` — REQUIRED: distinct, persisted, non-empty review report path under `<change-dir>/.superpowers/sdd/reviews/` (the overlay); stored in the execution receipt
173
174
 
174
175
  **Reviewer returns:** Strengths, Issues (Critical / Important / Minor), Recommendations, Assessment
175
176
 
@@ -113,7 +113,13 @@ See `test-matrix.md` for the full test case matrix (附属产物, 独立 hash).
113
113
 
114
114
  ### Hotfix/Tweak Exemption
115
115
 
116
- hotfix/tweak workflow 不生成 test-matrix.md(guard 豁免);full workflow 确无自动化测试需求的特例(纯文档/纯配置)同理。设置显式 skip + 理由(v0.13 §48.2 可审计豁免,**不允许静默不生成**):
116
+ **hotfix/tweak**:不生成 test-matrix.md 与 tasks.md(guard 豁免),设置显式 skip + 理由(v0.13 §48.2 + v0.22 §85 可审计豁免,**不允许静默不生成**):
117
+ ```bash
118
+ tf state set <change-dir> test_matrix_skipped true && tf state set <change-dir> test_matrix_skip_reason "<一句话说明>"
119
+ tf state set <change-dir> tasks_skipped true && tf state set <change-dir> tasks_skip_reason "<一句话说明>"
120
+ ```
121
+
122
+ **full workflow 特例**(纯文档/纯配置,确无自动化测试需求):**只**豁免测试矩阵,**不得设置 `tasks_skipped`**——`tasks.md` 是 spec-writer 的核心产物,full 路径不允许跳过(v0.22 §85.4);该禁令**代码层强制**:`tasks-complete` 对 full/auto 置键直接 FAIL。
117
123
  ```bash
118
124
  tf state set <change-dir> test_matrix_skipped true && tf state set <change-dir> test_matrix_skip_reason "<一句话说明>"
119
125
  ```
@@ -137,13 +143,38 @@ Refresh if: scope changed in proposal, requirements changed in specs, constraint
137
143
 
138
144
  ## Hotfix Mode
139
145
 
140
- 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.
146
+ **适用判据**(须同时满足;任一条不满足 走完整契约):
147
+
148
+ 1. 改动文件 ≤2
149
+ 2. 不新增/变更:API 签名、请求响应 schema、DB schema、`filter.args` 等配置契约 key
150
+ 3. 变更性质 = 文案 / 样式 / 布局 / 提示语 / 日志措辞
151
+
152
+ **轻契约骨架**(目标 ≤60 行;>60 行须在 DP-3 摘要说明理由;>100 行视为不适用轻契约、回退完整契约):
153
+
154
+ | 章节 | 内容 |
155
+ |---|---|
156
+ | `## Intent Lock` | 1-2 句(问题 + 范围) |
157
+ | `## 锁定值表` | 改前/改后逐字——防实现偏差的核心,必留 |
158
+ | `## 范围栅栏` | 改动文件 + 禁改项清单 |
159
+ | `## Execution Batch` | 编号任务(含验证任务) |
160
+ | `## Test Matrix` | 测试策略——**代码解析锚点,标题不可删**(除非 `test_matrix_skipped=true`) |
161
+ | `## Approval Gate (DP-3)` | 审批对象声明 |
162
+
163
+ **移出轻契约**:AC 覆盖矩阵、信息量守恒核对表、DOM 结构详述、金字塔/复杂度分析、人工核验义务(改由 closing 总结承载);Review Gates 章节不写入契约,但 **wave 级 review receipt 仍须由 build-executor 记录**——closing 的 `execution-reviews-passed` 维度对 hotfix 同样考核(`guard.mjs:75`)。
164
+
165
+ **其余代码锚点**:涉及 UI 时保留 `## UX 增量`;GLAF4 委托时保留 `## GLAF4 Delegation`。除此之外的段落代码不解析,可自由裁剪;但契约全文入 `contract_hash`,裁剪后须 `tf state rebuild`。
166
+
167
+ **质量不变量(不得因轻量化削减)**:锁定值逐字、范围栅栏、测试策略、Escalation 条件。
168
+
169
+ Still requires DP-3 approval.
170
+
171
+ **非存量 hotfix/tweak 必须设置显式 skip(v0.13 §50 + v0.22 §85)**:hotfix/tweak 不生成矩阵与 `tasks.md`,但 closing 的 `tests-passing` / `tasks-complete` 两个门禁仍考核非存量 change——生成最小契约后立即执行上方 Hotfix/Tweak Exemption 段的四条 `tf state set`,否则 release-archivist 轻量收尾会被门禁阻断(v0.22 §85:修复前 `tasks-complete` 无豁免分支,closing 死锁)。
141
172
 
142
- **非存量 hotfix/tweak 必须设置显式 skip(v0.13 §50)**:hotfix/tweak 不生成矩阵,但 closing tests-passing 门禁仍考核非存量 change——生成最小契约后立即执行 Hotfix/Tweak Exemption 段的两条 `tf state set`(`test_matrix_skipped=true` + 理由),否则 release-archivist 轻量收尾会被门禁阻断。
173
+ **`tasks.md` 归属(v0.22 §85)**:hotfix/tweak 默认跳过(上条),但若该 change 确实需要任务记录,`tasks.md` 由本 skill 一并产出——归属 contract-builder(本 skill 已有 `tasks.md Execution Batches` Artifact Mapping,反向生成成本最低);任务文本不再经 spec-writer(hotfix/tweak 已跳过它)。
143
174
 
144
175
  ## Guardrails
145
176
 
146
- - **状态字段禁写(v0.30.0)**:仅写本 skill 的 `dp_3_*` 决策字段;**MUST NOT** 修改 `state`/`workflow` 核心字段——状态转换由主代理经 `tf state transition` 执行。`tf state init` 只创建状态文件,不改 `state` 值(来源:workflow-feedback 2026-08-01)。
177
+ - **状态字段禁写(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)。
147
178
 
148
179
  - Do not continue to implementation if ambiguity remains
149
180
  - Do not approve the contract on the user's behalf