agentic-flow-kit 1.6.0 → 1.7.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +40 -6
  2. package/modules/gates/README.md +1 -0
  3. package/modules/gates/test-protect/README.md +23 -0
  4. package/modules/gates/test-protect/check-test-protect.mjs +64 -0
  5. package/modules/gates/test-protect/local-pre-commit.line +1 -0
  6. package/modules/hosts/README.md +57 -0
  7. package/modules/hosts/claude/commands/wf-build.md +5 -24
  8. package/modules/hosts/claude/commands/wf-deploy.md +1 -0
  9. package/modules/hosts/claude/commands/wf-design.md +2 -2
  10. package/modules/hosts/claude/commands/wf-gate-checklist.md +1 -3
  11. package/modules/hosts/claude/commands/wf-plan.md +1 -1
  12. package/modules/hosts/claude/commands/wf-source-sync-check.md +1 -3
  13. package/modules/hosts/claude/commands/wf-sync-hosts.md +1 -3
  14. package/modules/hosts/claude/commands/wf-test.md +5 -4
  15. package/modules/hosts/codex/commands/wf-build.md +5 -24
  16. package/modules/hosts/codex/commands/wf-deploy.md +1 -0
  17. package/modules/hosts/codex/commands/wf-design.md +2 -2
  18. package/modules/hosts/codex/commands/wf-gate-checklist.md +1 -3
  19. package/modules/hosts/codex/commands/wf-plan.md +1 -1
  20. package/modules/hosts/codex/commands/wf-source-sync-check.md +1 -3
  21. package/modules/hosts/codex/commands/wf-sync-hosts.md +1 -3
  22. package/modules/hosts/codex/commands/wf-test.md +5 -4
  23. package/modules/hosts/cursor/commands/wf-build.md +5 -24
  24. package/modules/hosts/cursor/commands/wf-deploy.md +1 -0
  25. package/modules/hosts/cursor/commands/wf-design.md +2 -2
  26. package/modules/hosts/cursor/commands/wf-gate-checklist.md +1 -3
  27. package/modules/hosts/cursor/commands/wf-plan.md +1 -1
  28. package/modules/hosts/cursor/commands/wf-source-sync-check.md +1 -3
  29. package/modules/hosts/cursor/commands/wf-sync-hosts.md +1 -3
  30. package/modules/hosts/cursor/commands/wf-test.md +5 -4
  31. package/modules/hosts/opencode/commands/wf-build.md +5 -24
  32. package/modules/hosts/opencode/commands/wf-deploy.md +1 -0
  33. package/modules/hosts/opencode/commands/wf-design.md +2 -2
  34. package/modules/hosts/opencode/commands/wf-gate-checklist.md +1 -3
  35. package/modules/hosts/opencode/commands/wf-plan.md +1 -1
  36. package/modules/hosts/opencode/commands/wf-source-sync-check.md +1 -3
  37. package/modules/hosts/opencode/commands/wf-sync-hosts.md +1 -3
  38. package/modules/hosts/opencode/commands/wf-test.md +5 -4
  39. package/modules/hosts/trae/commands/wf-build.md +5 -24
  40. package/modules/hosts/trae/commands/wf-deploy.md +1 -0
  41. package/modules/hosts/trae/commands/wf-design.md +2 -2
  42. package/modules/hosts/trae/commands/wf-gate-checklist.md +1 -3
  43. package/modules/hosts/trae/commands/wf-plan.md +1 -1
  44. package/modules/hosts/trae/commands/wf-source-sync-check.md +1 -3
  45. package/modules/hosts/trae/commands/wf-sync-hosts.md +1 -3
  46. package/modules/hosts/trae/commands/wf-test.md +5 -4
  47. package/package.json +2 -2
  48. package/src/add-gate.mjs +25 -1
  49. package/src/add-gate.test.mjs +103 -0
  50. package/src/cli.mjs +17 -2
  51. package/src/doctor.mjs +99 -11
  52. package/src/gates.test.mjs +17 -0
  53. package/src/init.mjs +7 -1
  54. package/src/init.test.mjs +19 -0
  55. package/src/instance-ref.test.mjs +62 -0
  56. package/src/jscpd-drift.test.mjs +144 -0
  57. package/src/render.mjs +5 -0
  58. package/src/rule-budget.test.mjs +103 -0
  59. package/src/run-tests.mjs +16 -9
  60. package/src/sync-hosts.mjs +4 -2
  61. package/src/trae-hooks.test.mjs +15 -3
  62. package/src/validate.mjs +72 -0
  63. package/src/validate.test.mjs +95 -0
  64. package/templates/AGENTS.md +3 -1
  65. package/templates/_agents/commands/build.md +5 -24
  66. package/templates/_agents/commands/deploy.md +1 -0
  67. package/templates/_agents/commands/design.md +2 -2
  68. package/templates/_agents/commands/gate-checklist.md +1 -3
  69. package/templates/_agents/commands/plan.md +1 -1
  70. package/templates/_agents/commands/source-sync-check.md +1 -3
  71. package/templates/_agents/commands/sync-hosts.md +1 -3
  72. package/templates/_agents/commands/test.md +5 -4
  73. package/templates/_agents/control-surfaces.txt +53 -0
  74. package/templates/_agents/scripts/agg-delegations.cjs +51 -6
  75. package/templates/_agents/scripts/agg-delegations.test.mjs +79 -1
  76. package/templates/_agents/scripts/check-engine-integrity.mjs +288 -0
  77. package/templates/_agents/scripts/check-engine-integrity.test.mjs +227 -0
  78. package/templates/_agents/scripts/check-lane-surface.mjs +7 -2
  79. package/templates/_agents/scripts/check-ledger-invariant.mjs +18 -0
  80. package/templates/_agents/scripts/check-ledger-invariant.test.mjs +16 -0
  81. package/templates/_agents/scripts/check-ledger.test.mjs +2 -0
  82. package/templates/_agents/scripts/check-loop.mjs +247 -5
  83. package/templates/_agents/scripts/check-loop.test.mjs +367 -2
  84. package/templates/_agents/scripts/confirm-doc.mjs +50 -3
  85. package/templates/_agents/scripts/confirm-doc.test.mjs +93 -1
  86. package/templates/_agents/scripts/doctor.test.mjs +251 -1
  87. package/templates/_agents/scripts/draft-sediment.mjs +178 -0
  88. package/templates/_agents/scripts/draft-sediment.test.mjs +272 -0
  89. package/templates/_agents/scripts/gate-checklist.mjs +10 -2
  90. package/templates/_agents/scripts/gate-checklist.test.mjs +7 -1
  91. package/templates/_agents/scripts/gen-wiki-board.mjs +61 -6
  92. package/templates/_agents/scripts/gen-wiki-board.test.mjs +74 -1
  93. package/templates/_agents/scripts/gen-workflow-dashboard.mjs +2 -2
  94. package/templates/_agents/scripts/gen-workflow-metrics.mjs +11 -5
  95. package/templates/_agents/scripts/kb-search.mjs +87 -12
  96. package/templates/_agents/scripts/kb-search.test.mjs +83 -0
  97. package/templates/_agents/scripts/pipeline-run.mjs +1 -1
  98. package/templates/_agents/scripts/policy.mjs +49 -0
  99. package/templates/_agents/scripts/solidify-task.mjs +1 -1
  100. package/templates/_agents/scripts/source-sync-check.test.mjs +9 -4
  101. package/templates/_agents/scripts/stage-gates.mjs +48 -1
  102. package/templates/_agents/scripts/stage-gates.test.mjs +105 -0
  103. package/templates/_agents/scripts/verify-wiki-consistency.mjs +34 -0
  104. package/templates/_agents/scripts/verify-wiki-consistency.test.mjs +44 -2
  105. package/templates/_agents/scripts/verify.mjs +12 -4
  106. package/templates/_agents/scripts/verify.test.mjs +30 -3
  107. package/templates/_agents/scripts-test-exempt.txt +3 -1
  108. package/templates/_agents/skills/wiki/SKILL.md +5 -3
  109. package/templates/wiki/INDEX.md +44 -1
  110. package/templates/wiki//347/237/245/350/257/206/346/262/211/346/267/200/346/200/273/350/247/210.html +22 -1
  111. package/templates/workflow/delegations.md +5 -4
  112. package/templates/workflow/incidents/_TEMPLATE.md +2 -0
  113. package/templates/workflow/intents/_TEMPLATE.md +3 -0
  114. package/templates/workflow/plans/_TEMPLATE.md +4 -0
  115. package/templates/workflow/specs/_TEMPLATE.md +23 -0
@@ -14,12 +14,19 @@ const check = (name, cond, detail = '') => {
14
14
  else { fail++; console.log(`FAIL ${name}${detail ? `——${detail}` : ''}`); }
15
15
  };
16
16
 
17
- function mkWiki({ extraDiskFile = false, noArchive = false } = {}) {
17
+ function mkWiki({ extraDiskFile = false, noArchive = false, draftSource = null } = {}) {
18
18
  const fx = fs.mkdtempSync(path.join(os.tmpdir(), 'vwc-'));
19
19
  fs.mkdirSync(path.join(fx, 'wiki', '主题A'), { recursive: true });
20
20
  fs.writeFileSync(path.join(fx, 'wiki', '主题A', '文档1.md'), '# 文档1\n\n无外链。\n');
21
21
  if (extraDiskFile) fs.writeFileSync(path.join(fx, 'wiki', '主题A', '文档2.md'), '# 文档2\n');
22
+ let archiveCount = 0;
22
23
  if (!noArchive) fs.mkdirSync(path.join(fx, 'wiki', 'drafts-archive'), { recursive: true });
24
+ if (draftSource) { // B2 落的草稿形态:drafts-archive/<日期-主题>/ 下带来源 frontmatter
25
+ fs.mkdirSync(path.join(fx, 'wiki', 'drafts-archive', '2026-09-12-主题'), { recursive: true });
26
+ fs.writeFileSync(path.join(fx, 'wiki', 'drafts-archive', '2026-09-12-主题', '草稿.md'),
27
+ `---\n来源: ${draftSource}\n---\n# 草稿\n`);
28
+ archiveCount = 1;
29
+ }
23
30
  fs.writeFileSync(path.join(fx, 'wiki', 'INDEX.md'), [
24
31
  '# Wiki 索引',
25
32
  '',
@@ -40,7 +47,7 @@ function mkWiki({ extraDiskFile = false, noArchive = false } = {}) {
40
47
  ].join('\n'));
41
48
  const DATA = {
42
49
  topics: [{ name: '主题A', files: [{ file: '文档1.md', dir: '主题A' }] }],
43
- summary: { total: 1, files: 1, topics: 1, archive: 0 },
50
+ summary: { total: 1, files: 1, topics: 1, archive: archiveCount },
44
51
  };
45
52
  fs.writeFileSync(path.join(fx, 'wiki', '知识沉淀总览.html'),
46
53
  '<!doctype html><script>\nconst DATA = ' + JSON.stringify(DATA, null, 2) + ';\n</script>\n');
@@ -77,5 +84,40 @@ const run = (fx) => spawnSync(process.execPath, [path.join(SRC, 'verify-wiki-con
77
84
  fs.rmSync(fx, { recursive: true, force: true });
78
85
  }
79
86
 
87
+ // ---- ④⑤⑥ 来源血缘校验(B3,2026-10-10,第 9 项)----
88
+ {
89
+ // ④ 活跃层来源断链 → exit 1
90
+ const fx = mkWiki();
91
+ fs.writeFileSync(path.join(fx, 'wiki', '主题A', '文档1.md'),
92
+ '---\n来源: workflow/intents/2026-09-12-不存在.md\n---\n# 文档1\n\n无外链。\n');
93
+ const r = run(fx);
94
+ const out = (r.stdout || '') + (r.stderr || '');
95
+ check('④ 活跃层来源断链 → exit 1 且点名断链',
96
+ r.status === 1 && out.includes('来源断链') && out.includes('不存在.md'), `status=${r.status}\n${out.slice(0, 500)}`);
97
+ fs.rmSync(fx, { recursive: true, force: true });
98
+ }
99
+ {
100
+ // ⑤ 活跃层来源指向存在的文件 → exit 0 且血缘有效提示
101
+ const fx = mkWiki();
102
+ fs.writeFileSync(path.join(fx, 'wiki', '主题A', '文档1.md'),
103
+ '---\n来源: workflow/intents/2026-09-12-真单.md\n---\n# 文档1\n\n无外链。\n');
104
+ fs.mkdirSync(path.join(fx, 'workflow', 'intents'), { recursive: true });
105
+ fs.writeFileSync(path.join(fx, 'workflow', 'intents', '2026-09-12-真单.md'), '# INTENT\n');
106
+ const r = run(fx);
107
+ const out = (r.stdout || '') + (r.stderr || '');
108
+ check('⑤ 活跃层来源有效 → exit 0 且提示血缘有效',
109
+ r.status === 0 && out.includes('来源血缘有效'), `status=${r.status}\n${out.slice(0, 500)}`);
110
+ fs.rmSync(fx, { recursive: true, force: true });
111
+ }
112
+ {
113
+ // ⑥ 草稿来源未落地 → 仅提示不阻断(草稿中间态,归类前允许)
114
+ const fx = mkWiki({ draftSource: 'workflow/incidents/2026-09-12-未闭环.md' });
115
+ const r = run(fx);
116
+ const out = (r.stdout || '') + (r.stderr || '');
117
+ check('⑥ 草稿来源未落地 → exit 0 且降级提示(不阻断)',
118
+ r.status === 0 && out.includes('草稿中间态'), `status=${r.status}\n${out.slice(0, 500)}`);
119
+ fs.rmSync(fx, { recursive: true, force: true });
120
+ }
121
+
80
122
  console.log(`\n合计: PASS ${pass} / FAIL ${fail}`);
81
123
  process.exit(fail ? 1 : 0);
@@ -9,7 +9,8 @@
9
9
  // 一行机器事实 {ts, exitCode:0, suite, passed?, failed?, runId?}——append-only 事实记录,不属裁决
10
10
  // (窗口判定/门禁在消费方 confirm-doc 与 check-loop 检查 8);消费语义 = 「按门跑了 verify 且全绿」,
11
11
  // 裸跑 npm test 不落账(对齐引导)。npm test 步骤输出从 inherit 改 pipe 捕获后回放(延迟显示,
12
- // 关单场景可接受)——仅为 best-effort 抓「合计: PASS n / FAIL n」计数行,抓不到则省略计数键。
12
+ // 关单场景可接受)——仅 best-effort 抓编排器权威汇总行 `[run-tests] 合计: SUITES n / FAILED m`,
13
+ // 抓不到则省略计数键(宁缺勿错:exitCode 才是硬事实,计数缺失不阻断)。
13
14
  // 装户仓(根目录无 package.json,工程在子目录)下默认 npm test 恒 ENOENT(exit 4058)→ **显式跳过步骤 1**
14
15
  // 且**不落测试绿凭证**(凭证语义 = 测试真跑绿,跳过即无凭证,防假绿),并提示用
15
16
  // --test-cmd "<项目测试命令>" 指定;显式 --test-cmd 不受此判定影响(2026-10-07 papercut)。
@@ -20,7 +21,7 @@
20
21
  // 事实;这样的行不给任何单背书(消费方按 doc 精确匹配时 e.doc 为 undefined 恒不命中)。
21
22
  // 用法:node .agents/scripts/verify.mjs [--test-cmd "<shell 命令>"] [--doc <本单 workflow 路径>]
22
23
  // (--test-cmd 用于测试注入,或在无根 package.json 的装户仓指定项目测试命令;
23
- // --doc 把凭证绑到本单,如 --doc workflow/intents/2026-10-08-x.md)
24
+ // --doc 把凭证绑到本单,如 --doc workflow/intents/<日期>-<主题>.md)
24
25
  import fs from 'node:fs';
25
26
  import { spawnSync } from 'node:child_process';
26
27
  import path from 'node:path';
@@ -84,8 +85,15 @@ try {
84
85
  if (skipTest) {
85
86
  console.log('[verify] ⚠️ 步骤 1 已跳过——本次不落测试绿凭证(凭证语义 = 测试真跑绿)');
86
87
  } else {
87
- const m = [...testStdout.matchAll(/合计: PASS (\d+) \/ FAIL (\d+)/g)].pop();
88
+ // 计数行**只认编排器权威前缀**(2026-10-09 审查 P0-2):此前是 pop 通配「合计: PASS n / FAIL n」,
89
+ // 而全仓 45+ 套件每个都打印自己那行同形文本 → 取到的是字母序最后一个套件的场景数
90
+ // (本仓实况:workflows-check.test.mjs 的 15),落进「一行机器事实」的 passed 字段。
91
+ // 改为精确匹配 run-tests.mjs 的专属行 + 套件口径:嵌套套件同形行不再被误取,
92
+ // 非本编排器口径的 --test-cmd(装户项目自有测试命令)抓不到即省略计数键,不回退到错的事实。
93
+ const m = [...testStdout.matchAll(/\[run-tests\] 合计: SUITES (\d+) \/ FAILED (\d+)/g)].pop();
88
94
  const entry = { ts: new Date().toISOString(), exitCode: 0, suite: 'npm test' };
95
+ // passed/failed 口径 = **套件**(非断言、非场景):凭证明此记录的是「跑过多少套、挂了几套」。
96
+ // 步骤 1 红已在上面 fail-fast 退出,故落账行 failed 恒为 0。
89
97
  if (m) { entry.passed = Number(m[1]); entry.failed = Number(m[2]); }
90
98
  if (process.env.PIPELINE_RUN_ID) entry.runId = process.env.PIPELINE_RUN_ID;
91
99
  // doc 键:未传 --doc 时**不写该键**(不是写 null)——消费方按 doc 精确匹配,undefined 与 null 都恒不命中,
@@ -93,7 +101,7 @@ try {
93
101
  if (docRel) entry.doc = docRel;
94
102
  fs.mkdirSync(path.join(ROOT, '.agents'), { recursive: true });
95
103
  fs.appendFileSync(path.join(ROOT, '.agents', 'verifications.jsonl'), `${JSON.stringify(entry)}\n`);
96
- console.log(`[verify] 🧾 测试绿凭证已落账 verifications.jsonl${entry.passed !== undefined ? `(PASS ${entry.passed} / FAIL ${entry.failed})` : ''}${docRel ? ` 绑定本单 ${docRel}` : '(未带 --doc:不给任何单背书)'}`);
104
+ console.log(`[verify] 🧾 测试绿凭证已落账 verifications.jsonl${entry.passed !== undefined ? `(套件 ${entry.passed} / FAIL ${entry.failed})` : ''}${docRel ? ` 绑定本单 ${docRel}` : '(未带 --doc:不给任何单背书)'}`);
97
105
  }
98
106
  } catch (e) {
99
107
  console.error(`[verify] ⚠️ 凭证落账失败(${e.code || e.message})——不阻断,关单门前置将按无凭证告警`);
@@ -3,7 +3,8 @@
3
3
  // 断言:①绿路径(假过 + 空夹具闭环)exit 0;②步骤 1 假败 exit 1 且不出全绿;
4
4
  // ③步骤 2 配对断裂夹具 exit 1(verify 自身标记断言——孙进程 stdio inherit 输出不进本测试管道);
5
5
  // ④⑤⑥凭证落账三态(绿落 / check-loop 红不落 / 无汇总行省略计数键);
6
- // ⑦装户仓(cwd 无 package.json)未给 --test-cmd → 跳过步骤 1、不落凭证、仍跑步骤 2、exit 0。
6
+ // ⑦装户仓(cwd 无 package.json)未给 --test-cmd → 跳过步骤 1、不落凭证、仍跑步骤 2、exit 0;
7
+ // ⑧--doc 绑定五态;⑨⑩嵌套套件同形汇总行不得被误取(计数口径=编排器权威套件数,2026-10-09 审查 P0-2 回归锁)。
7
8
  // 用法:node templates/_agents/scripts/verify.test.mjs
8
9
  import fs from 'node:fs';
9
10
  import os from 'node:os';
@@ -86,7 +87,7 @@ const run = (argv, opts = {}) => spawnSync(process.execPath, [VERIFY, ...argv],
86
87
  // ---- 场景 4:绿路径凭证落账(2026-10-07 verify-evidence)——全绿后 fixture 台账出合法绿行 ----
87
88
  {
88
89
  const root = mkfix();
89
- const r = run(['--test-cmd', `node ${mkCmd(0, '合计: PASS 3 / FAIL 0\n')}`], { env: { ...process.env, CHECK_LOOP_ROOT: root } });
90
+ const r = run(['--test-cmd', `node ${mkCmd(0, '[run-tests] 合计: SUITES 3 / FAILED 0\n')}`], { env: { ...process.env, CHECK_LOOP_ROOT: root } });
90
91
  const vp = path.join(root, '.agents', 'verifications.jsonl');
91
92
  const line = fs.existsSync(vp) ? JSON.parse(fs.readFileSync(vp, 'utf8').trim()) : null;
92
93
  check('场景 4:全绿 → verifications.jsonl 落绿行(exitCode 0 + 计数捕获)',
@@ -146,7 +147,7 @@ const run = (argv, opts = {}) => spawnSync(process.execPath, [VERIFY, ...argv],
146
147
 
147
148
  const rootA = mkfix();
148
149
  const rel = 'workflow/intents/2026-10-08-demo.md';
149
- const rA = run(['--test-cmd', `node ${mkCmd(0, '合计: PASS 3 / FAIL 0\n')}`, '--doc', rel],
150
+ const rA = run(['--test-cmd', `node ${mkCmd(0, '[run-tests] 合计: SUITES 3 / FAILED 0\n')}`, '--doc', rel],
150
151
  { env: { ...process.env, CHECK_LOOP_ROOT: rootA } });
151
152
  const eA = readLast(rootA);
152
153
  check('场景 8①:带 --doc → 末行含 doc 且为 posix 相对路径',
@@ -185,6 +186,32 @@ const run = (argv, opts = {}) => spawnSync(process.execPath, [VERIFY, ...argv],
185
186
  fs.rmSync(bare, { recursive: true, force: true });
186
187
  }
187
188
 
189
+ // ---- 场景 9 / 10:嵌套套件同形汇总行不得被误取(2026-10-09 审查 P0-2 回归锁)----
190
+ // 缺陷复现:旧判据 pop 通配「合计: PASS n / FAIL n」,而全仓 45+ 套件每个都打印自己那行同形文本,
191
+ // 取到的是字母序最后一个套件的场景数(本仓实况 workflows-check.test.mjs = 15),落进凭证 passed。
192
+ // ⑨ 权威行与同形行并存 → 取权威套件数;⑩ 仅有同形行 → 省略计数键(宁缺勿错,不回退到错的事实)。
193
+ {
194
+ const root9 = mkfix();
195
+ const r9 = run(['--test-cmd', `node ${mkCmd(0, '合计: PASS 15 / FAIL 0\n[run-tests] 合计: SUITES 45 / FAILED 0\n')}`],
196
+ { env: { ...process.env, CHECK_LOOP_ROOT: root9 } });
197
+ const vp9 = path.join(root9, '.agents', 'verifications.jsonl');
198
+ const l9 = fs.existsSync(vp9) ? JSON.parse(fs.readFileSync(vp9, 'utf8').trim()) : null;
199
+ check('场景 9:嵌套套件同形行不被误取,计数取编排器权威套件数',
200
+ r9.status === 0 && l9 !== null && l9.passed === 45 && l9.failed === 0,
201
+ `line=${JSON.stringify(l9)}`);
202
+ fs.rmSync(root9, { recursive: true, force: true });
203
+
204
+ const root10 = mkfix();
205
+ const r10 = run(['--test-cmd', `node ${mkCmd(0, '合计: PASS 15 / FAIL 0\n')}`],
206
+ { env: { ...process.env, CHECK_LOOP_ROOT: root10 } });
207
+ const vp10 = path.join(root10, '.agents', 'verifications.jsonl');
208
+ const l10 = fs.existsSync(vp10) ? JSON.parse(fs.readFileSync(vp10, 'utf8').trim()) : null;
209
+ check('场景 10:仅有嵌套同形行 → 绿行落盘但省略计数键(不回退到错的事实)',
210
+ r10.status === 0 && l10 !== null && l10.exitCode === 0 && !('passed' in l10) && !('failed' in l10),
211
+ `line=${JSON.stringify(l10)}`);
212
+ fs.rmSync(root10, { recursive: true, force: true });
213
+ }
214
+
188
215
  console.log(`\n合计: PASS ${pass} / FAIL ${fail}`);
189
216
  if (fail) {
190
217
  console.log('\n用法:node templates/_agents/scripts/verify.test.mjs');
@@ -6,7 +6,9 @@
6
6
  check-metric-claims.mjs | 经 check-loop.mjs 消费 | 由 check-loop.test.mjs 间接覆盖其调用路径
7
7
  ensure-board.mjs | 看板启动器 | 永久工具豁免(需真实端口/进程环境,自动化覆盖无性价比——2026-10-09 engine-quality-round2 A2 评估定性)
8
8
  policy.mjs | 库件 | 被 check-loop.test.mjs 直接 import 覆盖
9
- stage-gates.mjs | 库件 | 被 check-loop.test.mjs 直接 import 覆盖(fill-*/confirm-doc.test 消费其行为)
9
+ # 2026-10-12 needs-clarification:stage-gates.mjs 已建同名直测(stage-gates.test.mjs 15 断言),
10
+ # 覆盖待澄清门纯函数族(CLARIFY_RE 形态矩阵 / HTML 注释不计 / clarifyGateFor 三态 / 行号点名)——
11
+ # 这两条判据**没有 check-loop 侧对应检查**,间接覆盖盖不到,故必须直测。登记随之撤除。
10
12
  # 2026-10-08 engine-quality-batch:pipeline-run 三层拆分的库件层——纯函数/存储层由 pipeline-run.test.mjs 全量覆盖(断言零改动全过),单建同名测试属形式主义(plan 偏离留痕 ①)
11
13
  pipeline-run-docs.mjs | 库件(文档纯函数层,2026-10-08 engine-quality-batch 拆分) | 由 pipeline-run.test.mjs 全量覆盖(断言零改动 29 组全过)
12
14
  pipeline-run-run.mjs | 库件(run 存储层,同上拆分) | 由 pipeline-run.test.mjs 全量覆盖(含 PIPELINE_RUN_* 注入契约场景)
@@ -26,7 +26,9 @@ description: 项目 wiki 整理与验证技能。负责把项目内散落文档
26
26
  - **权威**:红线与闭环以 AGENTS.md / workflow 为准;wiki 承载当前态知识(领域 / 表 / 编码 / SQL 台账)。wiki 当前文档优于 `drafts-archive/`(归档仅历史快照)。
27
27
  - **双格式对(md + html 同内容)**:md 为权威内容源,html 为展示快照——内容冲突以 md 为准,改 md 后按需重出 html;速览表「用途」列标注权威关系。
28
28
  - **索引生成(2026-09-13 起)**:速览表计数/映射表/看板 DATA 由 `node .agents/scripts/gen-wiki-board.mjs` 自动生成——人工只维护磁盘文件 + 速览表「用途」列;收录/删除/移动文件后必跑生成器(新主题用途列为 `<待补>` 时补描述后重跑)。写盘前可先 `--dry-run` 看差异(`--help` 打印用法,未知参数 exit 1)。
29
- - **归档目录**:`wiki/drafts-archive/YYYY-MM-DD_<主题>/`,按整理批次日期+主题命名,保留原文件名。
29
+ - **归档目录**:`wiki/drafts-archive/YYYY-MM-DD-<主题>/`,按整理批次日期+主题命名,保留原文件名。
30
+ - **来源血缘(双向链接,2026-10-10 起)**:沉淀到 wiki 的知识在 frontmatter 记 `来源: workflow/<intents|incidents|...>/<文件>` 指回 workflow 归档;被沉淀的 workflow 文件记 `沉淀: wiki/<主题>/<文件>`(或 `沉淀: 无` 显式豁免)。两向字段由 `verify-wiki-consistency.mjs` 校验存在性(活跃层断链即拦,草稿未落地仅提示)——人工移动/改归类时须同步改这两行,否则 check-loop 的 `[WARN 沉淀断档]` 与验证脚本都会点名。
31
+ - **关单自动沉淀(2026-10-10 起)**:intent 置 done / incident 置 closed 时,跑 `node .agents/scripts/draft-sediment.mjs <源文件>` 自动抽取高价值节(intent:影响面/触达红线;incident:影响面/根因/为什么之前没拦住/复盘三件套)→ 落 `wiki/drafts-archive/<日期-主题>/` 草稿(带 `来源` 字段)→ 回写源文件 `沉淀` 字段 → 重跑 gen-wiki-board。草稿是**中间态**:人工读一遍,归类到 `wiki/<主题>/`(补主题与用途,保留 `来源`)后跑生成器 + §4 验证。`--dry-run` 预览不写盘;仅占位的高价值节会被拒抽(内容无沉淀价值)。
30
32
  - **排除**:`workflow/`、依赖锁文件、IDE 配置。
31
33
 
32
34
  ## 3. 标准操作流程
@@ -35,8 +37,8 @@ description: 项目 wiki 整理与验证技能。负责把项目内散落文档
35
37
 
36
38
  1. **识别范围**:列出候选文件后逐篇读首行判断主题——pwsh:`Get-ChildItem -Recurse -File -Include *.md` / `Get-Content <文件> -TotalCount 8`;POSIX:`find` / `head -8`。
37
39
  2. **主题判定**:主题由内容自决,不预设分类。当前已沉淀主题:`产品需求 / 项目计划 / 开发方案 / 用户功能 / 项目规范 / 测试报告 / 数据维护`。新增主题前先与用户对齐。
38
- 3. **建目录**:pwsh `New-Item -ItemType Directory -Force wiki/<主题>`(POSIX:`mkdir -p`);归档目录同理建 `wiki/drafts-archive/YYYY-MM-DD_<主题>`。
39
- 4. **复制并改名**:pwsh `Copy-Item 原路径 wiki/<主题>/<新名>`(POSIX:`cp`);来源为仓库内原位文件时,同时按原名复制一份到 `drafts-archive/YYYY-MM-DD_<主题>/` 留溯源。
40
+ 3. **建目录**:pwsh `New-Item -ItemType Directory -Force wiki/<主题>`(POSIX:`mkdir -p`);归档目录同理建 `wiki/drafts-archive/YYYY-MM-DD-<主题>`。
41
+ 4. **复制并改名**:pwsh `Copy-Item 原路径 wiki/<主题>/<新名>`(POSIX:`cp`);来源为仓库内原位文件时,同时按原名复制一份到 `drafts-archive/YYYY-MM-DD-<主题>/` 留溯源。
40
42
  5. **生成索引**:跑 `node .agents/scripts/gen-wiki-board.mjs`(速览计数/映射表/看板 DATA 自动重生成);新主题在速览表「用途」列补一行描述后重跑。
41
43
  6. **自检**:跑第 4 节"验证脚本",确认三方一致、目录无孤儿。
42
44
 
@@ -16,12 +16,55 @@
16
16
  | 项目计划 | 1 | 计划、里程碑与会议纪要(按日期命名) |
17
17
  | 测试报告 | 1 | 测试报告与验收记录(按 日期-主题 命名) |
18
18
  | 数据维护 | 1 | schema 变更与数据修复台账(子目录按批次组织,批内 README 记账,不参与文件级登记) |
19
+ | drafts-archive | — | 原文档备份(按 日期-主题 分目录) |
19
20
 
20
21
  合计:**7 份**知识文档,**7 个主题**
21
22
 
22
23
  ## 文件 → 主题 → 归属目录 映射表
23
24
 
24
- (生成区:gen-wiki-board.mjs 维护)
25
+ ### 产品需求(1)
26
+
27
+ | 文件名 | 主题 | 归属目录 |
28
+ |---|---|---|
29
+ | README.md | 产品需求 | wiki/产品需求/ |
30
+
31
+ ### 用户功能(1)
32
+
33
+ | 文件名 | 主题 | 归属目录 |
34
+ |---|---|---|
35
+ | README.md | 用户功能 | wiki/用户功能/ |
36
+
37
+ ### 开发方案(1)
38
+
39
+ | 文件名 | 主题 | 归属目录 |
40
+ |---|---|---|
41
+ | README.md | 开发方案 | wiki/开发方案/ |
42
+
43
+ ### 项目规范(1)
44
+
45
+ | 文件名 | 主题 | 归属目录 |
46
+ |---|---|---|
47
+ | README.md | 项目规范 | wiki/项目规范/ |
48
+
49
+ ### 项目计划(1)
50
+
51
+ | 文件名 | 主题 | 归属目录 |
52
+ |---|---|---|
53
+ | README.md | 项目计划 | wiki/项目计划/ |
54
+
55
+ ### 测试报告(1)
56
+
57
+ | 文件名 | 主题 | 归属目录 |
58
+ |---|---|---|
59
+ | README.md | 测试报告 | wiki/测试报告/ |
60
+
61
+ ### 数据维护(1)
62
+
63
+ | 文件名 | 主题 | 归属目录 |
64
+ |---|---|---|
65
+ | README.md | 数据维护 | wiki/数据维护/ |
66
+
67
+ ---
25
68
 
26
69
  ## 命名规则
27
70
 
@@ -20,8 +20,29 @@
20
20
  <div id="app"></div>
21
21
  <script>
22
22
  const DATA = {
23
- "summary": { "total": 0, "topics": 0, "files": 0, "archive": 0 },
23
+ "summary": { "total": 7, "topics": 7, "files": 7, "archive": 1 },
24
24
  "topics": [
25
+ { "name": "产品需求", "files": [
26
+ { "file": "README.md", "topic": "产品需求", "dir": "./产品需求/" }
27
+ ]},
28
+ { "name": "用户功能", "files": [
29
+ { "file": "README.md", "topic": "用户功能", "dir": "./用户功能/" }
30
+ ]},
31
+ { "name": "开发方案", "files": [
32
+ { "file": "README.md", "topic": "开发方案", "dir": "./开发方案/" }
33
+ ]},
34
+ { "name": "项目规范", "files": [
35
+ { "file": "README.md", "topic": "项目规范", "dir": "./项目规范/" }
36
+ ]},
37
+ { "name": "项目计划", "files": [
38
+ { "file": "README.md", "topic": "项目计划", "dir": "./项目计划/" }
39
+ ]},
40
+ { "name": "测试报告", "files": [
41
+ { "file": "README.md", "topic": "测试报告", "dir": "./测试报告/" }
42
+ ]},
43
+ { "name": "数据维护", "files": [
44
+ { "file": "README.md", "topic": "数据维护", "dir": "./数据维护/" }
45
+ ]}
25
46
  ]
26
47
  };
27
48
  (function () {
@@ -5,19 +5,20 @@
5
5
  > - **委派结果表**:每次向子智能体/执行模型委派后追加一行。
6
6
  > - **自做任务结果表**:主智能体自己完成的 **L1+ 新需求任务**,闭环时(intent→done)追加一行;**修复类不重复记**——incident 本身即故障信号,聚合脚本按月扫 `workflow/incidents/` 计数。
7
7
  > - 结果列取值:`一次通过`(静态门首跑全过且复核无 P0/P1 返工)/ `返工×N`(回炉 N 次)/ `主兜底`(executor 失败、主智能体接手——委派口径专用,计返工信号)/ `返工待修`(未闭环,不计入率,单列提示)。
8
+ > - **合入结论列**(末列,2026-10-12 merge-accept-rate):`合入` / `返工后合入` / `未合入` / 留空。为什么单列而不并进结果列:结果列度量**执行过程质量**(跑了几遍),合入结论度量**产出被不被人接受**——METR 2026-03 实测落差(agent 生成的 SWE-bench 通过 PR,维护者合并判定比自动评分低约 24 个百分点、约一半不会被合入)说明「自动门全绿」与「人愿意合」是两个维度,混在一列必然被前者盖过后者。记法:关单时顺手一写;留空 = 未记录(**不计入接受率分母**,存量行零回填)。边界:结论由人工/独立复核写入,机器无法判真伪(同 `--delegated` 信任边界);它是**观测项不是门槛项**——不进 §并发扩容门槛(样本 <5 不出率)。对标:<https://metr.org/notes/2026-03-10-many-swe-bench-passing-prs-would-not-be-merged-into-main/>
8
9
  > 聚合:`node .agents/scripts/agg-delegations.cjs` → 输出各月指标 + 扩容门判定 + 可粘贴快照行,粘贴进 §月度聚合快照(每月一行)。聚合时顺路按「三类清理清单」巡检 AGENTS.md:代码/配置已可推导的删;只针对一次需求的细节移 wiki 或删;已被脚本/hook/测试自动保证的只留入口。
9
10
  > 口径说明:合并冲突率不适用(单人串行 + 每阶段确认);人工复核负担以「复核类委派的返工行」近似(见结果列 + 备注)。
10
11
  > 调整某角色的模型指派前,先从 `workflow/incidents/` 取 3 个已定性 bug 丢给候选模型做回归对比,再拍板。
11
12
 
12
13
  ## 委派结果
13
14
 
14
- | 日期 | 被委派方(模型) | 任务一句话 | 结果 | 备注 |
15
- |------|----------------|------------|------|------|
15
+ | 日期 | 被委派方(模型) | 任务一句话 | 结果 | 备注 | 合入结论 |
16
+ |------|----------------|------------|------|------|----------|
16
17
 
17
18
  ## 自做任务结果
18
19
 
19
- | 日期 | 任务一句话 | 结果 | 备注 |
20
- |------|------------|------|------|
20
+ | 日期 | 任务一句话 | 结果 | 备注 | 合入结论 |
21
+ |------|------------|------|------|----------|
21
22
 
22
23
  ## 月度聚合快照
23
24
 
@@ -3,6 +3,7 @@
3
3
  级别: L1
4
4
  发现: YYYY-MM-DD
5
5
  模块: <词表之一,见 .agents/workflow-modules.txt>
6
+ 沉淀: <可选:复盘沉淀到 wiki 的相对仓根路径,如 wiki/项目规范/权限收敛方案.md;不沉淀写「无」,留空待 check-loop 提醒;关单时可跑 node .agents/scripts/draft-sediment.mjs 自动抽草稿并回写本字段>
6
7
  ---
7
8
  # INCIDENT — <日期 主题>
8
9
  <!-- 复制为 YYYY-MM-DD-<主题>.md;线上或实测发现的功能缺陷都记录,历史 BUG 可回填 -->
@@ -20,6 +21,7 @@
20
21
 
21
22
  ## 根因
22
23
  <一句话;深层原因另起一行>
24
+ <!-- 复杂度收敛证据收集(P4 判据触发器,2026-10-11):根因若与重复/未收拢代码有关(改 A 处漏了同源 B 处、克隆分叉),在此写明涉及的两处位置——这是「收敛须有消费方与事故证据才启动」判据的直接采集点(证据出现再立项收拢,基线对照 scripts/jscpd-baseline.json;无关联则无视本行) -->
23
25
 
24
26
  ## 为什么之前没拦住
25
27
  <门禁 / 测试 / 规范各查一遍:哪一层本可以拦住>
@@ -3,6 +3,7 @@
3
3
  级别: L1
4
4
  日期: YYYY-MM-DD
5
5
  模块: <词表之一,见 .agents/workflow-modules.txt>
6
+ 沉淀: <可选:沉淀到 wiki 的相对仓根路径,如 wiki/项目规范/权限收敛方案.md;不沉淀写「无」,留空待 check-loop 提醒;关单时可跑 node .agents/scripts/draft-sediment.mjs 自动抽草稿并回写本字段>
6
7
  备注: <可选:附注自由文本,check-loop 不解析>
7
8
  ---
8
9
  # INTENT — <主题>
@@ -39,3 +40,5 @@
39
40
 
40
41
  > **闭环对账**:关单在 test 阶段(不依赖 deploy)。intent 置 done 前逐条勾验,每条勾选项后补证据——`- [x] <判据>(证据:<commit SHA / 测试用例名 / 冒烟脚本输出>)`。
41
42
  > done 状态仍有未勾项会被 check-loop 拦截(2026-09-12 起新建 intent 为 hard-block,存量 intent 仅 warning 提示);勾选但缺「证据:」为 warning。
43
+ > **场景覆盖**(2026-10-10 scenario-coverage 灰度):同名 spec 写了「验收场景」节时,本节须**逐场景 ID 引用**——
44
+ > `- [x] 场景:S1 <判据>(证据:…)`。缺引用只出 warning(灰度第一档,不阻断);spec 无该节则本条不适用。
@@ -7,6 +7,9 @@
7
7
  <!-- 与 intents/ 或 incidents/ 下同名入口文档配对;L2/L3 必须先有 ../specs/ 同名 spec 确认通过;AI 起草、用户对话内确认后开工 -->
8
8
  <!-- frontmatter 受限子集(2026-09-13):状态∈draft/approved/done/superseded/cancelled(严格枚举,附注写备注键);级别∈L0/L1/L2/L3;正文不再写状态/级别行 -->
9
9
  <!-- L1 极简形态(Quick-Plan,与 fill-plan.mjs 单源一致):单/少文件微改动只填「改动方案」+「约束与风险」+「验证计划」三节(L1 主节标题模板正文用「改动面」,fill-plan 生成「改动方案」——check-loop 证据校验对 改动面/任务拆解/改动方案 三种节名均识别为声明文件来源)——改动方案逐条列改哪个文件做什么(判据细节直接写进条目),验证计划一行静态门 + 按需 UI 实测;任务拆解/执行顺序仅 L1 多文件多步骤时保留 -->
10
+ <!-- 待澄清标记(2026-10-12 needs-clarification):判据不明 / 依赖不确定 / 用户没说的细节,照实写一行
11
+ `- 待澄清:<你卡在哪>`,不要猜(语义说明同 specs 模板:占位符=忘了填,本标记=我不知道)。
12
+ 起草不拦,draft→approved 确认时仍挂着会被 confirm-doc 拒绝;解决后改行首为 `- 已澄清:` 或删行。 -->
10
13
 
11
14
  对应入口:../intents/YYYY-MM-DD-<主题>.md 或 ../incidents/YYYY-MM-DD-<主题>.md(保留实际一项)
12
15
  对应 spec:../specs/YYYY-MM-DD-<主题>.md(L1 可省略)
@@ -26,6 +29,7 @@
26
29
  <1 → 2 → 3;标注依赖关系>
27
30
 
28
31
  ## 验证方式
32
+ - 验证层标注:每条验收标准标注验证层(单元 / 集成 / E2E / 人工实测)——关单证据按层对质,「已人工验证」不替代可自动化层
29
33
  - 静态门:`项目构建命令`(+ `项目测试命令`,测试项目就绪后)
30
34
  - 前端:cd frontend && npm run build(vue-tsc)
31
35
  - UI:.agents/commands/test.md(涉及页面改动必走,headless Chrome 实测)
@@ -6,12 +6,35 @@
6
6
  # SPEC — <与入口文档同名主题>
7
7
  <!-- 与 intents/ 或 incidents/ 下同名入口文档配对;L2 / L3 必须先有 spec 确认通过方可起草 plan;L1 可省略 -->
8
8
  <!-- frontmatter 受限子集(2026-09-13):状态∈draft/approved/done/superseded/cancelled(done=关单、superseded=曾确认后放弃、cancelled=未完成即取消);L3 确认通过后在 frontmatter 追加两行:`确认结果: approved` 与 `确认时间: YYYY-MM-DD`(check-loop 对 L3 强制校验) -->
9
+ <!-- 待澄清标记(2026-10-12 needs-clarification):起草时**不确定的地方照实写一行** `- 待澄清:<你卡在哪>`,
10
+ 不要猜一个填上去——「我不知道」是负责,猜是失职(与检查 2 的模板占位符语义相反:占位符是忘了填)。
11
+ 起草门不拦(不阻塞你继续写);但 draft→approved 确认时仍挂着未澄清项会被 confirm-doc 拒绝落账——
12
+ 确认即「认可这份文档」,文档里写着「这里我不知道」就没法确认。
13
+ 解决后把行首改成 `- 已澄清:…`(**保留该行**,留痕曾不清楚过,便于事后对质)或直接删行。
14
+ 判据单源:stage-gates.mjs#openClarifications / clarifyGateFor(confirm-doc 消费)。 -->
9
15
 
10
16
  对应入口:../intents/YYYY-MM-DD-<主题>.md 或 ../incidents/YYYY-MM-DD-<主题>.md(保留实际一项)
11
17
 
12
18
  ## 功能行为
13
19
  <讲清功能怎么工作;分小节列用户 / 系统行为,必要时附状态机 / 时序图说明>
14
20
 
21
+ ## 验收场景(可选)
22
+ <结构化验收用例,GIVEN/WHEN/THEN 三行写法。每条带场景 ID(S1、S2…),同名 intent 的「验收标准」
23
+ 按 ID 逐条引用——check-loop 检查 8 会校验场景覆盖(缺引用 = warning,灰度第一档)。
24
+ THEN 行是机器对账断言:声明了场景却缺「- THEN <可观测结果>」行 = 空壳场景,check-loop 出
25
+ [WARN 场景无断言](advisory,灰度第一档)。
26
+ **本节可选**:不写时检查 8 走原「逐条勾验」判据,行为零变化;写了则 intent 的验收标准应覆盖全部场景 ID。>
27
+
28
+ ### S1 <场景名>
29
+ - GIVEN <前置条件>
30
+ - WHEN <触发动作>
31
+ - THEN <可观测的结果断言>
32
+
33
+ ### S2 <场景名>
34
+ - GIVEN <前置条件>
35
+ - WHEN <触发动作>
36
+ - THEN <可观测的结果断言>
37
+
15
38
  ## 数据流
16
39
  <数据从哪里来 → 经过哪些处理 → 落到哪里;含字段映射、接口契约、上下游依赖>
17
40