agentic-flow-kit 0.2.0 → 0.3.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 (70) hide show
  1. package/README.md +4 -2
  2. package/modules/gates/dotnet-ca/check-architecture.sh +14 -10
  3. package/modules/hosts/trae/commands/wf-build.md +14 -14
  4. package/modules/hosts/trae/commands/wf-deploy.md +13 -13
  5. package/modules/hosts/trae/commands/wf-design.md +13 -13
  6. package/modules/hosts/trae/commands/wf-maintain.md +13 -13
  7. package/modules/hosts/trae/commands/wf-new-task.md +13 -13
  8. package/modules/hosts/trae/commands/wf-plan.md +13 -13
  9. package/modules/hosts/trae/commands/wf-review.md +13 -13
  10. package/modules/hosts/trae/commands/wf-test.md +14 -14
  11. package/modules/hosts/trae/hooks/post-edit-check.cjs +10 -0
  12. package/modules/hosts/trae/hooks/pre-shell-check.cjs +14 -4
  13. package/modules/hosts/trae/hooks/resolve-shell.cjs +30 -21
  14. package/modules/hosts/trae/rules/beautify-input-chinese.md +6 -6
  15. package/modules/hosts/trae/rules/git-commit-message.md +10 -10
  16. package/package.json +10 -2
  17. package/src/add-gate.mjs +8 -1
  18. package/src/add-host.mjs +4 -0
  19. package/src/cli.mjs +8 -5
  20. package/src/doctor.mjs +9 -2
  21. package/src/init.mjs +96 -12
  22. package/src/init.test.mjs +56 -0
  23. package/src/profiles.mjs +8 -0
  24. package/src/render.mjs +8 -9
  25. package/src/run-tests.mjs +1 -0
  26. package/src/sync.mjs +20 -4
  27. package/src/sync.test.mjs +40 -1
  28. package/templates/AGENTS.md +3 -2
  29. package/templates/_agents/board/index.html +449 -382
  30. package/templates/_agents/board/marked.min.js +6 -6
  31. package/templates/_agents/cache/kb-index.json +1 -1
  32. package/templates/_agents/commands/build.md +1 -1
  33. package/templates/_agents/commands/design.md +1 -1
  34. package/templates/_agents/commands/maintain.md +1 -1
  35. package/templates/_agents/commands/new-task.md +73 -73
  36. package/templates/_agents/commands/plan.md +2 -2
  37. package/templates/_agents/commands/test.md +2 -1
  38. package/templates/_agents/hooks/check-pairing-incremental.sh +30 -29
  39. package/templates/_agents/hooks/commit-check.cjs +6 -1
  40. package/templates/_agents/scripts/agg-delegations.cjs +35 -18
  41. package/templates/_agents/scripts/agg-delegations.test.mjs +95 -0
  42. package/templates/_agents/scripts/check-loop.sh +6 -0
  43. package/templates/_agents/scripts/check-loop.test.sh +1042 -1042
  44. package/templates/_agents/scripts/commit-check-trigger.test.mjs +94 -0
  45. package/templates/_agents/scripts/ensure-board.ps1 +1 -1
  46. package/templates/_agents/scripts/gen-wiki-board.mjs +13 -3
  47. package/templates/_agents/scripts/gen-wiki-board.test.mjs +22 -0
  48. package/templates/_agents/scripts/gen-workflow-index.mjs +7 -2
  49. package/templates/_agents/scripts/gen-workflow-index.test.mjs +27 -0
  50. package/templates/_agents/scripts/gen-workflow-metrics.mjs +17 -3
  51. package/templates/_agents/scripts/gen-workflow-metrics.test.mjs +21 -0
  52. package/templates/_agents/scripts/kb-search.mjs +2 -1
  53. package/templates/_agents/scripts/rule-budget.sh +8 -2
  54. package/templates/_agents/scripts/verify-wiki-consistency.mjs +6 -1
  55. package/templates/_agents/scripts/verify.mjs +36 -0
  56. package/templates/_agents/scripts/verify.test.mjs +77 -0
  57. package/templates/_agents/scripts/workflow-board-server.mjs +245 -244
  58. package/templates/_githooks/commit-msg +4 -2
  59. package/templates/_githooks/pre-push +32 -32
  60. package/templates/wiki/INDEX.md +9 -2
  61. package/templates/wiki//344/272/247/345/223/201/351/234/200/346/261/202/README.md +3 -0
  62. package/templates/wiki//345/274/200/345/217/221/346/226/271/346/241/210/README.md +3 -0
  63. package/templates/wiki//346/225/260/346/215/256/347/273/264/346/212/244/README.md +3 -0
  64. package/templates/wiki//346/265/213/350/257/225/346/212/245/345/221/212/README.md +3 -0
  65. package/templates/wiki//347/224/250/346/210/267/345/212/237/350/203/275/README.md +3 -0
  66. package/templates/wiki//351/241/271/347/233/256/350/247/204/350/214/203/README.md +3 -0
  67. package/templates/wiki//351/241/271/347/233/256/350/256/241/345/210/222/README.md +3 -0
  68. package/templates/workflow/README.md +2 -2
  69. package/templates/workflow/intents/_TEMPLATE.md +40 -40
  70. package/templates/workflow/specs/_TEMPLATE.md +41 -41
@@ -1,1042 +1,1042 @@
1
- #!/bin/sh
2
- # check-loop.sh 的 fixture 驱动测试(2026-09-13 随 frontmatter 结构化改造引入)
3
- # 现场构造临时 workflow 根目录,经 CHECK_LOOP_ROOT 注入被测脚本,断言 exit code 与 hard-block 关键词。
4
- # 用法:sh .agents/scripts/check-loop.test.sh(在仓库任意目录执行均可)
5
-
6
- SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
7
- TARGET="$SCRIPT_DIR/check-loop.sh"
8
- PASS=0
9
- FAIL=0
10
-
11
- # 断言:expect_hard=1 期望 exit 1 且输出含关键词;expect_hard=0 期望 exit 0(输出不阻断)
12
- assert_case() {
13
- desc="$1"; fixture_root="$2"; expect_hard="$3"; keyword="$4"
14
- out=$(CHECK_LOOP_ROOT="$fixture_root" sh "$TARGET" 2>&1)
15
- rc=$?
16
- if [ "$expect_hard" = "1" ]; then
17
- if [ "$rc" -eq 1 ] && printf '%s' "$out" | grep -q "$keyword"; then
18
- PASS=$((PASS+1)); printf 'PASS %s\n' "$desc"
19
- else
20
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 1 + 关键词[%s],实际 exit %s)\n%s\n' "$desc" "$keyword" "$rc" "$out"
21
- fi
22
- else
23
- if [ "$rc" -eq 0 ]; then
24
- PASS=$((PASS+1)); printf 'PASS %s\n' "$desc"
25
- else
26
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0,实际 exit %s)\n%s\n' "$desc" "$rc" "$out"
27
- fi
28
- fi
29
- }
30
-
31
- # mkfix:建空 fixture 根并返回路径
32
- mkfix() {
33
- d=$(mktemp -d)
34
- mkdir -p "$d/workflow/intents" "$d/workflow/specs" "$d/workflow/plans" "$d/workflow/incidents"
35
- printf '%s' "$d"
36
- }
37
-
38
- # ---- 场景 1:全合法闭环(intent+plan,L1,done 全勾验带证据)→ exit 0 ----
39
- T=$(mkfix)
40
- cat > "$T/workflow/intents/2026-09-12-ok.md" <<'EOF'
41
- ---
42
- 状态: done
43
- 级别: L1
44
- 日期: 2026-09-12
45
- ---
46
- # INTENT — ok
47
-
48
- ## 验收标准(可测试)
49
- - [x] 用例通过(证据:dotnet test 全绿)
50
- EOF
51
- cat > "$T/workflow/plans/2026-09-12-ok.md" <<'EOF'
52
- ---
53
- 状态: done
54
- 级别: L1
55
- ---
56
- # PLAN — ok
57
- EOF
58
- assert_case "全合法闭环(L1 done 勾验带证据) → exit 0" "$T" 0 ""
59
- rm -rf "$T"
60
-
61
- # ---- 场景 2:intent 缺 plan → hard ----
62
- T=$(mkfix)
63
- cat > "$T/workflow/intents/2026-09-12-a.md" <<'EOF'
64
- ---
65
- 状态: approved
66
- 级别: L1
67
- 日期: 2026-09-12
68
- ---
69
- # INTENT — a
70
- EOF
71
- assert_case "intent 缺 plan → hard 配对断裂" "$T" 1 "配对断裂"
72
- rm -rf "$T"
73
-
74
- # ---- 场景 3:L2 intent 缺 spec → hard ----
75
- T=$(mkfix)
76
- cat > "$T/workflow/intents/2026-09-12-b.md" <<'EOF'
77
- ---
78
- 状态: approved
79
- 级别: L2
80
- 日期: 2026-09-12
81
- ---
82
- # INTENT — b
83
- EOF
84
- cat > "$T/workflow/plans/2026-09-12-b.md" <<'EOF'
85
- ---
86
- 状态: approved
87
- 级别: L2
88
- ---
89
- # PLAN — b
90
- EOF
91
- assert_case "L2 intent 缺 spec → hard 配对断裂" "$T" 1 "缺 spec"
92
- rm -rf "$T"
93
-
94
- # ---- 场景 4:L3 spec 缺确认三件 → hard ----
95
- T=$(mkfix)
96
- cat > "$T/workflow/intents/2026-09-12-c.md" <<'EOF'
97
- ---
98
- 状态: approved
99
- 级别: L3
100
- 日期: 2026-09-12
101
- ---
102
- # INTENT — c
103
- EOF
104
- cat > "$T/workflow/specs/2026-09-12-c.md" <<'EOF'
105
- ---
106
- 状态: approved
107
- 级别: L3
108
- ---
109
- # SPEC — c
110
-
111
- ## 确认与复核
112
- EOF
113
- cat > "$T/workflow/plans/2026-09-12-c.md" <<'EOF'
114
- ---
115
- 状态: approved
116
- 级别: L3
117
- ---
118
- # PLAN — c
119
- EOF
120
- assert_case "L3 spec 缺确认三件 → hard" "$T" 1 "L3 确认缺失"
121
- rm -rf "$T"
122
-
123
- # ---- 场景 5:L3 spec 确认三件齐全 → exit 0 ----
124
- T=$(mkfix)
125
- cat > "$T/workflow/intents/2026-09-12-d.md" <<'EOF'
126
- ---
127
- 状态: approved
128
- 级别: L3
129
- 日期: 2026-09-12
130
- ---
131
- # INTENT — d
132
- EOF
133
- cat > "$T/workflow/specs/2026-09-12-d.md" <<'EOF'
134
- ---
135
- 状态: approved
136
- 级别: L3
137
- 确认结果: approved
138
- 确认时间: 2026-09-12
139
- ---
140
- # SPEC — d
141
-
142
- ## 确认与复核
143
- - 独立复核:已由 independent-reviewer 新会话完成,结论 approved
144
- EOF
145
- cat > "$T/workflow/plans/2026-09-12-d.md" <<'EOF'
146
- ---
147
- 状态: approved
148
- 级别: L3
149
- ---
150
- # PLAN — d
151
- EOF
152
- assert_case "L3 确认三件齐全(frontmatter 2 件+正文独立复核) → exit 0" "$T" 0 ""
153
- rm -rf "$T"
154
-
155
- # ---- 场景 6(papercut #4 回归):新建 done intent 验收未勾验 → hard;带附注不影响判定 ----
156
- T=$(mkfix)
157
- cat > "$T/workflow/intents/2026-09-13-e.md" <<'EOF'
158
- ---
159
- 状态: done
160
- 级别: L1
161
- 日期: 2026-09-13
162
- 备注: 回溯补档,原工作 2026-09-12 完成
163
- ---
164
- # INTENT — e
165
-
166
- ## 验收标准(可测试)
167
- - [ ] 用例通过
168
- EOF
169
- cat > "$T/workflow/plans/2026-09-13-e.md" <<'EOF'
170
- ---
171
- 状态: done
172
- 级别: L1
173
- ---
174
- # PLAN — e
175
- EOF
176
- assert_case "新建 done 未勾验(附注在备注键,状态仍纯枚举) → hard 验收未对账" "$T" 1 "验收未对账"
177
- rm -rf "$T"
178
-
179
- # ---- 场景 7:存量(<2026-09-12) done 未勾验 → warning,exit 0 ----
180
- T=$(mkfix)
181
- cat > "$T/workflow/intents/2026-09-01-f.md" <<'EOF'
182
- ---
183
- 状态: done
184
- 级别: L1
185
- 日期: 2026-09-01
186
- ---
187
- # INTENT — f
188
-
189
- ## 验收标准(可测试)
190
- - [ ] 用例通过
191
- EOF
192
- cat > "$T/workflow/plans/2026-09-01-f.md" <<'EOF'
193
- ---
194
- 状态: done
195
- 级别: L1
196
- ---
197
- # PLAN — f
198
- EOF
199
- assert_case "存量 done 未勾验 → warning 不阻断" "$T" 0 ""
200
- rm -rf "$T"
201
-
202
- # ---- 场景 8:incident 选「是」但 intent 不存在 → hard 回路断档 ----
203
- T=$(mkfix)
204
- cat > "$T/workflow/incidents/2026-09-12-g.md" <<'EOF'
205
- ---
206
- 状态: fixed
207
- 级别: L2
208
- 发现: 2026-09-12
209
- ---
210
- # INCIDENT — g
211
-
212
- ## 复盘三件套(缺一不可)
213
-
214
- 1. 结构性修复
215
- - 修复 commit:abc1234
216
- - 影响环境:dev
217
- - 是否需要新 intent:
218
- - 是 → ../intents/2026-09-12-ghost.md
219
-
220
- 2. 防复发验证
221
- - 用例:XxxTest
222
-
223
- 3. 规范条目
224
- - AGENTS.md 某节
225
- EOF
226
- cat > "$T/workflow/plans/2026-09-12-g.md" <<'EOF'
227
- ---
228
- 状态: done
229
- 级别: L2
230
- ---
231
- # PLAN — g
232
- EOF
233
- cat > "$T/workflow/specs/2026-09-12-g.md" <<'EOF'
234
- ---
235
- 状态: approved
236
- 级别: L2
237
- ---
238
- # SPEC — g
239
- EOF
240
- assert_case "incident 回路引用不存在 intent → hard 回路断档" "$T" 1 "回路断档"
241
- rm -rf "$T"
242
-
243
- # ---- 场景 9:incident 流程 legacy → 豁免级别/配对检查,exit 0 ----
244
- T=$(mkfix)
245
- cat > "$T/workflow/incidents/2026-08-27-h.md" <<'EOF'
246
- ---
247
- 状态: closed
248
- 流程: legacy
249
- 发现: 2026-08-27
250
- ---
251
- # INCIDENT — h(legacy 回填,无级别无配对)
252
-
253
- ## 复盘三件套(缺一不可)
254
-
255
- 1. 结构性修复
256
- - 修复 commit:历史回填
257
- - 影响环境:dev
258
- - 是否需要新 intent:
259
- - 否 → 理由:legacy 回填
260
-
261
- 2. 防复发验证
262
- - 回归清单条目在案
263
-
264
- 3. 规范条目
265
- - AGENTS.md 某节
266
- EOF
267
- assert_case "incident legacy 豁免配对 → exit 0" "$T" 0 ""
268
- rm -rf "$T"
269
-
270
- # ---- 场景 10:无 frontmatter → 状态键缺失 warning,exit 0(非 L3) ----
271
- T=$(mkfix)
272
- cat > "$T/workflow/intents/2026-09-12-i.md" <<'EOF'
273
- # INTENT — i(未迁移旧格式)
274
-
275
- 状态:draft
276
- EOF
277
- cat > "$T/workflow/plans/2026-09-12-i.md" <<'EOF'
278
- ---
279
- 状态: approved
280
- 级别: L1
281
- ---
282
- # PLAN — i
283
- EOF
284
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
285
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 状态未确认.*i.md"; then
286
- PASS=$((PASS+1)); printf 'PASS %s\n' "无 frontmatter → warning 提示状态键缺失"
287
- else
288
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 状态未提示)\n%s\n' "无 frontmatter → warning 提示状态键缺失" "$out"
289
- fi
290
- rm -rf "$T"
291
-
292
- # ---- 场景 11:frontmatter 状态值域外(自造值)→ warning,exit 0(非 L3) ----
293
- T=$(mkfix)
294
- cat > "$T/workflow/intents/2026-09-12-j.md" <<'EOF'
295
- ---
296
- 状态: 进行中
297
- 级别: L1
298
- 日期: 2026-09-12
299
- ---
300
- # INTENT — j
301
- EOF
302
- cat > "$T/workflow/plans/2026-09-12-j.md" <<'EOF'
303
- ---
304
- 状态: approved
305
- 级别: L1
306
- ---
307
- # PLAN — j
308
- EOF
309
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
310
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 状态未确认.*j.md.*进行中"; then
311
- PASS=$((PASS+1)); printf 'PASS %s\n' "状态值域外 → warning 且带当前值提示"
312
- else
313
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 带当前值)\n%s\n' "状态值域外 → warning 且带当前值提示" "$out"
314
- fi
315
- rm -rf "$T"
316
-
317
- # ---- 场景 12:无 frontmatter 的旧格式 L3 声明 → 状态 warning(有意决策,见注释) ----
318
- # frontmatter 唯一来源:无 frontmatter 判不出 L3,降为 warning 引导补 frontmatter;
319
- # 不回退读正文级别行(回退=双源,违背结构化初衷)。恶意删 frontmatter 绕 hard 与旧格式删状态行同性质,不设防。
320
- T=$(mkfix)
321
- cat > "$T/workflow/intents/2026-09-12-k.md" <<'EOF'
322
- # INTENT — k
323
-
324
- 级别:L3
325
- 状态:approved
326
- EOF
327
- cat > "$T/workflow/plans/2026-09-12-k.md" <<'EOF'
328
- # PLAN — k
329
-
330
- 级别:L3
331
- 状态:approved
332
- EOF
333
- cat > "$T/workflow/specs/2026-09-12-k.md" <<'EOF'
334
- # SPEC — k
335
-
336
- 级别:L3
337
- 状态:approved
338
- EOF
339
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
340
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 状态未确认.*k.md(frontmatter 状态键当前值:『缺失』)"; then
341
- PASS=$((PASS+1)); printf 'PASS %s\n' "无 frontmatter 旧格式 → warning 引导补 frontmatter(不回退读正文)"
342
- else
343
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 状态键缺失)\n%s\n' "无 frontmatter 旧格式 → warning 引导补 frontmatter(不回退读正文)" "$out"
344
- fi
345
- rm -rf "$T"
346
-
347
- # ---- 场景 13:git fixture——L1 intent 与迁移 SQL 同 commit → warning,exit 0(检查项 10) ----
348
- T=$(mkfix)
349
- git -C "$T" init -q
350
- cat > "$T/workflow/intents/2026-09-12-m.md" <<'EOF'
351
- ---
352
- 状态: done
353
- 级别: L1
354
- 日期: 2026-09-12
355
- ---
356
- # INTENT — m
357
-
358
- ## 验收标准(可测试)
359
- - [x] 场景构造项(证据:fixture)
360
- EOF
361
- cat > "$T/workflow/plans/2026-09-12-m.md" <<'EOF'
362
- ---
363
- 状态: done
364
- 级别: L1
365
- ---
366
- # PLAN — m
367
- EOF
368
- mkdir -p "$T/docs/scripts"
369
- printf 'CREATE TABLE t(id INT);\n' > "$T/docs/scripts/01-add-table.sql"
370
- git -C "$T" add -A
371
- git -C "$T" -c user.email=t@t -c user.name=t commit -qm test
372
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
373
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 级别疑似判低.*m.md"; then
374
- PASS=$((PASS+1)); printf 'PASS %s\n' "L1 入口文档提交触及迁移 SQL → warning 疑似判低"
375
- else
376
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 级别疑似判低)\n%s\n' "L1 入口文档提交触及迁移 SQL → warning 疑似判低" "$out"
377
- fi
378
- rm -rf "$T"
379
-
380
- # ---- 场景 14:git fixture——L3 intent 与迁移 SQL 同 commit → 级别一致,不告警,exit 0 ----
381
- T=$(mkfix)
382
- git -C "$T" init -q
383
- cat > "$T/workflow/intents/2026-09-12-n.md" <<'EOF'
384
- ---
385
- 状态: done
386
- 级别: L3
387
- 日期: 2026-09-12
388
- ---
389
- # INTENT — n
390
-
391
- ## 验收标准(可测试)
392
- - [x] 场景构造项(证据:fixture)
393
- EOF
394
- cat > "$T/workflow/specs/2026-09-12-n.md" <<'EOF'
395
- ---
396
- 状态: done
397
- 级别: L3
398
- 确认结果: approved
399
- 确认时间: 2026-09-12
400
- ---
401
- # SPEC — n
402
-
403
- ## 确认与复核
404
- - 独立复核:已由 independent-reviewer 新会话完成,结论 approved
405
- EOF
406
- cat > "$T/workflow/plans/2026-09-12-n.md" <<'EOF'
407
- ---
408
- 状态: done
409
- 级别: L3
410
- ---
411
- # PLAN — n
412
- EOF
413
- mkdir -p "$T/docs/scripts"
414
- printf 'CREATE TABLE t(id INT);\n' > "$T/docs/scripts/01-add-table.sql"
415
- git -C "$T" add -A
416
- git -C "$T" -c user.email=t@t -c user.name=t commit -qm test
417
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
418
- if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "级别疑似判低"; then
419
- PASS=$((PASS+1)); printf 'PASS %s\n' "L3 入口文档提交触及迁移 SQL → 级别一致不告警"
420
- else
421
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无级别疑似判低)\n%s\n' "L3 入口文档提交触及迁移 SQL → 级别一致不告警" "$out"
422
- fi
423
- rm -rf "$T"
424
-
425
- # ---- 场景 15:ZCode Adapter 缺失不再告警(本地配置不入 git),但存在且断线仍告警 ----
426
- T=$(mkfix)
427
- cat > "$T/workflow/intents/2026-09-12-o.md" <<'EOF'
428
- ---
429
- 状态: done
430
- 级别: L1
431
- 日期: 2026-09-12
432
- ---
433
- # INTENT — o
434
-
435
- ## 验收标准(可测试)
436
- - [x] 用例通过(证据:全绿)
437
- EOF
438
- cat > "$T/workflow/plans/2026-09-12-o.md" <<'EOF'
439
- ---
440
- 状态: done
441
- 级别: L1
442
- ---
443
- # PLAN — o
444
- EOF
445
- mkdir -p "$T/.agents/roles" "$T/.zcode/agents"
446
- for r in implementer independent-reviewer ui-verifier; do printf '# role %s\n' "$r" > "$T/.agents/roles/$r.md"; done
447
- printf -- '---\nname: implementer\n---\n断线内容,无角色引用\n' > "$T/.zcode/agents/implementer.md"
448
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
449
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "ZCode implementer 未引用公共角色" && ! printf '%s' "$out" | grep -q "ZCode 缺"; then
450
- PASS=$((PASS+1)); printf 'PASS %s\n' "ZCode 缺失跳过/存在断线仍告警"
451
- else
452
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + ZCode 断线告警且无缺失告警)\n%s\n' "ZCode 缺失跳过/存在断线仍告警" "$out"
453
- fi
454
- rm -rf "$T"
455
-
456
- # ---- 场景 16:skills 引用仓库内与用户级均不存在 → 仍报引用断档(用户级回退不放行一切) ----
457
- T=$(mkfix)
458
- cat > "$T/workflow/README.md" <<'EOF'
459
- # WF README
460
-
461
- 技能见 .agents/skills/fake-skill(仓库内与用户级均不存在)
462
- EOF
463
- cat > "$T/workflow/intents/2026-09-12-p.md" <<'EOF'
464
- ---
465
- 状态: done
466
- 级别: L1
467
- 日期: 2026-09-12
468
- ---
469
- # INTENT — p
470
-
471
- ## 验收标准(可测试)
472
- - [x] 用例通过(证据:全绿)
473
- EOF
474
- cat > "$T/workflow/plans/2026-09-12-p.md" <<'EOF'
475
- ---
476
- 状态: done
477
- 级别: L1
478
- ---
479
- # PLAN — p
480
- EOF
481
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
482
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "引用断档.*fake-skill"; then
483
- PASS=$((PASS+1)); printf 'PASS %s\n' "skills 引用仓库内与用户级均无 → 仍报引用断档"
484
- else
485
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + 引用断档告警)\n%s\n' "skills 引用仓库内与用户级均无 → 仍报引用断档" "$out"
486
- fi
487
- rm -rf "$T"
488
-
489
- # ---- 场景 17:存量 done 未勾验但含「存量对账豁免」声明 → 出账,无验收对账 warning ----
490
- T=$(mkfix)
491
- cat > "$T/workflow/intents/2026-09-01-q.md" <<'EOF'
492
- ---
493
- 状态: done
494
- 级别: L1
495
- 日期: 2026-09-01
496
- ---
497
- # INTENT — q
498
-
499
- ## 验收标准(可测试)
500
- > **存量对账豁免(2026-09-12,用户拍板不追溯)**:下方未勾项均为第二轮 UI/浏览器实测项。
501
- - [ ] 用例通过
502
- EOF
503
- cat > "$T/workflow/plans/2026-09-01-q.md" <<'EOF'
504
- ---
505
- 状态: done
506
- 级别: L1
507
- ---
508
- # PLAN — q
509
- EOF
510
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
511
- if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "验收对账存量"; then
512
- PASS=$((PASS+1)); printf 'PASS %s\n' "存量含豁免声明 → 出账不计未对账"
513
- else
514
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无验收对账存量 warning)\n%s\n' "存量含豁免声明 → 出账不计未对账" "$out"
515
- fi
516
- rm -rf "$T"
517
-
518
- # ---- 场景 18:新建 done intent 缺「## 验收标准」节 → hard(2026-09-16 补口回归:此前后缺节静默通过) ----
519
- T=$(mkfix)
520
- cat > "$T/workflow/intents/2026-09-13-r.md" <<'EOF'
521
- ---
522
- 状态: done
523
- 级别: L1
524
- 日期: 2026-09-13
525
- ---
526
- # INTENT — r
527
-
528
- ## 目标
529
- 关单前未写验收标准节。
530
- EOF
531
- cat > "$T/workflow/plans/2026-09-13-r.md" <<'EOF'
532
- ---
533
- 状态: done
534
- 级别: L1
535
- ---
536
- # PLAN — r
537
- EOF
538
- assert_case "新建 done 缺验收标准节 → hard 验收未对账" "$T" 1 "缺「## 验收标准」节"
539
- rm -rf "$T"
540
-
541
- # ---- 场景 19:新建 done intent 勾选项缩进写法 → hard(口径放宽后仍拦,2026-09-16 补口回归) ----
542
- T=$(mkfix)
543
- cat > "$T/workflow/intents/2026-09-13-s.md" <<'EOF'
544
- ---
545
- 状态: done
546
- 级别: L1
547
- 日期: 2026-09-13
548
- ---
549
- # INTENT — s
550
-
551
- ## 验收标准(可测试)
552
- - [ ] 缩进未勾项(此前后静默通过)
553
- EOF
554
- cat > "$T/workflow/plans/2026-09-13-s.md" <<'EOF'
555
- ---
556
- 状态: done
557
- 级别: L1
558
- ---
559
- # PLAN — s
560
- EOF
561
- assert_case "新建 done 勾选项缩进 → hard 验收未对账" "$T" 1 "验收未对账"
562
- rm -rf "$T"
563
-
564
- # ---- 场景 20:incident 状态值域外 → warning(2026-09-16 补口:此前 incident 状态零断言) ----
565
- T=$(mkfix)
566
- cat > "$T/workflow/incidents/2026-09-13-t.md" <<'EOF'
567
- ---
568
- 状态: 已修复
569
- 级别: L1
570
- 发现: 2026-09-13
571
- ---
572
- # INCIDENT — t
573
-
574
- ## 复盘三件套(缺一不可)
575
-
576
- 1. 结构性修复
577
- - 修复 commit:abc1234
578
- - 影响环境:dev
579
- - 是否需要新 intent:
580
- - 否 → 理由:实现 bug 单点修复
581
-
582
- 2. 防复发验证
583
- - 回归清单条目在案
584
-
585
- 3. 规范条目
586
- - AGENTS.md 某节
587
- EOF
588
- cat > "$T/workflow/plans/2026-09-13-t.md" <<'EOF'
589
- ---
590
- 状态: done
591
- 级别: L1
592
- ---
593
- # PLAN — t
594
- EOF
595
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
596
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 状态非法.*t.md.*已修复"; then
597
- PASS=$((PASS+1)); printf 'PASS %s\n' "incident 状态值域外 → warning 且带当前值"
598
- else
599
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 状态非法)\n%s\n' "incident 状态值域外 → warning 且带当前值" "$out"
600
- fi
601
- rm -rf "$T"
602
-
603
- # ---- 场景 21:incident 缺级别 → warning 明示配对检查已跳过(不再静默豁免整段配对门) ----
604
- T=$(mkfix)
605
- cat > "$T/workflow/incidents/2026-09-13-u.md" <<'EOF'
606
- ---
607
- 状态: open
608
- 发现: 2026-09-13
609
- ---
610
- # INCIDENT — u
611
-
612
- ## 复盘三件套(缺一不可)
613
-
614
- 1. 结构性修复
615
- - 修复 commit:待修复
616
- - 影响环境:dev
617
- - 是否需要新 intent:
618
- - 否 → 理由:实现 bug 单点修复
619
-
620
- 2. 防复发验证
621
- - 回归清单条目在案
622
-
623
- 3. 规范条目
624
- - AGENTS.md 某节
625
- EOF
626
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
627
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 级别缺失.*u.md.*配对检查已跳过"; then
628
- PASS=$((PASS+1)); printf 'PASS %s\n' "incident 缺级别 → warning 明示配对已跳过"
629
- else
630
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 级别缺失含配对提示)\n%s\n' "incident 缺级别 → warning 明示配对已跳过" "$out"
631
- fi
632
- rm -rf "$T"
633
-
634
- # ---- 场景 22:存量(<2026-09-12) done 缺验收标准节 → 不 hard(存量聚合 warning 口径) ----
635
- T=$(mkfix)
636
- cat > "$T/workflow/intents/2026-09-01-v.md" <<'EOF'
637
- ---
638
- 状态: done
639
- 级别: L1
640
- 日期: 2026-09-01
641
- ---
642
- # INTENT — v
643
-
644
- ## 目标
645
- 存量旧格式,缺验收标准节。
646
- EOF
647
- cat > "$T/workflow/plans/2026-09-01-v.md" <<'EOF'
648
- ---
649
- 状态: done
650
- 级别: L1
651
- ---
652
- # PLAN — v
653
- EOF
654
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
655
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "验收对账存量"; then
656
- PASS=$((PASS+1)); printf 'PASS %s\n' "存量 done 缺节 → 聚合 warning 不 hard"
657
- else
658
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + 验收对账存量 warning)\n%s\n' "存量 done 缺节 → 聚合 warning 不 hard" "$out"
659
- fi
660
- rm -rf "$T"
661
-
662
- # ---- 场景 15:git 仓库模式——未跟踪的并行半成品(draft intent 无 plan)不拦 push → exit 0 ----
663
- # 2026-09-18 现场:共享工作区里并行会话的未跟踪 draft intent(尚未配 plan)恰好处于编辑瞬间,
664
- # 拦住了另一会话的 push。修复口径:仓库模式只扫 HEAD 已提交内容。此场景不设 CHECK_LOOP_ROOT(走 git 模式)。
665
- T=$(mkfix)
666
- git -C "$T" init -q
667
- cat > "$T/workflow/intents/2026-09-12-ok2.md" <<'EOF'
668
- ---
669
- 状态: done
670
- 级别: L1
671
- 日期: 2026-09-12
672
- ---
673
- # INTENT — ok2
674
-
675
- ## 验收标准(可测试)
676
- - [x] 场景构造项(证据:fixture)
677
- EOF
678
- cat > "$T/workflow/plans/2026-09-12-ok2.md" <<'EOF'
679
- ---
680
- 状态: done
681
- 级别: L1
682
- ---
683
- # PLAN — ok2
684
- EOF
685
- git -C "$T" add -A
686
- git -C "$T" -c user.email=t@t -c user.name=t commit -qm base
687
- # 未跟踪的并行半成品:draft L1 intent,无同名 plan(修复前会 hard-block「入口缺同名 plan」+ WARN 状态未确认)
688
- cat > "$T/workflow/intents/2026-09-18-parallel-wip.md" <<'EOF'
689
- ---
690
- 状态: draft
691
- 级别: L1
692
- 日期: 2026-09-18
693
- ---
694
- # INTENT — 并行会话半成品
695
- EOF
696
- out=$(cd "$T" && sh "$TARGET" 2>&1); rc=$?
697
- if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "parallel-wip"; then
698
- PASS=$((PASS+1)); printf 'PASS %s\n' "仓库模式:未跟踪 draft intent(无 plan)不进扫描,不拦 push"
699
- else
700
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且输出不含 parallel-wip,实际 exit %s)\n%s\n' "仓库模式:未跟踪 draft intent(无 plan)不进扫描,不拦 push" "$rc" "$out"
701
- fi
702
-
703
- # ---- 场景 16:git 仓库模式——同一断档件提交进 HEAD 后仍须 hard-block(门禁不因过滤失效)----
704
- git -C "$T" add workflow/intents/2026-09-18-parallel-wip.md
705
- git -C "$T" -c user.email=t@t -c user.name=t commit -qm wip
706
- out=$(cd "$T" && sh "$TARGET" 2>&1); rc=$?
707
- if [ "$rc" -eq 1 ] && printf '%s' "$out" | grep -q "缺 plan.*parallel-wip"; then
708
- PASS=$((PASS+1)); printf 'PASS %s\n' "仓库模式:已提交的入口缺 plan 断档仍 hard-block"
709
- else
710
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 1 + 关键词[缺同名 plan],实际 exit %s)\n%s\n' "仓库模式:已提交的入口缺 plan 断档仍 hard-block" "$rc" "$out"
711
- fi
712
- rm -rf "$T"
713
-
714
- # ---- 场景 23:检索层——模块合法 + INDEX 一致 → exit 0 且无两条新告警 ----
715
- # fixture 拷入真实生成器与词表(测接线,非假桩;生成器逻辑自身由 gen-workflow-index.test.mjs 覆盖)
716
- T=$(mkfix)
717
- mkdir -p "$T/.agents/scripts" "$T/.agents"
718
- cp "$SCRIPT_DIR/gen-workflow-index.mjs" "$T/.agents/scripts/"
719
- cp "$SCRIPT_DIR/../workflow-modules.txt" "$T/.agents/"
720
- cat > "$T/workflow/intents/2026-09-22-mod-ok.md" <<'EOF'
721
- ---
722
- 状态: approved
723
- 级别: L1
724
- 日期: 2026-09-22
725
- 模块: pipeline
726
- ---
727
- # INTENT — mod ok
728
-
729
- ## 验收标准(可测试)
730
- - [ ] 用例通过
731
- EOF
732
- cat > "$T/workflow/plans/2026-09-22-mod-ok.md" <<'EOF'
733
- ---
734
- 状态: approved
735
- 级别: L1
736
- 模块: pipeline
737
- ---
738
- # PLAN — mod ok
739
- EOF
740
- (cd "$T" && node .agents/scripts/gen-workflow-index.mjs >/dev/null 2>&1)
741
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
742
- if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "WARN 模块元数据" && ! printf '%s' "$out" | grep -q "WARN 索引漂移"; then
743
- PASS=$((PASS+1)); printf 'PASS %s\n' "检索层:模块合法+INDEX 一致 → exit 0 无新告警"
744
- else
745
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无模块/索引告警)\n%s\n' "检索层:模块合法+INDEX 一致 → exit 0 无新告警" "$out"
746
- fi
747
- rm -rf "$T"
748
-
749
- # ---- 场景 24:模块枚举非法 + 2026-09-22 起新建缺字段 → WARN 不阻断 ----
750
- T=$(mkfix)
751
- mkdir -p "$T/.agents"
752
- cp "$SCRIPT_DIR/../workflow-modules.txt" "$T/.agents/"
753
- cat > "$T/workflow/intents/2026-09-22-mod-bad.md" <<'EOF'
754
- ---
755
- 状态: approved
756
- 级别: L1
757
- 日期: 2026-09-22
758
- 模块: 不存在的模块
759
- ---
760
- # INTENT — mod bad
761
- EOF
762
- cat > "$T/workflow/plans/2026-09-22-mod-bad.md" <<'EOF'
763
- ---
764
- 状态: approved
765
- 级别: L1
766
- ---
767
- # PLAN — mod bad
768
- EOF
769
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
770
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 模块元数据" && printf '%s' "$out" | grep -q "不在词表" && printf '%s' "$out" | grep -q "缺「模块:」字段"; then
771
- PASS=$((PASS+1)); printf 'PASS %s\n' "检索层:模块非法/缺字段 → WARN 且 exit 0"
772
- else
773
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + 模块元数据 WARN 含两类)\n%s\n' "检索层:模块非法/缺字段 → WARN 且 exit 0" "$out"
774
- fi
775
- rm -rf "$T"
776
-
777
- # ---- 场景 25:INDEX 漂移 → WARN 索引漂移,exit 0(口径:调生成器 --check)----
778
- T=$(mkfix)
779
- mkdir -p "$T/.agents/scripts" "$T/.agents"
780
- cp "$SCRIPT_DIR/gen-workflow-index.mjs" "$T/.agents/scripts/"
781
- cp "$SCRIPT_DIR/../workflow-modules.txt" "$T/.agents/"
782
- cat > "$T/workflow/intents/2026-09-22-drift.md" <<'EOF'
783
- ---
784
- 状态: approved
785
- 级别: L1
786
- 日期: 2026-09-22
787
- 模块: pipeline
788
- ---
789
- # INTENT — drift
790
-
791
- ## 验收标准(可测试)
792
- - [ ] 用例通过
793
- EOF
794
- cat > "$T/workflow/plans/2026-09-22-drift.md" <<'EOF'
795
- ---
796
- 状态: approved
797
- 级别: L1
798
- 模块: pipeline
799
- ---
800
- # PLAN — drift
801
- EOF
802
- (cd "$T" && node .agents/scripts/gen-workflow-index.mjs >/dev/null 2>&1)
803
- sed -i 's/^状态: approved$/状态: done/' "$T/workflow/plans/2026-09-22-drift.md" 2>/dev/null || printf '%s\n' "$(sed 's/^状态: approved$/状态: done/' "$T/workflow/plans/2026-09-22-drift.md")" > "$T/workflow/plans/2026-09-22-drift.md"
804
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
805
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 索引漂移"; then
806
- PASS=$((PASS+1)); printf 'PASS %s\n' "检索层:INDEX 漂移 → WARN 且 exit 0"
807
- else
808
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 索引漂移)\n%s\n' "检索层:INDEX 漂移 → WARN 且 exit 0" "$out"
809
- fi
810
- rm -rf "$T"
811
-
812
- # ---- 场景 26:常驻面预算——合规(小体积)→ 无超限告警,exit 0 ----
813
- T=$(mkfix)
814
- mkdir -p "$T/.agents/scripts"
815
- cp "$SCRIPT_DIR/rule-budget.sh" "$T/.agents/scripts/"
816
- cp "$SCRIPT_DIR/../rule-budgets.txt" "$T/.agents/"
817
- printf '# AGENTS 小体积 fixture\n' > "$T/AGENTS.md"
818
- mkdir -p "$T/.agents/commands"
819
- printf '# 小命令\n' > "$T/.agents/commands/plan.md"
820
- cat > "$T/workflow/intents/2026-09-22-budget-ok.md" <<'EOF'
821
- ---
822
- 状态: approved
823
- 级别: L1
824
- 日期: 2026-09-22
825
- 模块: pipeline
826
- ---
827
- # INTENT — budget ok
828
- EOF
829
- cat > "$T/workflow/plans/2026-09-22-budget-ok.md" <<'EOF'
830
- ---
831
- 状态: approved
832
- 级别: L1
833
- 模块: pipeline
834
- ---
835
- # PLAN — budget ok
836
- EOF
837
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
838
- if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "WARN 常驻面超限"; then
839
- PASS=$((PASS+1)); printf 'PASS %s\n' "常驻面预算:合规 → 无超限告警且 exit 0"
840
- else
841
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无超限告警)\n%s\n' "常驻面预算:合规 → 无超限告警且 exit 0" "$out"
842
- fi
843
- rm -rf "$T"
844
-
845
- # ---- 场景 27:常驻面预算——AGENTS.md 超限 → WARN 且 exit 0(一进一出提示)----
846
- T=$(mkfix)
847
- mkdir -p "$T/.agents/scripts"
848
- cp "$SCRIPT_DIR/rule-budget.sh" "$T/.agents/scripts/"
849
- cp "$SCRIPT_DIR/../rule-budgets.txt" "$T/.agents/"
850
- head -c 8000 /dev/zero | tr '\0' 'x' > "$T/AGENTS.md"
851
- cat > "$T/workflow/intents/2026-09-22-budget-bad.md" <<'EOF'
852
- ---
853
- 状态: approved
854
- 级别: L1
855
- 日期: 2026-09-22
856
- 模块: pipeline
857
- ---
858
- # INTENT — budget bad
859
- EOF
860
- cat > "$T/workflow/plans/2026-09-22-budget-bad.md" <<'EOF'
861
- ---
862
- 状态: approved
863
- 级别: L1
864
- 模块: pipeline
865
- ---
866
- # PLAN — budget bad
867
- EOF
868
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
869
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 常驻面超限" && printf '%s' "$out" | grep -q "一进一出"; then
870
- PASS=$((PASS+1)); printf 'PASS %s\n' "常驻面预算:超限 → WARN(含一进一出提示) 且 exit 0"
871
- else
872
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 常驻面超限)\n%s\n' "常驻面预算:超限 → WARN 且 exit 0" "$out"
873
- fi
874
- rm -rf "$T"
875
-
876
- # ---- 场景 28:rule-budget --staged——暂存超限即 exit 1(pre-commit 硬拦路径);换成合规即 exit 0 ----
877
- T=$(mkfix)
878
- mkdir -p "$T/.agents/scripts"
879
- cp "$SCRIPT_DIR/rule-budget.sh" "$T/.agents/scripts/"
880
- cp "$SCRIPT_DIR/../rule-budgets.txt" "$T/.agents/"
881
- git -C "$T" init -q
882
- head -c 8000 /dev/zero | tr '\0' 'x' > "$T/AGENTS.md"
883
- git -C "$T" add AGENTS.md
884
- out=$(cd "$T" && sh .agents/scripts/rule-budget.sh --staged 2>&1); rc=$?
885
- if [ "$rc" -eq 1 ] && printf '%s' "$out" | grep -q "常驻面超限:AGENTS.md"; then
886
- PASS=$((PASS+1)); printf 'PASS %s\n' "rule-budget --staged:暂存超限 → exit 1(硬拦路径)"
887
- else
888
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 1 + 超限行,实际 exit %s)\n%s\n' "rule-budget --staged:暂存超限 → exit 1" "$rc" "$out"
889
- fi
890
- printf '# 小体积\n' > "$T/AGENTS.md"
891
- git -C "$T" add AGENTS.md
892
- out2=$(cd "$T" && sh .agents/scripts/rule-budget.sh --staged 2>&1); rc2=$?
893
- if [ "$rc2" -eq 0 ]; then
894
- PASS=$((PASS+1)); printf 'PASS %s\n' "rule-budget --staged:合规 → exit 0(不误拦)"
895
- else
896
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0,实际 exit %s)\n%s\n' "rule-budget --staged:合规 → exit 0" "$rc2" "$out2"
897
- fi
898
- rm -rf "$T"
899
-
900
- # ---- 场景 29:git fixture——新 done 的 spec/plan 历史无 approved → WARN 确认态缺失,exit 0(检查项 14) ----
901
- T=$(mkfix)
902
- git -C "$T" init -q
903
- cat > "$T/workflow/incidents/2026-09-23-confirm-gate.md" <<'EOF'
904
- ---
905
- 状态: closed
906
- 级别: L1
907
- 发现: 2026-09-23
908
- 模块: material
909
- ---
910
- # INCIDENT — confirm gate
911
-
912
- ## 复盘三件套(缺一不可)
913
-
914
- 1. 结构性修复
915
- - 修复 commit:abc1234
916
- - 影响环境:dev
917
- - 是否需要新 intent:
918
- - 否 → 理由:实现 bug 单点修复
919
-
920
- 2. 防复发验证
921
- - 回归清单条目在案
922
-
923
- 3. 规范条目
924
- - AGENTS.md 某节
925
- EOF
926
- cat > "$T/workflow/plans/2026-09-23-confirm-gate.md" <<'EOF'
927
- ---
928
- 状态: done
929
- 级别: L1
930
- 模块: material
931
- ---
932
- # PLAN — confirm gate
933
- EOF
934
- git -C "$T" add -A
935
- git -C "$T" -c user.email=t@t -c user.name=t commit -qm test
936
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
937
- if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 确认态缺失.*2026-09-23-confirm-gate.md"; then
938
- PASS=$((PASS+1)); printf 'PASS %s\n' "新 done 无 approved 历史 → WARN 确认态缺失 且 exit 0"
939
- else
940
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 确认态缺失)\n%s\n' "新 done 无 approved 历史 → WARN 确认态缺失" "$out"
941
- fi
942
- rm -rf "$T"
943
-
944
- # ---- 场景 30:git fixture——先 approved 后 done(确认环节留痕)→ 无该 WARN,exit 0 ----
945
- T=$(mkfix)
946
- git -C "$T" init -q
947
- cat > "$T/workflow/incidents/2026-09-23-confirm-ok.md" <<'EOF'
948
- ---
949
- 状态: closed
950
- 级别: L1
951
- 发现: 2026-09-23
952
- 模块: material
953
- ---
954
- # INCIDENT — confirm ok
955
-
956
- ## 复盘三件套(缺一不可)
957
-
958
- 1. 结构性修复
959
- - 修复 commit:abc1234
960
- - 影响环境:dev
961
- - 是否需要新 intent:
962
- - 否 → 理由:实现 bug 单点修复
963
-
964
- 2. 防复发验证
965
- - 回归清单条目在案
966
-
967
- 3. 规范条目
968
- - AGENTS.md 某节
969
- EOF
970
- cat > "$T/workflow/plans/2026-09-23-confirm-ok.md" <<'EOF'
971
- ---
972
- 状态: approved
973
- 级别: L1
974
- 模块: material
975
- ---
976
- # PLAN — confirm ok
977
- EOF
978
- git -C "$T" add -A
979
- git -C "$T" -c user.email=t@t -c user.name=t commit -qm approved
980
- cat > "$T/workflow/plans/2026-09-23-confirm-ok.md" <<'EOF'
981
- ---
982
- 状态: done
983
- 级别: L1
984
- 模块: material
985
- ---
986
- # PLAN — confirm ok
987
- EOF
988
- git -C "$T" add -A
989
- git -C "$T" -c user.email=t@t -c user.name=t commit -qm done
990
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
991
- if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "WARN 确认态缺失"; then
992
- PASS=$((PASS+1)); printf 'PASS %s\n' "approved → done 留痕 → 无确认态缺失告警"
993
- else
994
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无确认态缺失告警)\n%s\n' "approved → done 留痕 → 无确认态缺失告警" "$out"
995
- fi
996
- rm -rf "$T"
997
-
998
- # ---- 场景 31:非 git fixture——历史不可考,检查项 14 静默跳过(不误报) ----
999
- T=$(mkfix)
1000
- cat > "$T/workflow/incidents/2026-09-23-confirm-nogit.md" <<'EOF'
1001
- ---
1002
- 状态: closed
1003
- 级别: L1
1004
- 发现: 2026-09-23
1005
- 模块: material
1006
- ---
1007
- # INCIDENT — confirm nogit
1008
-
1009
- ## 复盘三件套(缺一不可)
1010
-
1011
- 1. 结构性修复
1012
- - 修复 commit:abc1234
1013
- - 影响环境:dev
1014
- - 是否需要新 intent:
1015
- - 否 → 理由:实现 bug 单点修复
1016
-
1017
- 2. 防复发验证
1018
- - 回归清单条目在案
1019
-
1020
- 3. 规范条目
1021
- - AGENTS.md 某节
1022
- EOF
1023
- cat > "$T/workflow/plans/2026-09-23-confirm-nogit.md" <<'EOF'
1024
- ---
1025
- 状态: done
1026
- 级别: L1
1027
- 模块: material
1028
- ---
1029
- # PLAN — confirm nogit
1030
- EOF
1031
- out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
1032
- if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "WARN 确认态缺失"; then
1033
- PASS=$((PASS+1)); printf 'PASS %s\n' "非 git fixture → 检查项 14 跳过,不误报"
1034
- else
1035
- FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无确认态缺失告警)\n%s\n' "非 git fixture → 检查项 14 跳过" "$out"
1036
- fi
1037
- rm -rf "$T"
1038
-
1039
- # ---- 汇总 ----
1040
- printf '\n合计: PASS %s / FAIL %s\n' "$PASS" "$FAIL"
1041
- [ "$FAIL" -eq 0 ] || exit 1
1042
- exit 0
1
+ #!/bin/sh
2
+ # check-loop.sh 的 fixture 驱动测试(2026-09-13 随 frontmatter 结构化改造引入)
3
+ # 现场构造临时 workflow 根目录,经 CHECK_LOOP_ROOT 注入被测脚本,断言 exit code 与 hard-block 关键词。
4
+ # 用法:sh .agents/scripts/check-loop.test.sh(在仓库任意目录执行均可)
5
+
6
+ SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
7
+ TARGET="$SCRIPT_DIR/check-loop.sh"
8
+ PASS=0
9
+ FAIL=0
10
+
11
+ # 断言:expect_hard=1 期望 exit 1 且输出含关键词;expect_hard=0 期望 exit 0(输出不阻断)
12
+ assert_case() {
13
+ desc="$1"; fixture_root="$2"; expect_hard="$3"; keyword="$4"
14
+ out=$(CHECK_LOOP_ROOT="$fixture_root" sh "$TARGET" 2>&1)
15
+ rc=$?
16
+ if [ "$expect_hard" = "1" ]; then
17
+ if [ "$rc" -eq 1 ] && printf '%s' "$out" | grep -q "$keyword"; then
18
+ PASS=$((PASS+1)); printf 'PASS %s\n' "$desc"
19
+ else
20
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 1 + 关键词[%s],实际 exit %s)\n%s\n' "$desc" "$keyword" "$rc" "$out"
21
+ fi
22
+ else
23
+ if [ "$rc" -eq 0 ]; then
24
+ PASS=$((PASS+1)); printf 'PASS %s\n' "$desc"
25
+ else
26
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0,实际 exit %s)\n%s\n' "$desc" "$rc" "$out"
27
+ fi
28
+ fi
29
+ }
30
+
31
+ # mkfix:建空 fixture 根并返回路径
32
+ mkfix() {
33
+ d=$(mktemp -d)
34
+ mkdir -p "$d/workflow/intents" "$d/workflow/specs" "$d/workflow/plans" "$d/workflow/incidents"
35
+ printf '%s' "$d"
36
+ }
37
+
38
+ # ---- 场景 1:全合法闭环(intent+plan,L1,done 全勾验带证据)→ exit 0 ----
39
+ T=$(mkfix)
40
+ cat > "$T/workflow/intents/2026-09-12-ok.md" <<'EOF'
41
+ ---
42
+ 状态: done
43
+ 级别: L1
44
+ 日期: 2026-09-12
45
+ ---
46
+ # INTENT — ok
47
+
48
+ ## 验收标准(可测试)
49
+ - [x] 用例通过(证据:dotnet test 全绿)
50
+ EOF
51
+ cat > "$T/workflow/plans/2026-09-12-ok.md" <<'EOF'
52
+ ---
53
+ 状态: done
54
+ 级别: L1
55
+ ---
56
+ # PLAN — ok
57
+ EOF
58
+ assert_case "全合法闭环(L1 done 勾验带证据) → exit 0" "$T" 0 ""
59
+ rm -rf "$T"
60
+
61
+ # ---- 场景 2:intent 缺 plan → hard ----
62
+ T=$(mkfix)
63
+ cat > "$T/workflow/intents/2026-09-12-a.md" <<'EOF'
64
+ ---
65
+ 状态: approved
66
+ 级别: L1
67
+ 日期: 2026-09-12
68
+ ---
69
+ # INTENT — a
70
+ EOF
71
+ assert_case "intent 缺 plan → hard 配对断裂" "$T" 1 "配对断裂"
72
+ rm -rf "$T"
73
+
74
+ # ---- 场景 3:L2 intent 缺 spec → hard ----
75
+ T=$(mkfix)
76
+ cat > "$T/workflow/intents/2026-09-12-b.md" <<'EOF'
77
+ ---
78
+ 状态: approved
79
+ 级别: L2
80
+ 日期: 2026-09-12
81
+ ---
82
+ # INTENT — b
83
+ EOF
84
+ cat > "$T/workflow/plans/2026-09-12-b.md" <<'EOF'
85
+ ---
86
+ 状态: approved
87
+ 级别: L2
88
+ ---
89
+ # PLAN — b
90
+ EOF
91
+ assert_case "L2 intent 缺 spec → hard 配对断裂" "$T" 1 "缺 spec"
92
+ rm -rf "$T"
93
+
94
+ # ---- 场景 4:L3 spec 缺确认三件 → hard ----
95
+ T=$(mkfix)
96
+ cat > "$T/workflow/intents/2026-09-12-c.md" <<'EOF'
97
+ ---
98
+ 状态: approved
99
+ 级别: L3
100
+ 日期: 2026-09-12
101
+ ---
102
+ # INTENT — c
103
+ EOF
104
+ cat > "$T/workflow/specs/2026-09-12-c.md" <<'EOF'
105
+ ---
106
+ 状态: approved
107
+ 级别: L3
108
+ ---
109
+ # SPEC — c
110
+
111
+ ## 确认与复核
112
+ EOF
113
+ cat > "$T/workflow/plans/2026-09-12-c.md" <<'EOF'
114
+ ---
115
+ 状态: approved
116
+ 级别: L3
117
+ ---
118
+ # PLAN — c
119
+ EOF
120
+ assert_case "L3 spec 缺确认三件 → hard" "$T" 1 "L3 确认缺失"
121
+ rm -rf "$T"
122
+
123
+ # ---- 场景 5:L3 spec 确认三件齐全 → exit 0 ----
124
+ T=$(mkfix)
125
+ cat > "$T/workflow/intents/2026-09-12-d.md" <<'EOF'
126
+ ---
127
+ 状态: approved
128
+ 级别: L3
129
+ 日期: 2026-09-12
130
+ ---
131
+ # INTENT — d
132
+ EOF
133
+ cat > "$T/workflow/specs/2026-09-12-d.md" <<'EOF'
134
+ ---
135
+ 状态: approved
136
+ 级别: L3
137
+ 确认结果: approved
138
+ 确认时间: 2026-09-12
139
+ ---
140
+ # SPEC — d
141
+
142
+ ## 确认与复核
143
+ - 独立复核:已由 independent-reviewer 新会话完成,结论 approved
144
+ EOF
145
+ cat > "$T/workflow/plans/2026-09-12-d.md" <<'EOF'
146
+ ---
147
+ 状态: approved
148
+ 级别: L3
149
+ ---
150
+ # PLAN — d
151
+ EOF
152
+ assert_case "L3 确认三件齐全(frontmatter 2 件+正文独立复核) → exit 0" "$T" 0 ""
153
+ rm -rf "$T"
154
+
155
+ # ---- 场景 6(papercut #4 回归):新建 done intent 验收未勾验 → hard;带附注不影响判定 ----
156
+ T=$(mkfix)
157
+ cat > "$T/workflow/intents/2026-09-13-e.md" <<'EOF'
158
+ ---
159
+ 状态: done
160
+ 级别: L1
161
+ 日期: 2026-09-13
162
+ 备注: 回溯补档,原工作 2026-09-12 完成
163
+ ---
164
+ # INTENT — e
165
+
166
+ ## 验收标准(可测试)
167
+ - [ ] 用例通过
168
+ EOF
169
+ cat > "$T/workflow/plans/2026-09-13-e.md" <<'EOF'
170
+ ---
171
+ 状态: done
172
+ 级别: L1
173
+ ---
174
+ # PLAN — e
175
+ EOF
176
+ assert_case "新建 done 未勾验(附注在备注键,状态仍纯枚举) → hard 验收未对账" "$T" 1 "验收未对账"
177
+ rm -rf "$T"
178
+
179
+ # ---- 场景 7:存量(<2026-09-12) done 未勾验 → warning,exit 0 ----
180
+ T=$(mkfix)
181
+ cat > "$T/workflow/intents/2026-09-01-f.md" <<'EOF'
182
+ ---
183
+ 状态: done
184
+ 级别: L1
185
+ 日期: 2026-09-01
186
+ ---
187
+ # INTENT — f
188
+
189
+ ## 验收标准(可测试)
190
+ - [ ] 用例通过
191
+ EOF
192
+ cat > "$T/workflow/plans/2026-09-01-f.md" <<'EOF'
193
+ ---
194
+ 状态: done
195
+ 级别: L1
196
+ ---
197
+ # PLAN — f
198
+ EOF
199
+ assert_case "存量 done 未勾验 → warning 不阻断" "$T" 0 ""
200
+ rm -rf "$T"
201
+
202
+ # ---- 场景 8:incident 选「是」但 intent 不存在 → hard 回路断档 ----
203
+ T=$(mkfix)
204
+ cat > "$T/workflow/incidents/2026-09-12-g.md" <<'EOF'
205
+ ---
206
+ 状态: fixed
207
+ 级别: L2
208
+ 发现: 2026-09-12
209
+ ---
210
+ # INCIDENT — g
211
+
212
+ ## 复盘三件套(缺一不可)
213
+
214
+ 1. 结构性修复
215
+ - 修复 commit:abc1234
216
+ - 影响环境:dev
217
+ - 是否需要新 intent:
218
+ - 是 → ../intents/2026-09-12-ghost.md
219
+
220
+ 2. 防复发验证
221
+ - 用例:XxxTest
222
+
223
+ 3. 规范条目
224
+ - AGENTS.md 某节
225
+ EOF
226
+ cat > "$T/workflow/plans/2026-09-12-g.md" <<'EOF'
227
+ ---
228
+ 状态: done
229
+ 级别: L2
230
+ ---
231
+ # PLAN — g
232
+ EOF
233
+ cat > "$T/workflow/specs/2026-09-12-g.md" <<'EOF'
234
+ ---
235
+ 状态: approved
236
+ 级别: L2
237
+ ---
238
+ # SPEC — g
239
+ EOF
240
+ assert_case "incident 回路引用不存在 intent → hard 回路断档" "$T" 1 "回路断档"
241
+ rm -rf "$T"
242
+
243
+ # ---- 场景 9:incident 流程 legacy → 豁免级别/配对检查,exit 0 ----
244
+ T=$(mkfix)
245
+ cat > "$T/workflow/incidents/2026-08-27-h.md" <<'EOF'
246
+ ---
247
+ 状态: closed
248
+ 流程: legacy
249
+ 发现: 2026-08-27
250
+ ---
251
+ # INCIDENT — h(legacy 回填,无级别无配对)
252
+
253
+ ## 复盘三件套(缺一不可)
254
+
255
+ 1. 结构性修复
256
+ - 修复 commit:历史回填
257
+ - 影响环境:dev
258
+ - 是否需要新 intent:
259
+ - 否 → 理由:legacy 回填
260
+
261
+ 2. 防复发验证
262
+ - 回归清单条目在案
263
+
264
+ 3. 规范条目
265
+ - AGENTS.md 某节
266
+ EOF
267
+ assert_case "incident legacy 豁免配对 → exit 0" "$T" 0 ""
268
+ rm -rf "$T"
269
+
270
+ # ---- 场景 10:无 frontmatter → 状态键缺失 warning,exit 0(非 L3) ----
271
+ T=$(mkfix)
272
+ cat > "$T/workflow/intents/2026-09-12-i.md" <<'EOF'
273
+ # INTENT — i(未迁移旧格式)
274
+
275
+ 状态:draft
276
+ EOF
277
+ cat > "$T/workflow/plans/2026-09-12-i.md" <<'EOF'
278
+ ---
279
+ 状态: approved
280
+ 级别: L1
281
+ ---
282
+ # PLAN — i
283
+ EOF
284
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
285
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 状态未确认.*i.md"; then
286
+ PASS=$((PASS+1)); printf 'PASS %s\n' "无 frontmatter → warning 提示状态键缺失"
287
+ else
288
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 状态未提示)\n%s\n' "无 frontmatter → warning 提示状态键缺失" "$out"
289
+ fi
290
+ rm -rf "$T"
291
+
292
+ # ---- 场景 11:frontmatter 状态值域外(自造值)→ warning,exit 0(非 L3) ----
293
+ T=$(mkfix)
294
+ cat > "$T/workflow/intents/2026-09-12-j.md" <<'EOF'
295
+ ---
296
+ 状态: 进行中
297
+ 级别: L1
298
+ 日期: 2026-09-12
299
+ ---
300
+ # INTENT — j
301
+ EOF
302
+ cat > "$T/workflow/plans/2026-09-12-j.md" <<'EOF'
303
+ ---
304
+ 状态: approved
305
+ 级别: L1
306
+ ---
307
+ # PLAN — j
308
+ EOF
309
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
310
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 状态未确认.*j.md.*进行中"; then
311
+ PASS=$((PASS+1)); printf 'PASS %s\n' "状态值域外 → warning 且带当前值提示"
312
+ else
313
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 带当前值)\n%s\n' "状态值域外 → warning 且带当前值提示" "$out"
314
+ fi
315
+ rm -rf "$T"
316
+
317
+ # ---- 场景 12:无 frontmatter 的旧格式 L3 声明 → 状态 warning(有意决策,见注释) ----
318
+ # frontmatter 唯一来源:无 frontmatter 判不出 L3,降为 warning 引导补 frontmatter;
319
+ # 不回退读正文级别行(回退=双源,违背结构化初衷)。恶意删 frontmatter 绕 hard 与旧格式删状态行同性质,不设防。
320
+ T=$(mkfix)
321
+ cat > "$T/workflow/intents/2026-09-12-k.md" <<'EOF'
322
+ # INTENT — k
323
+
324
+ 级别:L3
325
+ 状态:approved
326
+ EOF
327
+ cat > "$T/workflow/plans/2026-09-12-k.md" <<'EOF'
328
+ # PLAN — k
329
+
330
+ 级别:L3
331
+ 状态:approved
332
+ EOF
333
+ cat > "$T/workflow/specs/2026-09-12-k.md" <<'EOF'
334
+ # SPEC — k
335
+
336
+ 级别:L3
337
+ 状态:approved
338
+ EOF
339
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
340
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 状态未确认.*k.md(frontmatter 状态键当前值:『缺失』)"; then
341
+ PASS=$((PASS+1)); printf 'PASS %s\n' "无 frontmatter 旧格式 → warning 引导补 frontmatter(不回退读正文)"
342
+ else
343
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 状态键缺失)\n%s\n' "无 frontmatter 旧格式 → warning 引导补 frontmatter(不回退读正文)" "$out"
344
+ fi
345
+ rm -rf "$T"
346
+
347
+ # ---- 场景 13:git fixture——L1 intent 与迁移 SQL 同 commit → warning,exit 0(检查项 10) ----
348
+ T=$(mkfix)
349
+ git -C "$T" init -q
350
+ cat > "$T/workflow/intents/2026-09-12-m.md" <<'EOF'
351
+ ---
352
+ 状态: done
353
+ 级别: L1
354
+ 日期: 2026-09-12
355
+ ---
356
+ # INTENT — m
357
+
358
+ ## 验收标准(可测试)
359
+ - [x] 场景构造项(证据:fixture)
360
+ EOF
361
+ cat > "$T/workflow/plans/2026-09-12-m.md" <<'EOF'
362
+ ---
363
+ 状态: done
364
+ 级别: L1
365
+ ---
366
+ # PLAN — m
367
+ EOF
368
+ mkdir -p "$T/docs/scripts"
369
+ printf 'CREATE TABLE t(id INT);\n' > "$T/docs/scripts/01-add-table.sql"
370
+ git -C "$T" add -A
371
+ git -C "$T" -c user.email=t@t -c user.name=t commit -qm test
372
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
373
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 级别疑似判低.*m.md"; then
374
+ PASS=$((PASS+1)); printf 'PASS %s\n' "L1 入口文档提交触及迁移 SQL → warning 疑似判低"
375
+ else
376
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 级别疑似判低)\n%s\n' "L1 入口文档提交触及迁移 SQL → warning 疑似判低" "$out"
377
+ fi
378
+ rm -rf "$T"
379
+
380
+ # ---- 场景 14:git fixture——L3 intent 与迁移 SQL 同 commit → 级别一致,不告警,exit 0 ----
381
+ T=$(mkfix)
382
+ git -C "$T" init -q
383
+ cat > "$T/workflow/intents/2026-09-12-n.md" <<'EOF'
384
+ ---
385
+ 状态: done
386
+ 级别: L3
387
+ 日期: 2026-09-12
388
+ ---
389
+ # INTENT — n
390
+
391
+ ## 验收标准(可测试)
392
+ - [x] 场景构造项(证据:fixture)
393
+ EOF
394
+ cat > "$T/workflow/specs/2026-09-12-n.md" <<'EOF'
395
+ ---
396
+ 状态: done
397
+ 级别: L3
398
+ 确认结果: approved
399
+ 确认时间: 2026-09-12
400
+ ---
401
+ # SPEC — n
402
+
403
+ ## 确认与复核
404
+ - 独立复核:已由 independent-reviewer 新会话完成,结论 approved
405
+ EOF
406
+ cat > "$T/workflow/plans/2026-09-12-n.md" <<'EOF'
407
+ ---
408
+ 状态: done
409
+ 级别: L3
410
+ ---
411
+ # PLAN — n
412
+ EOF
413
+ mkdir -p "$T/docs/scripts"
414
+ printf 'CREATE TABLE t(id INT);\n' > "$T/docs/scripts/01-add-table.sql"
415
+ git -C "$T" add -A
416
+ git -C "$T" -c user.email=t@t -c user.name=t commit -qm test
417
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
418
+ if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "级别疑似判低"; then
419
+ PASS=$((PASS+1)); printf 'PASS %s\n' "L3 入口文档提交触及迁移 SQL → 级别一致不告警"
420
+ else
421
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无级别疑似判低)\n%s\n' "L3 入口文档提交触及迁移 SQL → 级别一致不告警" "$out"
422
+ fi
423
+ rm -rf "$T"
424
+
425
+ # ---- 场景 15:ZCode Adapter 缺失不再告警(本地配置不入 git),但存在且断线仍告警 ----
426
+ T=$(mkfix)
427
+ cat > "$T/workflow/intents/2026-09-12-o.md" <<'EOF'
428
+ ---
429
+ 状态: done
430
+ 级别: L1
431
+ 日期: 2026-09-12
432
+ ---
433
+ # INTENT — o
434
+
435
+ ## 验收标准(可测试)
436
+ - [x] 用例通过(证据:全绿)
437
+ EOF
438
+ cat > "$T/workflow/plans/2026-09-12-o.md" <<'EOF'
439
+ ---
440
+ 状态: done
441
+ 级别: L1
442
+ ---
443
+ # PLAN — o
444
+ EOF
445
+ mkdir -p "$T/.agents/roles" "$T/.zcode/agents"
446
+ for r in implementer independent-reviewer ui-verifier; do printf '# role %s\n' "$r" > "$T/.agents/roles/$r.md"; done
447
+ printf -- '---\nname: implementer\n---\n断线内容,无角色引用\n' > "$T/.zcode/agents/implementer.md"
448
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
449
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "ZCode implementer 未引用公共角色" && ! printf '%s' "$out" | grep -q "ZCode 缺"; then
450
+ PASS=$((PASS+1)); printf 'PASS %s\n' "ZCode 缺失跳过/存在断线仍告警"
451
+ else
452
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + ZCode 断线告警且无缺失告警)\n%s\n' "ZCode 缺失跳过/存在断线仍告警" "$out"
453
+ fi
454
+ rm -rf "$T"
455
+
456
+ # ---- 场景 16:skills 引用仓库内与用户级均不存在 → 仍报引用断档(用户级回退不放行一切) ----
457
+ T=$(mkfix)
458
+ cat > "$T/workflow/README.md" <<'EOF'
459
+ # WF README
460
+
461
+ 技能见 .agents/skills/fake-skill(仓库内与用户级均不存在)
462
+ EOF
463
+ cat > "$T/workflow/intents/2026-09-12-p.md" <<'EOF'
464
+ ---
465
+ 状态: done
466
+ 级别: L1
467
+ 日期: 2026-09-12
468
+ ---
469
+ # INTENT — p
470
+
471
+ ## 验收标准(可测试)
472
+ - [x] 用例通过(证据:全绿)
473
+ EOF
474
+ cat > "$T/workflow/plans/2026-09-12-p.md" <<'EOF'
475
+ ---
476
+ 状态: done
477
+ 级别: L1
478
+ ---
479
+ # PLAN — p
480
+ EOF
481
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
482
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "引用断档.*fake-skill"; then
483
+ PASS=$((PASS+1)); printf 'PASS %s\n' "skills 引用仓库内与用户级均无 → 仍报引用断档"
484
+ else
485
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + 引用断档告警)\n%s\n' "skills 引用仓库内与用户级均无 → 仍报引用断档" "$out"
486
+ fi
487
+ rm -rf "$T"
488
+
489
+ # ---- 场景 17:存量 done 未勾验但含「存量对账豁免」声明 → 出账,无验收对账 warning ----
490
+ T=$(mkfix)
491
+ cat > "$T/workflow/intents/2026-09-01-q.md" <<'EOF'
492
+ ---
493
+ 状态: done
494
+ 级别: L1
495
+ 日期: 2026-09-01
496
+ ---
497
+ # INTENT — q
498
+
499
+ ## 验收标准(可测试)
500
+ > **存量对账豁免(2026-09-12,用户拍板不追溯)**:下方未勾项均为第二轮 UI/浏览器实测项。
501
+ - [ ] 用例通过
502
+ EOF
503
+ cat > "$T/workflow/plans/2026-09-01-q.md" <<'EOF'
504
+ ---
505
+ 状态: done
506
+ 级别: L1
507
+ ---
508
+ # PLAN — q
509
+ EOF
510
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
511
+ if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "验收对账存量"; then
512
+ PASS=$((PASS+1)); printf 'PASS %s\n' "存量含豁免声明 → 出账不计未对账"
513
+ else
514
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无验收对账存量 warning)\n%s\n' "存量含豁免声明 → 出账不计未对账" "$out"
515
+ fi
516
+ rm -rf "$T"
517
+
518
+ # ---- 场景 18:新建 done intent 缺「## 验收标准」节 → hard(2026-09-16 补口回归:此前后缺节静默通过) ----
519
+ T=$(mkfix)
520
+ cat > "$T/workflow/intents/2026-09-13-r.md" <<'EOF'
521
+ ---
522
+ 状态: done
523
+ 级别: L1
524
+ 日期: 2026-09-13
525
+ ---
526
+ # INTENT — r
527
+
528
+ ## 目标
529
+ 关单前未写验收标准节。
530
+ EOF
531
+ cat > "$T/workflow/plans/2026-09-13-r.md" <<'EOF'
532
+ ---
533
+ 状态: done
534
+ 级别: L1
535
+ ---
536
+ # PLAN — r
537
+ EOF
538
+ assert_case "新建 done 缺验收标准节 → hard 验收未对账" "$T" 1 "缺「## 验收标准」节"
539
+ rm -rf "$T"
540
+
541
+ # ---- 场景 19:新建 done intent 勾选项缩进写法 → hard(口径放宽后仍拦,2026-09-16 补口回归) ----
542
+ T=$(mkfix)
543
+ cat > "$T/workflow/intents/2026-09-13-s.md" <<'EOF'
544
+ ---
545
+ 状态: done
546
+ 级别: L1
547
+ 日期: 2026-09-13
548
+ ---
549
+ # INTENT — s
550
+
551
+ ## 验收标准(可测试)
552
+ - [ ] 缩进未勾项(此前后静默通过)
553
+ EOF
554
+ cat > "$T/workflow/plans/2026-09-13-s.md" <<'EOF'
555
+ ---
556
+ 状态: done
557
+ 级别: L1
558
+ ---
559
+ # PLAN — s
560
+ EOF
561
+ assert_case "新建 done 勾选项缩进 → hard 验收未对账" "$T" 1 "验收未对账"
562
+ rm -rf "$T"
563
+
564
+ # ---- 场景 20:incident 状态值域外 → warning(2026-09-16 补口:此前 incident 状态零断言) ----
565
+ T=$(mkfix)
566
+ cat > "$T/workflow/incidents/2026-09-13-t.md" <<'EOF'
567
+ ---
568
+ 状态: 已修复
569
+ 级别: L1
570
+ 发现: 2026-09-13
571
+ ---
572
+ # INCIDENT — t
573
+
574
+ ## 复盘三件套(缺一不可)
575
+
576
+ 1. 结构性修复
577
+ - 修复 commit:abc1234
578
+ - 影响环境:dev
579
+ - 是否需要新 intent:
580
+ - 否 → 理由:实现 bug 单点修复
581
+
582
+ 2. 防复发验证
583
+ - 回归清单条目在案
584
+
585
+ 3. 规范条目
586
+ - AGENTS.md 某节
587
+ EOF
588
+ cat > "$T/workflow/plans/2026-09-13-t.md" <<'EOF'
589
+ ---
590
+ 状态: done
591
+ 级别: L1
592
+ ---
593
+ # PLAN — t
594
+ EOF
595
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
596
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 状态非法.*t.md.*已修复"; then
597
+ PASS=$((PASS+1)); printf 'PASS %s\n' "incident 状态值域外 → warning 且带当前值"
598
+ else
599
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 状态非法)\n%s\n' "incident 状态值域外 → warning 且带当前值" "$out"
600
+ fi
601
+ rm -rf "$T"
602
+
603
+ # ---- 场景 21:incident 缺级别 → warning 明示配对检查已跳过(不再静默豁免整段配对门) ----
604
+ T=$(mkfix)
605
+ cat > "$T/workflow/incidents/2026-09-13-u.md" <<'EOF'
606
+ ---
607
+ 状态: open
608
+ 发现: 2026-09-13
609
+ ---
610
+ # INCIDENT — u
611
+
612
+ ## 复盘三件套(缺一不可)
613
+
614
+ 1. 结构性修复
615
+ - 修复 commit:待修复
616
+ - 影响环境:dev
617
+ - 是否需要新 intent:
618
+ - 否 → 理由:实现 bug 单点修复
619
+
620
+ 2. 防复发验证
621
+ - 回归清单条目在案
622
+
623
+ 3. 规范条目
624
+ - AGENTS.md 某节
625
+ EOF
626
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
627
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 级别缺失.*u.md.*配对检查已跳过"; then
628
+ PASS=$((PASS+1)); printf 'PASS %s\n' "incident 缺级别 → warning 明示配对已跳过"
629
+ else
630
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 级别缺失含配对提示)\n%s\n' "incident 缺级别 → warning 明示配对已跳过" "$out"
631
+ fi
632
+ rm -rf "$T"
633
+
634
+ # ---- 场景 22:存量(<2026-09-12) done 缺验收标准节 → 不 hard(存量聚合 warning 口径) ----
635
+ T=$(mkfix)
636
+ cat > "$T/workflow/intents/2026-09-01-v.md" <<'EOF'
637
+ ---
638
+ 状态: done
639
+ 级别: L1
640
+ 日期: 2026-09-01
641
+ ---
642
+ # INTENT — v
643
+
644
+ ## 目标
645
+ 存量旧格式,缺验收标准节。
646
+ EOF
647
+ cat > "$T/workflow/plans/2026-09-01-v.md" <<'EOF'
648
+ ---
649
+ 状态: done
650
+ 级别: L1
651
+ ---
652
+ # PLAN — v
653
+ EOF
654
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
655
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "验收对账存量"; then
656
+ PASS=$((PASS+1)); printf 'PASS %s\n' "存量 done 缺节 → 聚合 warning 不 hard"
657
+ else
658
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + 验收对账存量 warning)\n%s\n' "存量 done 缺节 → 聚合 warning 不 hard" "$out"
659
+ fi
660
+ rm -rf "$T"
661
+
662
+ # ---- 场景 15:git 仓库模式——未跟踪的并行半成品(draft intent 无 plan)不拦 push → exit 0 ----
663
+ # 2026-09-18 现场:共享工作区里并行会话的未跟踪 draft intent(尚未配 plan)恰好处于编辑瞬间,
664
+ # 拦住了另一会话的 push。修复口径:仓库模式只扫 HEAD 已提交内容。此场景不设 CHECK_LOOP_ROOT(走 git 模式)。
665
+ T=$(mkfix)
666
+ git -C "$T" init -q
667
+ cat > "$T/workflow/intents/2026-09-12-ok2.md" <<'EOF'
668
+ ---
669
+ 状态: done
670
+ 级别: L1
671
+ 日期: 2026-09-12
672
+ ---
673
+ # INTENT — ok2
674
+
675
+ ## 验收标准(可测试)
676
+ - [x] 场景构造项(证据:fixture)
677
+ EOF
678
+ cat > "$T/workflow/plans/2026-09-12-ok2.md" <<'EOF'
679
+ ---
680
+ 状态: done
681
+ 级别: L1
682
+ ---
683
+ # PLAN — ok2
684
+ EOF
685
+ git -C "$T" add -A
686
+ git -C "$T" -c user.email=t@t -c user.name=t commit -qm base
687
+ # 未跟踪的并行半成品:draft L1 intent,无同名 plan(修复前会 hard-block「入口缺同名 plan」+ WARN 状态未确认)
688
+ cat > "$T/workflow/intents/2026-09-18-parallel-wip.md" <<'EOF'
689
+ ---
690
+ 状态: draft
691
+ 级别: L1
692
+ 日期: 2026-09-18
693
+ ---
694
+ # INTENT — 并行会话半成品
695
+ EOF
696
+ out=$(cd "$T" && sh "$TARGET" 2>&1); rc=$?
697
+ if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "parallel-wip"; then
698
+ PASS=$((PASS+1)); printf 'PASS %s\n' "仓库模式:未跟踪 draft intent(无 plan)不进扫描,不拦 push"
699
+ else
700
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且输出不含 parallel-wip,实际 exit %s)\n%s\n' "仓库模式:未跟踪 draft intent(无 plan)不进扫描,不拦 push" "$rc" "$out"
701
+ fi
702
+
703
+ # ---- 场景 16:git 仓库模式——同一断档件提交进 HEAD 后仍须 hard-block(门禁不因过滤失效)----
704
+ git -C "$T" add workflow/intents/2026-09-18-parallel-wip.md
705
+ git -C "$T" -c user.email=t@t -c user.name=t commit -qm wip
706
+ out=$(cd "$T" && sh "$TARGET" 2>&1); rc=$?
707
+ if [ "$rc" -eq 1 ] && printf '%s' "$out" | grep -q "缺 plan.*parallel-wip"; then
708
+ PASS=$((PASS+1)); printf 'PASS %s\n' "仓库模式:已提交的入口缺 plan 断档仍 hard-block"
709
+ else
710
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 1 + 关键词[缺同名 plan],实际 exit %s)\n%s\n' "仓库模式:已提交的入口缺 plan 断档仍 hard-block" "$rc" "$out"
711
+ fi
712
+ rm -rf "$T"
713
+
714
+ # ---- 场景 23:检索层——模块合法 + INDEX 一致 → exit 0 且无两条新告警 ----
715
+ # fixture 拷入真实生成器与词表(测接线,非假桩;生成器逻辑自身由 gen-workflow-index.test.mjs 覆盖)
716
+ T=$(mkfix)
717
+ mkdir -p "$T/.agents/scripts" "$T/.agents"
718
+ cp "$SCRIPT_DIR/gen-workflow-index.mjs" "$T/.agents/scripts/"
719
+ cp "$SCRIPT_DIR/../workflow-modules.txt" "$T/.agents/"
720
+ cat > "$T/workflow/intents/2026-09-22-mod-ok.md" <<'EOF'
721
+ ---
722
+ 状态: approved
723
+ 级别: L1
724
+ 日期: 2026-09-22
725
+ 模块: pipeline
726
+ ---
727
+ # INTENT — mod ok
728
+
729
+ ## 验收标准(可测试)
730
+ - [ ] 用例通过
731
+ EOF
732
+ cat > "$T/workflow/plans/2026-09-22-mod-ok.md" <<'EOF'
733
+ ---
734
+ 状态: approved
735
+ 级别: L1
736
+ 模块: pipeline
737
+ ---
738
+ # PLAN — mod ok
739
+ EOF
740
+ (cd "$T" && node .agents/scripts/gen-workflow-index.mjs >/dev/null 2>&1)
741
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
742
+ if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "WARN 模块元数据" && ! printf '%s' "$out" | grep -q "WARN 索引漂移"; then
743
+ PASS=$((PASS+1)); printf 'PASS %s\n' "检索层:模块合法+INDEX 一致 → exit 0 无新告警"
744
+ else
745
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无模块/索引告警)\n%s\n' "检索层:模块合法+INDEX 一致 → exit 0 无新告警" "$out"
746
+ fi
747
+ rm -rf "$T"
748
+
749
+ # ---- 场景 24:模块枚举非法 + 2026-09-22 起新建缺字段 → WARN 不阻断 ----
750
+ T=$(mkfix)
751
+ mkdir -p "$T/.agents"
752
+ cp "$SCRIPT_DIR/../workflow-modules.txt" "$T/.agents/"
753
+ cat > "$T/workflow/intents/2026-09-22-mod-bad.md" <<'EOF'
754
+ ---
755
+ 状态: approved
756
+ 级别: L1
757
+ 日期: 2026-09-22
758
+ 模块: 不存在的模块
759
+ ---
760
+ # INTENT — mod bad
761
+ EOF
762
+ cat > "$T/workflow/plans/2026-09-22-mod-bad.md" <<'EOF'
763
+ ---
764
+ 状态: approved
765
+ 级别: L1
766
+ ---
767
+ # PLAN — mod bad
768
+ EOF
769
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
770
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 模块元数据" && printf '%s' "$out" | grep -q "不在词表" && printf '%s' "$out" | grep -q "缺「模块:」字段"; then
771
+ PASS=$((PASS+1)); printf 'PASS %s\n' "检索层:模块非法/缺字段 → WARN 且 exit 0"
772
+ else
773
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + 模块元数据 WARN 含两类)\n%s\n' "检索层:模块非法/缺字段 → WARN 且 exit 0" "$out"
774
+ fi
775
+ rm -rf "$T"
776
+
777
+ # ---- 场景 25:INDEX 漂移 → WARN 索引漂移,exit 0(口径:调生成器 --check)----
778
+ T=$(mkfix)
779
+ mkdir -p "$T/.agents/scripts" "$T/.agents"
780
+ cp "$SCRIPT_DIR/gen-workflow-index.mjs" "$T/.agents/scripts/"
781
+ cp "$SCRIPT_DIR/../workflow-modules.txt" "$T/.agents/"
782
+ cat > "$T/workflow/intents/2026-09-22-drift.md" <<'EOF'
783
+ ---
784
+ 状态: approved
785
+ 级别: L1
786
+ 日期: 2026-09-22
787
+ 模块: pipeline
788
+ ---
789
+ # INTENT — drift
790
+
791
+ ## 验收标准(可测试)
792
+ - [ ] 用例通过
793
+ EOF
794
+ cat > "$T/workflow/plans/2026-09-22-drift.md" <<'EOF'
795
+ ---
796
+ 状态: approved
797
+ 级别: L1
798
+ 模块: pipeline
799
+ ---
800
+ # PLAN — drift
801
+ EOF
802
+ (cd "$T" && node .agents/scripts/gen-workflow-index.mjs >/dev/null 2>&1)
803
+ sed -i 's/^状态: approved$/状态: done/' "$T/workflow/plans/2026-09-22-drift.md" 2>/dev/null || printf '%s\n' "$(sed 's/^状态: approved$/状态: done/' "$T/workflow/plans/2026-09-22-drift.md")" > "$T/workflow/plans/2026-09-22-drift.md"
804
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
805
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 索引漂移"; then
806
+ PASS=$((PASS+1)); printf 'PASS %s\n' "检索层:INDEX 漂移 → WARN 且 exit 0"
807
+ else
808
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 索引漂移)\n%s\n' "检索层:INDEX 漂移 → WARN 且 exit 0" "$out"
809
+ fi
810
+ rm -rf "$T"
811
+
812
+ # ---- 场景 26:常驻面预算——合规(小体积)→ 无超限告警,exit 0 ----
813
+ T=$(mkfix)
814
+ mkdir -p "$T/.agents/scripts"
815
+ cp "$SCRIPT_DIR/rule-budget.sh" "$T/.agents/scripts/"
816
+ cp "$SCRIPT_DIR/../rule-budgets.txt" "$T/.agents/"
817
+ printf '# AGENTS 小体积 fixture\n' > "$T/AGENTS.md"
818
+ mkdir -p "$T/.agents/commands"
819
+ printf '# 小命令\n' > "$T/.agents/commands/plan.md"
820
+ cat > "$T/workflow/intents/2026-09-22-budget-ok.md" <<'EOF'
821
+ ---
822
+ 状态: approved
823
+ 级别: L1
824
+ 日期: 2026-09-22
825
+ 模块: pipeline
826
+ ---
827
+ # INTENT — budget ok
828
+ EOF
829
+ cat > "$T/workflow/plans/2026-09-22-budget-ok.md" <<'EOF'
830
+ ---
831
+ 状态: approved
832
+ 级别: L1
833
+ 模块: pipeline
834
+ ---
835
+ # PLAN — budget ok
836
+ EOF
837
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
838
+ if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "WARN 常驻面超限"; then
839
+ PASS=$((PASS+1)); printf 'PASS %s\n' "常驻面预算:合规 → 无超限告警且 exit 0"
840
+ else
841
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无超限告警)\n%s\n' "常驻面预算:合规 → 无超限告警且 exit 0" "$out"
842
+ fi
843
+ rm -rf "$T"
844
+
845
+ # ---- 场景 27:常驻面预算——AGENTS.md 超限 → WARN 且 exit 0(一进一出提示)----
846
+ T=$(mkfix)
847
+ mkdir -p "$T/.agents/scripts"
848
+ cp "$SCRIPT_DIR/rule-budget.sh" "$T/.agents/scripts/"
849
+ cp "$SCRIPT_DIR/../rule-budgets.txt" "$T/.agents/"
850
+ head -c 8000 /dev/zero | tr '\0' 'x' > "$T/AGENTS.md"
851
+ cat > "$T/workflow/intents/2026-09-22-budget-bad.md" <<'EOF'
852
+ ---
853
+ 状态: approved
854
+ 级别: L1
855
+ 日期: 2026-09-22
856
+ 模块: pipeline
857
+ ---
858
+ # INTENT — budget bad
859
+ EOF
860
+ cat > "$T/workflow/plans/2026-09-22-budget-bad.md" <<'EOF'
861
+ ---
862
+ 状态: approved
863
+ 级别: L1
864
+ 模块: pipeline
865
+ ---
866
+ # PLAN — budget bad
867
+ EOF
868
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
869
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 常驻面超限" && printf '%s' "$out" | grep -q "一进一出"; then
870
+ PASS=$((PASS+1)); printf 'PASS %s\n' "常驻面预算:超限 → WARN(含一进一出提示) 且 exit 0"
871
+ else
872
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 常驻面超限)\n%s\n' "常驻面预算:超限 → WARN 且 exit 0" "$out"
873
+ fi
874
+ rm -rf "$T"
875
+
876
+ # ---- 场景 28:rule-budget --staged——暂存超限即 exit 1(pre-commit 硬拦路径);换成合规即 exit 0 ----
877
+ T=$(mkfix)
878
+ mkdir -p "$T/.agents/scripts"
879
+ cp "$SCRIPT_DIR/rule-budget.sh" "$T/.agents/scripts/"
880
+ cp "$SCRIPT_DIR/../rule-budgets.txt" "$T/.agents/"
881
+ git -C "$T" init -q
882
+ head -c 8000 /dev/zero | tr '\0' 'x' > "$T/AGENTS.md"
883
+ git -C "$T" add AGENTS.md
884
+ out=$(cd "$T" && sh .agents/scripts/rule-budget.sh --staged 2>&1); rc=$?
885
+ if [ "$rc" -eq 1 ] && printf '%s' "$out" | grep -q "常驻面超限:AGENTS.md"; then
886
+ PASS=$((PASS+1)); printf 'PASS %s\n' "rule-budget --staged:暂存超限 → exit 1(硬拦路径)"
887
+ else
888
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 1 + 超限行,实际 exit %s)\n%s\n' "rule-budget --staged:暂存超限 → exit 1" "$rc" "$out"
889
+ fi
890
+ printf '# 小体积\n' > "$T/AGENTS.md"
891
+ git -C "$T" add AGENTS.md
892
+ out2=$(cd "$T" && sh .agents/scripts/rule-budget.sh --staged 2>&1); rc2=$?
893
+ if [ "$rc2" -eq 0 ]; then
894
+ PASS=$((PASS+1)); printf 'PASS %s\n' "rule-budget --staged:合规 → exit 0(不误拦)"
895
+ else
896
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0,实际 exit %s)\n%s\n' "rule-budget --staged:合规 → exit 0" "$rc2" "$out2"
897
+ fi
898
+ rm -rf "$T"
899
+
900
+ # ---- 场景 29:git fixture——新 done 的 spec/plan 历史无 approved → WARN 确认态缺失,exit 0(检查项 14) ----
901
+ T=$(mkfix)
902
+ git -C "$T" init -q
903
+ cat > "$T/workflow/incidents/2026-09-23-confirm-gate.md" <<'EOF'
904
+ ---
905
+ 状态: closed
906
+ 级别: L1
907
+ 发现: 2026-09-23
908
+ 模块: material
909
+ ---
910
+ # INCIDENT — confirm gate
911
+
912
+ ## 复盘三件套(缺一不可)
913
+
914
+ 1. 结构性修复
915
+ - 修复 commit:abc1234
916
+ - 影响环境:dev
917
+ - 是否需要新 intent:
918
+ - 否 → 理由:实现 bug 单点修复
919
+
920
+ 2. 防复发验证
921
+ - 回归清单条目在案
922
+
923
+ 3. 规范条目
924
+ - AGENTS.md 某节
925
+ EOF
926
+ cat > "$T/workflow/plans/2026-09-23-confirm-gate.md" <<'EOF'
927
+ ---
928
+ 状态: done
929
+ 级别: L1
930
+ 模块: material
931
+ ---
932
+ # PLAN — confirm gate
933
+ EOF
934
+ git -C "$T" add -A
935
+ git -C "$T" -c user.email=t@t -c user.name=t commit -qm test
936
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
937
+ if [ "$rc" -eq 0 ] && printf '%s' "$out" | grep -q "WARN 确认态缺失.*2026-09-23-confirm-gate.md"; then
938
+ PASS=$((PASS+1)); printf 'PASS %s\n' "新 done 无 approved 历史 → WARN 确认态缺失 且 exit 0"
939
+ else
940
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 + WARN 确认态缺失)\n%s\n' "新 done 无 approved 历史 → WARN 确认态缺失" "$out"
941
+ fi
942
+ rm -rf "$T"
943
+
944
+ # ---- 场景 30:git fixture——先 approved 后 done(确认环节留痕)→ 无该 WARN,exit 0 ----
945
+ T=$(mkfix)
946
+ git -C "$T" init -q
947
+ cat > "$T/workflow/incidents/2026-09-23-confirm-ok.md" <<'EOF'
948
+ ---
949
+ 状态: closed
950
+ 级别: L1
951
+ 发现: 2026-09-23
952
+ 模块: material
953
+ ---
954
+ # INCIDENT — confirm ok
955
+
956
+ ## 复盘三件套(缺一不可)
957
+
958
+ 1. 结构性修复
959
+ - 修复 commit:abc1234
960
+ - 影响环境:dev
961
+ - 是否需要新 intent:
962
+ - 否 → 理由:实现 bug 单点修复
963
+
964
+ 2. 防复发验证
965
+ - 回归清单条目在案
966
+
967
+ 3. 规范条目
968
+ - AGENTS.md 某节
969
+ EOF
970
+ cat > "$T/workflow/plans/2026-09-23-confirm-ok.md" <<'EOF'
971
+ ---
972
+ 状态: approved
973
+ 级别: L1
974
+ 模块: material
975
+ ---
976
+ # PLAN — confirm ok
977
+ EOF
978
+ git -C "$T" add -A
979
+ git -C "$T" -c user.email=t@t -c user.name=t commit -qm approved
980
+ cat > "$T/workflow/plans/2026-09-23-confirm-ok.md" <<'EOF'
981
+ ---
982
+ 状态: done
983
+ 级别: L1
984
+ 模块: material
985
+ ---
986
+ # PLAN — confirm ok
987
+ EOF
988
+ git -C "$T" add -A
989
+ git -C "$T" -c user.email=t@t -c user.name=t commit -qm done
990
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
991
+ if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "WARN 确认态缺失"; then
992
+ PASS=$((PASS+1)); printf 'PASS %s\n' "approved → done 留痕 → 无确认态缺失告警"
993
+ else
994
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无确认态缺失告警)\n%s\n' "approved → done 留痕 → 无确认态缺失告警" "$out"
995
+ fi
996
+ rm -rf "$T"
997
+
998
+ # ---- 场景 31:非 git fixture——历史不可考,检查项 14 静默跳过(不误报) ----
999
+ T=$(mkfix)
1000
+ cat > "$T/workflow/incidents/2026-09-23-confirm-nogit.md" <<'EOF'
1001
+ ---
1002
+ 状态: closed
1003
+ 级别: L1
1004
+ 发现: 2026-09-23
1005
+ 模块: material
1006
+ ---
1007
+ # INCIDENT — confirm nogit
1008
+
1009
+ ## 复盘三件套(缺一不可)
1010
+
1011
+ 1. 结构性修复
1012
+ - 修复 commit:abc1234
1013
+ - 影响环境:dev
1014
+ - 是否需要新 intent:
1015
+ - 否 → 理由:实现 bug 单点修复
1016
+
1017
+ 2. 防复发验证
1018
+ - 回归清单条目在案
1019
+
1020
+ 3. 规范条目
1021
+ - AGENTS.md 某节
1022
+ EOF
1023
+ cat > "$T/workflow/plans/2026-09-23-confirm-nogit.md" <<'EOF'
1024
+ ---
1025
+ 状态: done
1026
+ 级别: L1
1027
+ 模块: material
1028
+ ---
1029
+ # PLAN — confirm nogit
1030
+ EOF
1031
+ out=$(CHECK_LOOP_ROOT="$T" sh "$TARGET" 2>&1); rc=$?
1032
+ if [ "$rc" -eq 0 ] && ! printf '%s' "$out" | grep -q "WARN 确认态缺失"; then
1033
+ PASS=$((PASS+1)); printf 'PASS %s\n' "非 git fixture → 检查项 14 跳过,不误报"
1034
+ else
1035
+ FAIL=$((FAIL+1)); printf 'FAIL %s(期望 exit 0 且无确认态缺失告警)\n%s\n' "非 git fixture → 检查项 14 跳过" "$out"
1036
+ fi
1037
+ rm -rf "$T"
1038
+
1039
+ # ---- 汇总 ----
1040
+ printf '\n合计: PASS %s / FAIL %s\n' "$PASS" "$FAIL"
1041
+ [ "$FAIL" -eq 0 ] || exit 1
1042
+ exit 0